From bbe5939ab1834f79f177739cb84904bc12d08073 Mon Sep 17 00:00:00 2001 From: Alistair John Strachan Date: Tue, 15 Sep 2009 17:18:10 +0200 Subject: hwmon: (abituguru3) Support multiple DMI strings per chip ID Most known Abit motherboards have unique uguru chip IDs. However, some "refresh" boards keep the same chip ID but have a different DMI string. As our DMI board string matching is (necessarily) strict, some boards were failing DMI detection, and as the old probe method was also failing, the driver would not load. The only known boards affected by this problem are the IP35 Pro XE (vs IP35 Pro) and the AB9 Pro (vs AB9). Is it not sufficient to relax the match criteria, as some boards (e.g. the AB9 Quad GT) have different uguru chip IDs. This patch replaces the dmi_name string with a NULL terminated array of strings to be matched per uguru chip ID. It has been compile and runtime tested (thanks Rune). References: https://bugs.launchpad.net/bugs/298798 Signed-off-by: Alistair John Strachan Tested-by: Rune Svendsen Acked-by: Hans de Goede Signed-off-by: Jean Delvare --- drivers/hwmon/abituguru3.c | 77 ++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index 7d3f15d32fd..d45c569770f 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -117,9 +117,12 @@ struct abituguru3_sensor_info { int offset; }; +/* Avoid use of flexible array members */ +#define ABIT_UGURU3_MAX_DMI_NAMES 2 + struct abituguru3_motherboard_info { u16 id; - const char *dmi_name; + const char *dmi_name[ABIT_UGURU3_MAX_DMI_NAMES + 1]; /* + 1 -> end of sensors indicated by a sensor with name == NULL */ struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1]; }; @@ -164,7 +167,7 @@ struct abituguru3_data { /* Constants */ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { - { 0x000C, NULL /* Unknown, need DMI string */, { + { 0x000C, { NULL } /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -186,7 +189,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX1 Fan", 35, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000D, NULL /* Abit AW8, need DMI string */, { + { 0x000D, { NULL } /* Abit AW8, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -215,7 +218,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX5 Fan", 39, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000E, NULL /* AL-8, need DMI string */, { + { 0x000E, { NULL } /* AL-8, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -236,7 +239,8 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000F, NULL /* Unknown, need DMI string */, { + { 0x000F, { NULL } /* Unknown, need DMI string */, { + { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -257,7 +261,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0010, NULL /* Abit NI8 SLI GR, need DMI string */, { + { 0x0010, { NULL } /* Abit NI8 SLI GR, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -279,7 +283,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "OTES1 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0011, "AT8 32X", { + { 0x0011, { "AT8 32X", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -306,7 +310,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0012, NULL /* Abit AN8 32X, need DMI string */, { + { 0x0012, { NULL } /* Abit AN8 32X, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -328,7 +332,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX1 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0013, NULL /* Abit AW8D, need DMI string */, { + { 0x0013, { NULL } /* Abit AW8D, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -357,7 +361,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX5 Fan", 39, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0014, "AB9", /* + AB9 Pro */ { + { 0x0014, { "AB9", "AB9 Pro", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -378,7 +382,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0015, NULL /* Unknown, need DMI string */, { + { 0x0015, { NULL } /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -402,7 +406,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0016, "AW9D-MAX", { + { 0x0016, { "AW9D-MAX", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -430,7 +434,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "OTES1 Fan", 38, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0017, NULL /* Unknown, need DMI string */, { + { 0x0017, { NULL } /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -455,7 +459,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 FAN", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0018, "AB9 QuadGT", { + { 0x0018, { "AB9 QuadGT", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -482,7 +486,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0019, "IN9 32X MAX", { + { 0x0019, { "IN9 32X MAX", NULL }, { { "CPU Core", 7, 0, 10, 1, 0 }, { "DDR2", 13, 0, 20, 1, 0 }, { "DDR2 VTT", 14, 0, 10, 1, 0 }, @@ -509,7 +513,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 FAN", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001A, "IP35 Pro", { + { 0x001A, { "IP35 Pro", "IP35 Pro XE", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -537,7 +541,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX4 Fan", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001B, NULL /* Unknown, need DMI string */, { + { 0x001B, { NULL } /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR3", 1, 0, 20, 1, 0 }, { "DDR3 VTT", 2, 0, 10, 1, 0 }, @@ -564,7 +568,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001C, "IX38 QuadGT", { + { 0x001C, { "IX38 QuadGT", NULL }, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -591,7 +595,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } } + { 0x0000, { NULL }, { { NULL, 0, 0, 0, 0, 0 } } } }; @@ -946,15 +950,6 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard " "ID: %04X\n", (unsigned int)id); -#ifdef CONFIG_DMI - if (!abituguru3_motherboards[i].dmi_name) { - printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was " - "not detected using DMI. Please send the output of " - "\"dmidecode\" to the abituguru3 maintainer " - "(see MAINTAINERS)\n"); - } -#endif - /* Fill the sysfs attr array */ sysfs_attr_i = 0; sysfs_filename = data->sysfs_names; @@ -1131,6 +1126,7 @@ static int __init abituguru3_dmi_detect(void) { const char *board_vendor, *board_name; int i, err = (force) ? 1 : -ENODEV; + const char *const *dmi_name; size_t sublen; board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); @@ -1151,17 +1147,17 @@ static int __init abituguru3_dmi_detect(void) sublen--; for (i = 0; abituguru3_motherboards[i].id; i++) { - const char *dmi_name = abituguru3_motherboards[i].dmi_name; - if (!dmi_name || strlen(dmi_name) != sublen) - continue; - if (!strncasecmp(board_name, dmi_name, sublen)) - break; + dmi_name = abituguru3_motherboards[i].dmi_name; + for ( ; *dmi_name; dmi_name++) { + if (strlen(*dmi_name) != sublen) + continue; + if (!strncasecmp(board_name, *dmi_name, sublen)) + return 0; + } } - if (!abituguru3_motherboards[i].id) - return 1; - - return 0; + /* No match found */ + return 1; } #else /* !CONFIG_DMI */ @@ -1221,6 +1217,13 @@ static int __init abituguru3_init(void) err = abituguru3_detect(); if (err) return err; + +#ifdef CONFIG_DMI + printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was " + "not detected using DMI. Please send the output of " + "\"dmidecode\" to the abituguru3 maintainer " + "(see MAINTAINERS)\n"); +#endif } err = platform_driver_register(&abituguru3_driver); -- cgit v1.2.3-70-g09d2 From 5bed13f5809927be10facccb63add834b712df51 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 15 Sep 2009 17:18:11 +0200 Subject: hwmon-vid: Ignore 6th VID pin of AMD family 0Fh processors We had a report about a mainboard for AMD family 0Fh processors not routing the 6th VID pin from the CPU to the hardware monitoring chip. While the vendor should have wired the pin (or, failing that, should have hardwired it to level high rather than low), the fact is that none of these processors are currently known to operate at the lower voltage levels which require the 6th VID pin. So, as a practical workaround, I propose to ignore the 6th VID pin for these CPUs. If this decision ever causes problems, we'll reconsider. Signed-off-by: Jean Delvare Cc: Frank Myhr Tested-by: Hleb Valoshka <375gnu@gmail.com> Cc: Rudolf Marek Cc: Andreas Herrmann --- drivers/hwmon/hwmon-vid.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index bfc296145bb..bf0862a803c 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -179,8 +179,14 @@ struct vrm_model { static struct vrm_model vrm_models[] = { {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ - {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* NPT family 0Fh */ + /* In theory, all NPT family 0Fh processors have 6 VID pins and should + thus use vrm 25, however in practice not all mainboards route the + 6th VID pin because it is never needed. So we use the 5 VID pin + variant (vrm 24) for the models which exist today. */ + {X86_VENDOR_AMD, 0xF, 0x7F, ANY, 24}, /* NPT family 0Fh */ + {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* future fam. 0Fh */ {X86_VENDOR_AMD, 0x10, ANY, ANY, 25}, /* NPT family 10h */ + {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ @@ -191,12 +197,14 @@ static struct vrm_model vrm_models[] = { {X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */ {X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */ {X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */ + {X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */ {X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */ {X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */ {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */ {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */ {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */ + {X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */ }; -- cgit v1.2.3-70-g09d2 From 9410700b881f867a50dd8dc3204372fd9dccd8f8 Mon Sep 17 00:00:00 2001 From: Andre Prendel Date: Tue, 15 Sep 2009 17:18:11 +0200 Subject: hwmon: Add driver for Texas Instruments TMP421/422/423 sensor chips Add support for Texas Instruments TMP421/422/423 temperature sensor IC. TI's TMP421/422/423 are I2C temperature sensor chips. These chips are similar to TI's TMP401/411 chips, but with reduced functionality (only temperature measurement). The chips have one local sensor and up to three (TMP423) remote sensors. Signed-off-by: Andre Prendel Acked-by: Hans de Goede Signed-off-by: Jean Delvare --- drivers/hwmon/Kconfig | 10 ++ drivers/hwmon/Makefile | 1 + drivers/hwmon/tmp421.c | 347 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 drivers/hwmon/tmp421.c (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 2e25b7a827d..ee57a4a2cd7 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -814,6 +814,16 @@ config SENSORS_TMP401 This driver can also be built as a module. If so, the module will be called tmp401. +config SENSORS_TMP421 + tristate "Texas Instruments TMP421 and compatible" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for Texas Instruments TMP421, + TMP422 and TMP423 temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called tmp421. + config SENSORS_VIA686A tristate "VIA686A" depends on PCI diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 7f239a247c3..b577b499720 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o obj-$(CONFIG_SENSORS_TMP401) += tmp401.o +obj-$(CONFIG_SENSORS_TMP421) += tmp421.o obj-$(CONFIG_SENSORS_VIA686A) += via686a.o obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c new file mode 100644 index 00000000000..20924343431 --- /dev/null +++ b/drivers/hwmon/tmp421.c @@ -0,0 +1,347 @@ +/* tmp421.c + * + * Copyright (C) 2009 Andre Prendel + * Preliminary support by: + * Melvin Rook, Raymond Ng + * + * 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 Texas Instruments TMP421 SMBus temperature sensor IC. + * Supported models: TMP421, TMP422, TMP423 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2a, 0x4c, 0x4d, 0x4e, 0x4f, + I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_3(tmp421, tmp422, tmp423); + +/* The TMP421 registers */ +#define TMP421_CONFIG_REG_1 0x09 +#define TMP421_CONVERSION_RATE_REG 0x0B +#define TMP421_MANUFACTURER_ID_REG 0xFE +#define TMP421_DEVICE_ID_REG 0xFF + +static const u8 TMP421_TEMP_MSB[4] = { 0x00, 0x01, 0x02, 0x03 }; +static const u8 TMP421_TEMP_LSB[4] = { 0x10, 0x11, 0x12, 0x13 }; + +/* Flags */ +#define TMP421_CONFIG_SHUTDOWN 0x40 +#define TMP421_CONFIG_RANGE 0x04 + +/* Manufacturer / Device ID's */ +#define TMP421_MANUFACTURER_ID 0x55 +#define TMP421_DEVICE_ID 0x21 +#define TMP422_DEVICE_ID 0x22 +#define TMP423_DEVICE_ID 0x23 + +static const struct i2c_device_id tmp421_id[] = { + { "tmp421", tmp421 }, + { "tmp422", tmp422 }, + { "tmp423", tmp423 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tmp421_id); + +struct tmp421_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; + unsigned long last_updated; + int kind; + u8 config; + s16 temp[4]; +}; + +static int temp_from_s16(s16 reg) +{ + int temp = reg; + + return (temp * 1000 + 128) / 256; +} + +static int temp_from_u16(u16 reg) +{ + int temp = reg; + + /* Add offset for extended temperature range. */ + temp -= 64 * 256; + + return (temp * 1000 + 128) / 256; +} + +static struct tmp421_data *tmp421_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct tmp421_data *data = i2c_get_clientdata(client); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + data->config = i2c_smbus_read_byte_data(client, + TMP421_CONFIG_REG_1); + + for (i = 0; i <= data->kind; i++) { + data->temp[i] = i2c_smbus_read_byte_data(client, + TMP421_TEMP_MSB[i]) << 8; + data->temp[i] |= i2c_smbus_read_byte_data(client, + TMP421_TEMP_LSB[i]); + } + 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 tmp421_data *data = tmp421_update_device(dev); + int temp; + + mutex_lock(&data->update_lock); + if (data->config & TMP421_CONFIG_RANGE) + temp = temp_from_u16(data->temp[index]); + else + temp = temp_from_s16(data->temp[index]); + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", temp); +} + +static ssize_t show_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct tmp421_data *data = tmp421_update_device(dev); + + /* + * The OPEN bit signals a fault. This is bit 0 of the temperature + * register (low byte). + */ + if (data->temp[index] & 0x01) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static mode_t tmp421_is_visible(struct kobject *kobj, struct attribute *a, + int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tmp421_data *data = dev_get_drvdata(dev); + struct device_attribute *devattr; + unsigned int index; + + devattr = container_of(a, struct device_attribute, attr); + index = to_sensor_dev_attr(devattr)->index; + + if (data->kind > index) + return a->mode; + + return 0; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_value, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_value, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_fault, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_value, NULL, 2); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_fault, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_value, NULL, 3); +static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_fault, NULL, 3); + +static struct attribute *tmp421_attr[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp4_fault.dev_attr.attr, + NULL +}; + +static const struct attribute_group tmp421_group = { + .attrs = tmp421_attr, + .is_visible = tmp421_is_visible, +}; + +static int tmp421_init_client(struct i2c_client *client) +{ + int config, config_orig; + + /* Set the conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, TMP421_CONVERSION_RATE_REG, 0x05); + + /* Start conversions (disable shutdown if necessary) */ + config = i2c_smbus_read_byte_data(client, TMP421_CONFIG_REG_1); + if (config < 0) { + dev_err(&client->dev, "Could not read configuration" + " register (%d)\n", config); + return -ENODEV; + } + + config_orig = config; + config &= ~TMP421_CONFIG_SHUTDOWN; + + if (config != config_orig) { + dev_info(&client->dev, "Enable monitoring chip\n"); + i2c_smbus_write_byte_data(client, TMP421_CONFIG_REG_1, config); + } + + return 0; +} + +static int tmp421_detect(struct i2c_client *client, int kind, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = client->adapter; + const char *names[] = { "TMP421", "TMP422", "TMP423" }; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + if (kind <= 0) { + u8 reg; + + reg = i2c_smbus_read_byte_data(client, + TMP421_MANUFACTURER_ID_REG); + if (reg != TMP421_MANUFACTURER_ID) + return -ENODEV; + + reg = i2c_smbus_read_byte_data(client, + TMP421_DEVICE_ID_REG); + switch (reg) { + case TMP421_DEVICE_ID: + kind = tmp421; + break; + case TMP422_DEVICE_ID: + kind = tmp422; + break; + case TMP423_DEVICE_ID: + kind = tmp423; + break; + default: + return -ENODEV; + } + } + strlcpy(info->type, tmp421_id[kind - 1].name, I2C_NAME_SIZE); + dev_info(&adapter->dev, "Detected TI %s chip at 0x%02x\n", + names[kind - 1], client->addr); + + return 0; +} + +static int tmp421_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tmp421_data *data; + int err; + + data = kzalloc(sizeof(struct tmp421_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->kind = id->driver_data; + + err = tmp421_init_client(client); + if (err) + goto exit_free; + + err = sysfs_create_group(&client->dev.kobj, &tmp421_group); + if (err) + goto exit_free; + + 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; + } + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &tmp421_group); + +exit_free: + i2c_set_clientdata(client, NULL); + kfree(data); + + return err; +} + +static int tmp421_remove(struct i2c_client *client) +{ + struct tmp421_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &tmp421_group); + + i2c_set_clientdata(client, NULL); + kfree(data); + + return 0; +} + +static struct i2c_driver tmp421_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "tmp421", + }, + .probe = tmp421_probe, + .remove = tmp421_remove, + .id_table = tmp421_id, + .detect = tmp421_detect, + .address_data = &addr_data, +}; + +static int __init tmp421_init(void) +{ + return i2c_add_driver(&tmp421_driver); +} + +static void __exit tmp421_exit(void) +{ + i2c_del_driver(&tmp421_driver); +} + +MODULE_AUTHOR("Andre Prendel "); +MODULE_DESCRIPTION("Texas Instruments TMP421/422/423 temperature sensor" + " driver"); +MODULE_LICENSE("GPL"); + +module_init(tmp421_init); +module_exit(tmp421_exit); -- cgit v1.2.3-70-g09d2 From 6055fae8aceee41471edfd1876e5617d16e028fe Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 15 Sep 2009 17:18:13 +0200 Subject: hwmon: Include instead of Drivers should be including instead of . Signed-off-by: H Hartley Sweeten Cc: Alistair John Strachan Cc: Nicolas Boichat Cc: Juerg Haefliger Cc: Frank Seidel Acked-by: Jim Cromie Cc: "Mark M. Hoffman" Cc: Roger Lucas Signed-off-by: Jean Delvare --- drivers/hwmon/abituguru.c | 2 +- drivers/hwmon/abituguru3.c | 2 +- drivers/hwmon/applesmc.c | 2 +- drivers/hwmon/dme1737.c | 2 +- drivers/hwmon/f71805f.c | 2 +- drivers/hwmon/hdaps.c | 3 +-- drivers/hwmon/it87.c | 2 +- drivers/hwmon/lm78.c | 2 +- drivers/hwmon/pc87360.c | 2 +- drivers/hwmon/pc87427.c | 2 +- drivers/hwmon/sis5595.c | 2 +- drivers/hwmon/smsc47b397.c | 2 +- drivers/hwmon/smsc47m1.c | 2 +- drivers/hwmon/via686a.c | 2 +- drivers/hwmon/vt1211.c | 2 +- drivers/hwmon/vt8231.c | 2 +- drivers/hwmon/w83627ehf.c | 2 +- drivers/hwmon/w83627hf.c | 2 +- drivers/hwmon/w83781d.c | 2 +- 19 files changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 4dbdb81ea3b..03694cc17a3 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include /* Banks */ #define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */ diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index d45c569770f..3cf28af614b 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include /* uGuru3 bank addresses */ #define ABIT_UGURU3_SETTINGS_BANK 0x01 diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 678e34b01e5..753b34885f9 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 3df202a9ad7..9814d51b3af 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include /* ISA device, if found */ static struct platform_device *pdev; diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 89987657925..525a00bd70b 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include static unsigned short force_id; module_param(force_id, ushort, 0); diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index d3612a1f198..be2d131e405 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -35,8 +35,7 @@ #include #include #include - -#include +#include #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ #define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */ diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 9157247fed8..ffeb2a10e1a 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #define DRVNAME "it87" diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index a1787fdf5b9..f7e70163e01 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include /* ISA device, if found */ static struct platform_device *pdev; diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index fb052fea374..4a64b85d4ec 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include static u8 devid; static struct platform_device *pdev; diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 3a8a0f7a773..4e0de0e06d7 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include static unsigned short force_id; module_param(force_id, ushort, 0); diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index aa2e8318f16..12f2e708656 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include /* If force_addr is set to anything different from 0, we forcibly enable diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 6f6d52b4fb6..f46d936c12d 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include static unsigned short force_id; module_param(force_id, ushort, 0); diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index ba75bfcf14c..8ad50fdba00 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include static unsigned short force_id; module_param(force_id, ushort, 0); diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index a022aedcaac..39e82a492f2 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include /* If force_addr is set to anything different from 0, we forcibly enable diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 73f77a9b8b1..120b5d6dbd3 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include static int uch_config = -1; module_param(uch_config, int, 0); diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 9982b45fbb1..470a1226ba2 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include static int force_addr; module_param(force_addr, int, 0); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 0e9746913d2..bb5e7874878 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include "lm75.h" enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 389150ba30d..2be28ac4ede 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include "lm75.h" static struct platform_device *pdev; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 0bdab959b73..d27ed1bac00 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -48,7 +48,7 @@ #ifdef CONFIG_ISA #include #include -#include +#include #endif #include "lm75.h" -- cgit v1.2.3-70-g09d2 From 86855b0c1fd75338c67cabbf85d64d033612c47b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 15 Sep 2009 17:18:13 +0200 Subject: hwmon: Use resource_size Use the function resource_size, which reduces the chance of introducing off-by-one errors in calculating the resource size. The semantic patch that makes this change is as follows: (http://www.emn.fr/x-info/coccinelle/) // @@ struct resource *res; @@ - (res->end - res->start) + 1 + resource_size(res) // Signed-off-by: Julia Lawall Signed-off-by: Jean Delvare --- drivers/hwmon/pc87427.c | 6 +++--- drivers/hwmon/vt1211.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 4e0de0e06d7..3170b26d244 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -435,7 +435,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev) /* This will need to be revisited when we add support for temperature and voltage monitoring. */ res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { + if (!request_region(res->start, resource_size(res), DRVNAME)) { err = -EBUSY; dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n", (unsigned long)res->start, (unsigned long)res->end); @@ -475,7 +475,7 @@ exit_remove_files: sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); } exit_release_region: - release_region(res->start, res->end - res->start + 1); + release_region(res->start, resource_size(res)); exit_kfree: platform_set_drvdata(pdev, NULL); kfree(data); @@ -500,7 +500,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev) kfree(data); res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, res->end - res->start + 1); + release_region(res->start, resource_size(res)); return 0; } diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 120b5d6dbd3..ae33bbb577c 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1136,7 +1136,7 @@ static int __devinit vt1211_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) { + if (!request_region(res->start, resource_size(res), DRVNAME)) { err = -EBUSY; dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", (unsigned long)res->start, (unsigned long)res->end); @@ -1209,7 +1209,7 @@ EXIT_DEV_REMOVE: dev_err(dev, "Sysfs interface creation failed (%d)\n", err); EXIT_DEV_REMOVE_SILENT: vt1211_remove_sysfs(pdev); - release_region(res->start, res->end - res->start + 1); + release_region(res->start, resource_size(res)); EXIT_KFREE: platform_set_drvdata(pdev, NULL); kfree(data); @@ -1228,7 +1228,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev) kfree(data); res = platform_get_resource(pdev, IORESOURCE_IO, 0); - release_region(res->start, res->end - res->start + 1); + release_region(res->start, resource_size(res)); return 0; } -- cgit v1.2.3-70-g09d2 From 61cba5c244bd52e91c01e9f79abba30e54f68dd8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 15 Sep 2009 17:18:13 +0200 Subject: hwmon: Clearly mark ACPI drivers as such Now that we have ACPI-based hardware monitoring drivers, and we will start telling users to use them instead of native drivers when I/O resources conflict, I think it would be good to clearly mark ACPI drivers as such in Kconfig. Also, in the case of monolithic kernels, I think the ACPI drivers should take precedence over native drivers, so they should be listed first in Makefile. Signed-off-by: Jean Delvare Cc: Luca Tettamanti --- drivers/hwmon/Kconfig | 100 ++++++++++++++++++++++++++----------------------- drivers/hwmon/Makefile | 6 ++- 2 files changed, 58 insertions(+), 48 deletions(-) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ee57a4a2cd7..461abb1e273 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -28,6 +28,17 @@ config HWMON_VID tristate default n +config HWMON_DEBUG_CHIP + bool "Hardware Monitoring Chip debugging messages" + default n + help + Say Y here if you want the I2C chip drivers to produce a bunch of + debug messages to the system log. Select this if you are having + a problem with I2C support and want to see more of what is going + on. + +comment "Native drivers" + config SENSORS_ABITUGURU tristate "Abit uGuru (rev 1 & 2)" depends on X86 && EXPERIMENTAL @@ -248,18 +259,6 @@ config SENSORS_ASB100 This driver can also be built as a module. If so, the module will be called asb100. -config SENSORS_ATK0110 - tristate "ASUS ATK0110 ACPI hwmon" - depends on X86 && ACPI && EXPERIMENTAL - help - If you say yes here you get support for the ACPI hardware - monitoring interface found in many ASUS motherboards. This - driver will provide readings of fans, voltages and temperatures - through the system firmware. - - This driver can also be built as a module. If so, the module - will be called asus_atk0110. - config SENSORS_ATXP1 tristate "Attansic ATXP1 VID controller" depends on I2C && EXPERIMENTAL @@ -974,34 +973,6 @@ config SENSORS_HDAPS Say Y here if you have an applicable laptop and want to experience the awesome power of hdaps. -config SENSORS_LIS3LV02D - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" - depends on ACPI && INPUT - select INPUT_POLLDEV - select NEW_LEDS - select LEDS_CLASS - default n - help - This driver provides support for the LIS3LV02Dx accelerometer. In - particular, it can be found in a number of HP laptops, which have the - "Mobile Data Protection System 3D" or "3D DriveGuard" feature. On such - systems the driver should load automatically (via ACPI). The - accelerometer might also be found in other systems, connected via SPI - or I2C. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. On HP laptops, - if the led infrastructure is activated, support for a led indicating - disk protection will be provided as hp:red:hddprotection. - - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for HP laptops will be - called hp_accel. - - Say Y here if you have an applicable laptop and want to experience - the awesome power of lis3lv02d. - config SENSORS_LIS3_SPI tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" depends on !ACPI && SPI_MASTER && INPUT @@ -1044,13 +1015,50 @@ config SENSORS_APPLESMC Say Y here if you have an applicable laptop and want to experience the awesome power of applesmc. -config HWMON_DEBUG_CHIP - bool "Hardware Monitoring Chip debugging messages" +if ACPI + +comment "ACPI drivers" + +config SENSORS_ATK0110 + tristate "ASUS ATK0110" + depends on X86 && EXPERIMENTAL + help + If you say yes here you get support for the ACPI hardware + monitoring interface found in many ASUS motherboards. This + driver will provide readings of fans, voltages and temperatures + through the system firmware. + + This driver can also be built as a module. If so, the module + will be called asus_atk0110. + +config SENSORS_LIS3LV02D + tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer" + depends on INPUT + select INPUT_POLLDEV + select NEW_LEDS + select LEDS_CLASS default n help - Say Y here if you want the I2C chip drivers to produce a bunch of - debug messages to the system log. Select this if you are having - a problem with I2C support and want to see more of what is going - on. + This driver provides support for the LIS3LV02Dx accelerometer. In + particular, it can be found in a number of HP laptops, which have the + "Mobile Data Protection System 3D" or "3D DriveGuard" feature. On such + systems the driver should load automatically (via ACPI). The + accelerometer might also be found in other systems, connected via SPI + or I2C. The accelerometer data is readable via + /sys/devices/platform/lis3lv02d. + + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. On HP laptops, + if the led infrastructure is activated, support for a led indicating + disk protection will be provided as hp:red:hddprotection. + + This driver can also be built as modules. If so, the core module + will be called lis3lv02d and a specific module for HP laptops will be + called hp_accel. + + Say Y here if you have an applicable laptop and want to experience + the awesome power of lis3lv02d. + +endif # ACPI endif # HWMON diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index b577b499720..2e547881bc0 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -5,6 +5,10 @@ obj-$(CONFIG_HWMON) += hwmon.o obj-$(CONFIG_HWMON_VID) += hwmon-vid.o +# APCI drivers +obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o + +# Native drivers # asb100, then w83781d go first, as they can override other drivers' addresses. obj-$(CONFIG_SENSORS_ASB100) += asb100.o obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o @@ -29,10 +33,8 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o - obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ -obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o -- cgit v1.2.3-70-g09d2 From 5cfaf338134605ce8d9272b9c16605bc920d25be Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 15 Sep 2009 17:18:14 +0200 Subject: hwmon: (lm85) Don't bind to Winbond/Nuvoton WPCD377I The Winbond/Nuvoton WPCD377I is the reduced version of a Super-I/O which emulates the National Semiconductor LM96000 hardware monitoring chips, but without the hardware monitoring part. Instead of plain disabling the emulation, the vendor left the emulated chip visible, but all monitored values are always zero. This is rather confusing for the users. So detect this case and refuse to bind to such fake chips. This fixes lm-sensors ticket #2182: http://www.lm-sensors.org/ticket/2182 Signed-off-by: Jean Delvare --- drivers/hwmon/lm85.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers/hwmon') diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index b251d8674b4..6c53d987de1 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -75,6 +75,8 @@ I2C_CLIENT_INSMOD_7(lm85b, lm85c, adm1027, adt7463, adt7468, emc6d100, #define LM85_VERSTEP_GENERIC2 0x70 #define LM85_VERSTEP_LM85C 0x60 #define LM85_VERSTEP_LM85B 0x62 +#define LM85_VERSTEP_LM96000_1 0x68 +#define LM85_VERSTEP_LM96000_2 0x69 #define LM85_VERSTEP_ADM1027 0x60 #define LM85_VERSTEP_ADT7463 0x62 #define LM85_VERSTEP_ADT7463C 0x6A @@ -1133,6 +1135,26 @@ static void lm85_init_client(struct i2c_client *client) dev_warn(&client->dev, "Device is not ready\n"); } +static int lm85_is_fake(struct i2c_client *client) +{ + /* + * Differenciate between real LM96000 and Winbond WPCD377I. The latter + * emulate the former except that it has no hardware monitoring function + * so the readings are always 0. + */ + int i; + u8 in_temp, fan; + + for (i = 0; i < 8; i++) { + in_temp = i2c_smbus_read_byte_data(client, 0x20 + i); + fan = i2c_smbus_read_byte_data(client, 0x28 + i); + if (in_temp != 0x00 || fan != 0xff) + return 0; + } + + return 1; +} + /* Return 0 if detection is successful, -ENODEV otherwise */ static int lm85_detect(struct i2c_client *client, int kind, struct i2c_board_info *info) @@ -1173,6 +1195,16 @@ static int lm85_detect(struct i2c_client *client, int kind, case LM85_VERSTEP_LM85B: kind = lm85b; break; + case LM85_VERSTEP_LM96000_1: + case LM85_VERSTEP_LM96000_2: + /* Check for Winbond WPCD377I */ + if (lm85_is_fake(client)) { + dev_dbg(&adapter->dev, + "Found Winbond WPCD377I, " + "ignoring\n"); + return -ENODEV; + } + break; } } else if (company == LM85_COMPANY_ANALOG_DEV) { switch (verstep) { -- cgit v1.2.3-70-g09d2