From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anish Patel Date: Mon, 17 Jan 2011 19:18:36 +0000 Subject: [lm-sensors] driver for emc1023 Message-Id: <4D34960C.8070303@gmail.com> MIME-Version: 1 Content-Type: multipart/mixed; boundary="------------000407020203030607020701" List-Id: To: lm-sensors@vger.kernel.org This is a multi-part message in MIME format. --------------000407020203030607020701 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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. --------------000407020203030607020701 Content-Type: text/x-c; name="emc1023.c" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="emc1023.c" /* emc1023.c * * Copyright (C) 2011 Anish K. Patel * 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 #include #include #include #include #include #include #include #include #include /* 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 "); MODULE_DESCRIPTION("SMSC emc1023 temperature sensor driver"); MODULE_LICENSE("GPL"); module_init(emc1023_init); module_exit(emc1023_exit); --------------000407020203030607020701 Content-Type: text/plain; name="emc1023.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="emc1023.patch" 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) --------------000407020203030607020701 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ lm-sensors mailing list lm-sensors@lm-sensors.org http://lists.lm-sensors.org/mailman/listinfo/lm-sensors --------------000407020203030607020701--