here is the driver for the emc1023 and the makefile patch.
i've spent a couple hours now trying to figure out how to create a patch
for a new file, and can't find anything.
if someone would care to point me in the right direction i'll resubmit,
but at this point i am tired of trying to figure this out.
Doc/SubmittingDrivers and SubmittingPatches is no help on how to do this.
/* emc1023.c
*
* Copyright (C) 2011 Anish K. Patel <anishs.online.junk@xxxxxxxxx>
* based heavily on tmp401.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* Driver for the SMSC EMC1023 SMBUS temperature sensor IC.
* examples taken from datasheet
*
* legacy format (LF)
* registers for temperature store them in an 11bit value,
* 2's complement form
* the high byte holds the sign and the whole number part
* the low byte holds the fraction in the upper 3 bits.
* goes from -63.125 to 127.875
* bit 7 - 0.500
* bit 6 - 0.250
* bit 5 - 0.125
* temp data junk bits hex
* ie Diode fault = 10000000000|00000 400
* -63 = 11000001000|00000 608
* -63.875 = 11000000001|00000 601
* 0 = 00000000000|00000 000
* 1 = 00000001000|00000 008
* 127 = 01111111000|00000 3F8
* 127.875 = 01111111111|00000 3FF
*
* for the extend format (EF) add 64d to read the data
*
*
* todo - clean up the fraction part, implement EF temp
* *possibly make EF reporting default with module flag
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
/* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x48,0x49,0x4c,0x4d, I2C_CLIENT_END };
enum chips { emc1023_1 , emc1023_2, emc1023_3, emc1023_4 };
/*
* The EMC1023 registers, note some registers have different addresses for
* reading and writing
* device id - seems to be the 8,9,c,d corresponding to address of IC
* ie devid 0x08 ic addr 0x48, etc
*/
#define EMC1023_ONE_SHOT_CMD 0x0F
#define EMC1023_RMT1_IF_RW 0x27
#define EMC1023_RMT2_IF_RW 0x28
#define EMC1023_STATUS 0x02
#define EMC1023_CONFIG_READ 0x03
#define EMC1023_CONFIG_WRITE 0x09
#define EMC1023_DEVICE_ID_REG 0xED
#define EMC1023_MANUFACTURER_ID_REG 0xFE
#define EMC1023_PRODUCT_ID_REG 0xFF
#define EMC1023_MANUFACTURER_ID 0x5D
#define EMC1023_DEVICE_ID_1 0x0C
#define EMC1023_DEVICE_ID_2 0x0D
#define EMC1023_DEVICE_ID_3 0x08
#define EMC1023_DEVICE_ID_4 0x09
static const u8 EMC1023_DEVICE_ID[] = { 0x08, 0x09,
0x0c, 0x0d };
static const u8 EMC1023_LF_TEMP_HIGH_BYTE[3] = { 0x00, 0x01, 0xF8 };
static const u8 EMC1023_LF_TEMP_LOW_BYTE[3] = { 0x23, 0x10, 0xF9 };
static const u8 EMC1023_EF_TEMP_HIGH_BYTE[2] = { 0xFA, 0XFC };
static const u8 EMC1023_EF_TEMP_LOW_BYTE[2] = { 0xFB, 0XFD };
/*
* Driver data (common to all clients)
*/
static const struct i2c_device_id emc1023_id[] = {
{ "emc1023_1", emc1023_1 },
{ "emc1023_2", emc1023_2 },
{ "emc1023_3", emc1023_3 },
{ "emc1023_4", emc1023_4 },
{ }
};
MODULE_DEVICE_TABLE(i2c, emc1023_id);
/*
* Client data (each client gets its own)
*/
struct emc1023_data {
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
enum chips kind;
/* register values */
u8 status;
u8 config;
u16 temp;
u8 temp_high[3];
u8 temp_low[3];
};
/*
* Sysfs attr show / store functions
*/
static int emc1023_register_to_temp(u8 reg_high,u8 reg_low)
{
int temphigh = reg_high;
//since we only need the top 3bits from reg_low shift over 5
//and then do the magic below to pop temp low with correct data
int templow = (reg_low >> 5);
if ( temphigh > 128 )
temphigh = ((temphigh % 128 ) - 128)*1000;
else
temphigh *= 1000;
//get fraction part and populate temp low with info (ugly)
templow =(((templow & 4 ) >> 2) * 500 ) +
(((templow & 2 ) >> 1) * 250 ) +
((templow & 1 ) * 125);
return (temphigh+templow);
}
static struct emc1023_data *emc1023_update_device_reg16(
struct i2c_client *client, struct emc1023_data *data)
{
int i;
for (i=0; i < 3; i++) {
data->temp_high[i] = i2c_smbus_read_byte_data(client,
EMC1023_LF_TEMP_HIGH_BYTE[i]);
data->temp_low[i] = i2c_smbus_read_byte_data(client,
EMC1023_LF_TEMP_LOW_BYTE[i]);
}
return data;
}
static struct emc1023_data *emc1023_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct emc1023_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
data->status = i2c_smbus_read_byte_data(client, EMC1023_STATUS);
data->config = i2c_smbus_read_byte_data(client, EMC1023_CONFIG_READ);
emc1023_update_device_reg16(client, data);
data->last_updated = jiffies;
data->valid = 1;
}
mutex_unlock(&data->update_lock);
return data;
}
static ssize_t show_temp_value(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int index = to_sensor_dev_attr(devattr)->index;
struct emc1023_data *data = emc1023_update_device(dev);
return sprintf(buf, "%d\n",
emc1023_register_to_temp(data->temp_high[index], data->temp_low[index]));
}
/*static ssize_t show_status(struct device *dev,
struct device_attribute *devattr, char *buf)
{
//int mask = to_sensor_dev_attr(devattr)->index;
struct emc1023_data *data = emc1023_update_device(dev);
if ( (data->status >> 7) == 1 )
return sprintf(buf, "ready\n");
else
return sprintf(buf, "not ready\n");
}*/
static struct sensor_device_attribute emc1023_attr[] = {
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0),
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1),
SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2),
};
/*
* Begin non sysfs callback code (aka Real code)
*/
static void emc1023_init_client(struct i2c_client *client)
{
int config;
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, EMC1023_CONFIG_READ);
if (config < 0) {
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
}
static int emc1023_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
//int i=0;
struct i2c_adapter *adapter = client->adapter;
u8 reg;
enum chips kind;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* Detect and identify the chip */
reg = i2c_smbus_read_byte_data(client, EMC1023_MANUFACTURER_ID_REG);
if (reg != EMC1023_MANUFACTURER_ID)
return -ENODEV;
reg = i2c_smbus_read_byte_data(client, EMC1023_DEVICE_ID_REG);
//tried to cycle through array to match id.
/*for(i=0;i<4;i++)
if( reg == EMC1023_DEVICE_ID[i] )
{
kind = i;
break;
}*/
switch (reg) {
case EMC1023_DEVICE_ID_1:
kind = emc1023_1;
break;
case EMC1023_DEVICE_ID_2:
kind = emc1023_2;
break;
case EMC1023_DEVICE_ID_3:
kind = emc1023_3;
break;
case EMC1023_DEVICE_ID_4:
kind = emc1023_4;
break;
default:
return -ENODEV;
}
strlcpy(info->type, emc1023_id[kind].name, I2C_NAME_SIZE);
return 0;
}
static int emc1023_remove(struct i2c_client *client)
{
struct emc1023_data *data = i2c_get_clientdata(client);
int i;
if (data->hwmon_dev)
hwmon_device_unregister(data->hwmon_dev);
for (i = 0; i < ARRAY_SIZE(emc1023_attr); i++)
device_remove_file(&client->dev, &emc1023_attr[i].dev_attr);
kfree(data);
return 0;
}
static int emc1023_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int i, err = 0;
struct emc1023_data *data;
const char *names[] = { "EMC1023_1", "EMC1023_2", "EMC1023_3","EMC1023_4" };
data = kzalloc(sizeof(struct emc1023_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->kind = id->driver_data;
/* Initialize the EMC1023 chip */
emc1023_init_client(client);
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(emc1023_attr); i++) {
err = device_create_file(&client->dev,
&emc1023_attr[i].dev_attr);
if (err)
goto exit_remove;
}
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
data->hwmon_dev = NULL;
goto exit_remove;
}
dev_info(&client->dev, "Detected emc1023 %s chip\n", names[data->kind]);
return 0;
exit_remove:
emc1023_remove(client); /* will also free data for us */
return err;
}
static struct i2c_driver emc1023_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "emc1023",
},
.probe = emc1023_probe,
.remove = emc1023_remove,
.id_table = emc1023_id,
.detect = emc1023_detect,
.address_list = normal_i2c,
};
static int __init emc1023_init(void)
{
return i2c_add_driver(&emc1023_driver);
}
static void __exit emc1023_exit(void)
{
i2c_del_driver(&emc1023_driver);
}
MODULE_AUTHOR("Anish K Patel <anishp(at)win-ent!com!>");
MODULE_DESCRIPTION("SMSC emc1023 temperature sensor driver");
MODULE_LICENSE("GPL");
module_init(emc1023_init);
module_exit(emc1023_exit);
diff -uprN -X linux-2.6.36.2/Documentation/dontdiff linux-2.6.36.2/drivers/hwmon/Kconfig linux-new/drivers/hwmon/Kconfig
--- linux-2.6.36.2/drivers/hwmon/Kconfig 2010-10-20 16:30:22.000000000 -0400
+++ linux-new/drivers/hwmon/Kconfig 2011-01-17 12:21:12.292000226 -0500
@@ -310,6 +310,16 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module
will be called ds1621.
+config SENSORS_EMC1023
+ tristate "SMSC emc1023 Thermal Sensor"
+ depends on I2C
+ help
+ If you say yes here you get support for the SMC1023 Thermal Sensor
+ monitoring chip
+
+ This driver can also be built as a module. If so, the module
+ will be called emc1023
+
config SENSORS_I5K_AMB
tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets"
depends on PCI && EXPERIMENTAL
diff -uprN -X linux-2.6.36.2/Documentation/dontdiff linux-2.6.36.2/drivers/hwmon/Makefile linux-new/drivers/hwmon/Makefile
--- linux-2.6.36.2/drivers/hwmon/Makefile 2010-10-20 16:30:22.000000000 -0400
+++ linux-new/drivers/hwmon/Makefile 2011-01-17 11:44:16.799999396 -0500
@@ -107,6 +107,7 @@ obj-$(CONFIG_SENSORS_W83627EHF) += w8362
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
+obj-$(CONFIG_SENSORS_EMC1023) += emc1023.o
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
_______________________________________________
lm-sensors mailing list
lm-sensors@xxxxxxxxxxxxxx
http://lists.lm-sensors.org/mailman/listinfo/lm-sensors