diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 12:50:19 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-14 12:50:19 -0700 |
commit | 4fa435018d740cb83d74c92306aa1f796da91ddd (patch) | |
tree | b2b5783837be3d17b65b924b051aeb01e6b1fce9 /drivers/hwmon | |
parent | 7441dd12e607651128e676866630a848b664d6e7 (diff) | |
parent | a022fef5a2b19086b329d1cc64a5d78aa83e2908 (diff) |
Merge branch 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6
* 'release' of git://lm-sensors.org/kernel/mhoffman/hwmon-2.6: (53 commits)
hwmon: (vt8231) fix sparse warning
hwmon: (sis5595) fix sparse warning
hwmon: (w83627hf) don't assume bank 0
hwmon: (w83627hf) Fix setting fan min right after driver load
hwmon: (w83627hf) De-macro sysfs callback functions
hwmon: Add new combined driver for FSC chips
hwmon: (ibmpex) Release IPMI user if hwmon registration fails
hwmon: (dme1737) Add sch311x support
hwmon: (dme1737) group functions logically
hwmon: (dme1737) cleanups
hwmon: IBM power meter driver
hwmon: (coretemp) Add support for Celeron 4xx
hwmon: (lm87) Disable VID when it should be
hwmon: (w83781d) Add individual alarm and beep files
hwmon: VRM is not read from registers
MAINTAINERS: update hwmon subsystem git trees
hwmon: Fix the code examples in documentation
hwmon: update sysfs interface document - error handling
hwmon: (thmc50) Fix a debug message
hwmon: (thmc50) Don't create temp3 if not enabled
...
Diffstat (limited to 'drivers/hwmon')
62 files changed, 6614 insertions, 1625 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 192953b29b2..e47f8817080 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -30,7 +30,7 @@ config HWMON_VID config SENSORS_ABITUGURU tristate "Abit uGuru (rev 1 & 2)" - depends on EXPERIMENTAL + depends on X86 && EXPERIMENTAL help If you say yes here you get support for the sensor part of the first and second revision of the Abit uGuru chip. The voltage and frequency @@ -45,7 +45,7 @@ config SENSORS_ABITUGURU config SENSORS_ABITUGURU3 tristate "Abit uGuru (rev 3)" - depends on HWMON && EXPERIMENTAL + depends on X86 && EXPERIMENTAL help If you say yes here you get support for the sensor part of the third revision of the Abit uGuru chip. Only reading the sensors @@ -133,6 +133,16 @@ config SENSORS_ADM9240 This driver can also be built as a module. If so, the module will be called adm9240. +config SENSORS_ADT7470 + tristate "Analog Devices ADT7470" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Analog Devices + ADT7470 temperature monitoring chips. + + This driver can also be built as a module. If so, the module + will be called adt7470. + config SENSORS_K8TEMP tristate "AMD Athlon64/FX or Opteron temperature sensor" depends on X86 && PCI && EXPERIMENTAL @@ -172,7 +182,7 @@ config SENSORS_AMS_I2C config SENSORS_ASB100 tristate "Asus ASB100 Bach" - depends on I2C && EXPERIMENTAL + depends on X86 && I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the ASB100 Bach sensor @@ -206,19 +216,39 @@ config SENSORS_DS1621 will be called ds1621. config SENSORS_F71805F - tristate "Fintek F71805F/FG and F71872F/FG" + tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG" depends on EXPERIMENTAL help If you say yes here you get support for hardware monitoring - features of the Fintek F71805F/FG and F71872F/FG Super-I/O - chips. + features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG + Super-I/O chips. This driver can also be built as a module. If so, the module will be called f71805f. +config SENSORS_F71882FG + tristate "Fintek F71882FG and F71883FG" + depends on EXPERIMENTAL + help + If you say yes here you get support for hardware monitoring + features of the Fintek F71882FG and F71883FG Super-I/O chips. + + This driver can also be built as a module. If so, the module + will be called f71882fg. + +config SENSORS_F75375S + tristate "Fintek F75375S/SP and F75373"; + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for hardware monitoring + features of the Fintek F75375S/SP and F75373 + + This driver can also be built as a module. If so, the module + will be called f75375s. + config SENSORS_FSCHER tristate "FSC Hermes" - depends on I2C + depends on X86 && I2C help If you say yes here you get support for Fujitsu Siemens Computers Hermes sensor chips. @@ -228,7 +258,7 @@ config SENSORS_FSCHER config SENSORS_FSCPOS tristate "FSC Poseidon" - depends on I2C + depends on X86 && I2C help If you say yes here you get support for Fujitsu Siemens Computers Poseidon sensor chips. @@ -236,6 +266,20 @@ config SENSORS_FSCPOS This driver can also be built as a module. If so, the module will be called fscpos. +config SENSORS_FSCHMD + tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" + depends on X86 && I2C && EXPERIMENTAL + help + If you say yes here you get support for various Fujitsu Siemens + Computers sensor chips. + + This is a new merged driver for FSC sensor chips which is intended + as a replacment for the fscpos, fscscy and fscher drivers and adds + support for several other FCS sensor chips. + + This driver can also be built as a module. If so, the module + will be called fschmd. + config SENSORS_GL518SM tristate "Genesys Logic GL518SM" depends on I2C @@ -265,6 +309,19 @@ config SENSORS_CORETEMP sensor inside your CPU. Supported all are all known variants of Intel Core family. +config SENSORS_IBMPEX + tristate "IBM PowerExecutive temperature/power sensors" + select IPMI_SI + depends on IPMI_HANDLER + help + If you say yes here you get support for the temperature and + power sensors in various IBM System X servers that support + PowerExecutive. So far this includes the x3550, x3650, x3655, + x3755, and certain HS20 blades. + + This driver can also be built as a module. If so, the module + will be called ibmpex. + config SENSORS_IT87 tristate "ITE IT87xx and compatibles" select HWMON_VID @@ -401,7 +458,7 @@ config SENSORS_LM92 config SENSORS_LM93 tristate "National Semiconductor LM93 and compatibles" - depends on HWMON && I2C + depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM93 @@ -466,13 +523,13 @@ config SENSORS_SIS5595 will be called sis5595. config SENSORS_DME1737 - tristate "SMSC DME1737 and compatibles" + tristate "SMSC DME1737, SCH311x and compatibles" depends on I2C && EXPERIMENTAL select HWMON_VID help If you say yes here you get support for the hardware monitoring and fan control features of the SMSC DME1737 (and compatibles - like the Asus A8000) Super-I/O chip. + like the Asus A8000) and SCH311x Super-I/O chips. This driver can also be built as a module. If so, the module will be called dme1737. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d04f90031eb..6da3eef9430 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o +obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o @@ -29,11 +30,15 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_F71805F) += f71805f.o +obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o +obj-$(CONFIG_SENSORS_F75375S) += f75375s.o obj-$(CONFIG_SENSORS_FSCHER) += fscher.o +obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o +obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o obj-$(CONFIG_SENSORS_LM63) += lm63.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 2317f4bb9c9..4dbdb81ea3b 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -176,7 +176,7 @@ MODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" The structure is dynamically allocated, at the same time when a new abituguru device is allocated. */ struct abituguru_data { - struct class_device *class_dev; /* hwmon registered device */ + struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned long last_updated; /* In jiffies */ unsigned short addr; /* uguru base address */ @@ -1287,11 +1287,11 @@ static int __devinit abituguru_probe(struct platform_device *pdev) &abituguru_sysfs_attr[i].dev_attr)) goto abituguru_probe_error; - data->class_dev = hwmon_device_register(&pdev->dev); - if (!IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (!IS_ERR(data->hwmon_dev)) return 0; /* success */ - res = PTR_ERR(data->class_dev); + res = PTR_ERR(data->hwmon_dev); abituguru_probe_error: for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); @@ -1308,7 +1308,7 @@ static int __devexit abituguru_remove(struct platform_device *pdev) int i; struct abituguru_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index cdd8b6dea16..cb2331bfd9d 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -124,7 +124,7 @@ struct abituguru3_motherboard_info { The structure is dynamically allocated, at the same time when a new abituguru3 device is allocated. */ struct abituguru3_data { - struct class_device *class_dev; /* hwmon registered device */ + struct device *hwmon_dev; /* hwmon registered device */ struct mutex update_lock; /* protect access to data and uGuru */ unsigned short addr; /* uguru base address */ char valid; /* !=0 if following fields are valid */ @@ -933,9 +933,9 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) &abituguru3_sysfs_attr[i].dev_attr)) goto abituguru3_probe_error; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - res = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + res = PTR_ERR(data->hwmon_dev); goto abituguru3_probe_error; } @@ -957,7 +957,7 @@ static int __devexit abituguru3_remove(struct platform_device *pdev) struct abituguru3_data *data = platform_get_drvdata(pdev); platform_set_drvdata(pdev, NULL); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++) diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index cc8b624a1e5..fcd7fe78f3f 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -47,7 +47,7 @@ static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN, struct ad7418_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct attribute_group attrs; enum chips type; struct mutex lock; @@ -172,7 +172,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct i2c_client *client = to_i2c_client(dev); struct ad7418_data *data = i2c_get_clientdata(client); - int temp = simple_strtol(buf, NULL, 10); + long temp = simple_strtol(buf, NULL, 10); mutex_lock(&data->lock); data->temp[attr->index] = LM75_TEMP_TO_REG(temp); @@ -326,9 +326,9 @@ static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -347,7 +347,7 @@ exit: static int ad7418_detach_client(struct i2c_client *client) { struct ad7418_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &data->attrs); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index c466329b2ef..ebdc6d7db23 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -1,6 +1,6 @@ /* adm1021.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring + monitoring Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com> @@ -25,6 +25,7 @@ #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> @@ -32,93 +33,77 @@ /* Addresses to scan */ static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, + 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; /* Insmod parameters */ -I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, mc1066); +I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, + mc1066); /* adm1021 constants specified below */ /* The adm1021 registers */ /* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 +/* For nr in 0-1 */ +#define ADM1021_REG_TEMP(nr) (nr) #define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +/* 0x41 = AD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi */ +#define ADM1021_REG_MAN_ID 0xFE +/* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DEV_ID 0xFF /* These use different addresses for reading/writing */ #define ADM1021_REG_CONFIG_R 0x03 #define ADM1021_REG_CONFIG_W 0x09 #define ADM1021_REG_CONV_RATE_R 0x04 #define ADM1021_REG_CONV_RATE_W 0x0A /* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 +#define ADM1023_REG_REM_TEMP_PREC 0x10 +#define ADM1023_REG_REM_OFFSET 0x11 +#define ADM1023_REG_REM_OFFSET_PREC 0x12 +#define ADM1023_REG_REM_TOS_PREC 0x13 +#define ADM1023_REG_REM_THYST_PREC 0x14 /* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E +/* For nr in 0-1 */ +#define ADM1021_REG_TOS_R(nr) (0x05 + 2 * (nr)) +#define ADM1021_REG_TOS_W(nr) (0x0B + 2 * (nr)) +#define ADM1021_REG_THYST_R(nr) (0x06 + 2 * (nr)) +#define ADM1021_REG_THYST_W(nr) (0x0C + 2 * (nr)) /* write-only */ #define ADM1021_REG_ONESHOT 0x0F - -/* Conversions. Rounding and limit checking is only done on the TO_REG - variants. Note that you should be a bit careful with which arguments - these macros are called: arguments may be evaluated more than once. - Fixing this is just not worth it. */ -/* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? (val-256)*1000 : val*1000) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? (val/1000)+256 : val/1000),0,255)) - /* Initial values */ -/* Note: Even though I left the low and high limits named os and hyst, -they don't quite work like a thermostat the way the LM75 does. I.e., -a lower temp than THYST actually triggers an alarm instead of +/* Note: Even though I left the low and high limits named os and hyst, +they don't quite work like a thermostat the way the LM75 does. I.e., +a lower temp than THYST actually triggers an alarm instead of clearing it. Weird, ey? --Phil */ /* Each client has this additional data */ struct adm1021_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 temp_max; /* Register values */ - u8 temp_hyst; - u8 temp_input; - u8 remote_temp_max; - u8 remote_temp_hyst; - u8 remote_temp_input; - u8 alarms; - /* Special values for ADM1023 only */ - u8 remote_temp_prec; - u8 remote_temp_os_prec; - u8 remote_temp_hyst_prec; - u8 remote_temp_offset; - u8 remote_temp_offset_prec; + s8 temp_max[2]; /* Register values */ + s8 temp_min[2]; + s8 temp[2]; + u8 alarms; + /* Special values for ADM1023 only */ + u8 remote_temp_prec; + u8 remote_temp_os_prec; + u8 remote_temp_hyst_prec; + u8 remote_temp_offset; + u8 remote_temp_offset_prec; }; static int adm1021_attach_adapter(struct i2c_adapter *adapter); static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); static void adm1021_init_client(struct i2c_client *client); static int adm1021_detach_client(struct i2c_client *client); -static int adm1021_read_value(struct i2c_client *client, u8 reg); -static int adm1021_write_value(struct i2c_client *client, u8 reg, - u16 value); static struct adm1021_data *adm1021_update_device(struct device *dev); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ @@ -135,53 +120,104 @@ static struct i2c_driver adm1021_driver = { .detach_client = adm1021_detach_client, }; -#define show(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->value)); \ +static ssize_t show_temp(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp[index]); } -show(temp_max); -show(temp_hyst); -show(temp_input); -show(remote_temp_max); -show(remote_temp_hyst); -show(remote_temp_input); - -#define show2(value) \ -static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1021_data *data = adm1021_update_device(dev); \ - return sprintf(buf, "%d\n", data->value); \ + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp_max[index]); } -show2(alarms); - -#define set(value, reg) \ -static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1021_data *data = i2c_get_clientdata(client); \ - int temp = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->value = TEMP_TO_REG(temp); \ - adm1021_write_value(client, reg, data->value); \ - mutex_unlock(&data->update_lock); \ - return count; \ + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + + return sprintf(buf, "%d\n", 1000 * data->temp_min[index]); +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1021_data *data = adm1021_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> index) & 1); +} + +static ssize_t show_alarms(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct adm1021_data *data = adm1021_update_device(dev); + return sprintf(buf, "%u\n", data->alarms); } -set(temp_max, ADM1021_REG_TOS_W); -set(temp_hyst, ADM1021_REG_THYST_W); -set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); -set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); - -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); -static DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); -static DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); -static DEVICE_ATTR(temp2_input, S_IRUGO, show_remote_temp_input, NULL); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t set_temp_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + long temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->update_lock); + data->temp_max[index] = SENSORS_LIMIT(temp, -128, 127); + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_TOS_W(index), + data->temp_max[index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t set_temp_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1021_data *data = i2c_get_clientdata(client); + long temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->update_lock); + data->temp_min[index] = SENSORS_LIMIT(temp, -128, 127); + if (!read_only) + i2c_smbus_write_byte_data(client, ADM1021_REG_THYST_W(index), + data->temp_min[index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 1); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); + +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static int adm1021_attach_adapter(struct i2c_adapter *adapter) { @@ -191,12 +227,17 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *adm1021_attributes[] = { - &dev_attr_temp1_max.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp2_input.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &dev_attr_alarms.attr, NULL }; @@ -208,35 +249,44 @@ static const struct attribute_group adm1021_group = { static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) { int i; - struct i2c_client *new_client; + struct i2c_client *client; struct adm1021_data *data; int err = 0; const char *type_name = ""; + int conv_rate, status, config; - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pr_debug("adm1021: detect failed, " + "smbus byte data not supported!\n"); goto error0; + } /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. - But it allows us to access adm1021_{read,write}_value. */ + But it allows us to access adm1021 register values. */ if (!(data = kzalloc(sizeof(struct adm1021_data), GFP_KERNEL))) { + pr_debug("adm1021: detect failed, kzalloc failed!\n"); err = -ENOMEM; goto error0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1021_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1021_driver; + status = i2c_smbus_read_byte_data(client, ADM1021_REG_STATUS); + conv_rate = i2c_smbus_read_byte_data(client, + ADM1021_REG_CONV_RATE_R); + config = i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R); /* Now, we do the remaining detection. */ if (kind < 0) { - if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x3F) != 0x00 - || (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) & 0xF8) != 0x00) { + if ((status & 0x03) != 0x00 || (config & 0x3F) != 0x00 + || (conv_rate & 0xF8) != 0x00) { + pr_debug("adm1021: detect failed, " + "chip not detected!\n"); err = -ENODEV; goto error1; } @@ -244,9 +294,10 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) /* Determine the chip type. */ if (kind <= 0) { - i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); + i = i2c_smbus_read_byte_data(client, ADM1021_REG_MAN_ID); if (i == 0x41) - if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + if ((i2c_smbus_read_byte_data(client, + ADM1021_REG_DEV_ID) & 0xF0) == 0x30) kind = adm1023; else kind = adm1021; @@ -255,15 +306,16 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) else if (i == 0x23) kind = gl523sm; else if ((i == 0x4d) && - (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) + (i2c_smbus_read_byte_data(client, + ADM1021_REG_DEV_ID) == 0x01)) kind = max1617a; else if (i == 0x54) kind = mc1066; /* LM84 Mfr ID in a different place, and it has more unused bits */ - else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00 - && (kind == 0 /* skip extra detection */ - || ((adm1021_read_value(new_client, ADM1021_REG_CONFIG_R) & 0x7F) == 0x00 - && (adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0xAB) == 0x00))) + else if (conv_rate == 0x00 + && (kind == 0 /* skip extra detection */ + || ((config & 0x7F) == 0x00 + && (status & 0xAB) == 0x00))) kind = lm84; else kind = max1617; @@ -286,37 +338,38 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) } else if (kind == mc1066) { type_name = "mc1066"; } + pr_debug("adm1021: Detected chip %s at adapter %d, address 0x%02x.\n", + type_name, i2c_adapter_id(adapter), address); - /* Fill in the remaining client fields and put it into the global list */ - strlcpy(new_client->name, type_name, I2C_NAME_SIZE); + /* Fill in the remaining client fields */ + strlcpy(client->name, type_name, I2C_NAME_SIZE); data->type = kind; - data->valid = 0; mutex_init(&data->update_lock); /* Tell the I2C layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) + if ((err = i2c_attach_client(client))) goto error1; /* Initialize the ADM1021 chip */ - if (kind != lm84) - adm1021_init_client(new_client); + if (kind != lm84 && !read_only) + adm1021_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1021_group))) goto error2; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error3; } return 0; error3: - sysfs_remove_group(&new_client->dev.kobj, &adm1021_group); + sysfs_remove_group(&client->dev.kobj, &adm1021_group); error2: - i2c_detach_client(new_client); + i2c_detach_client(client); error1: kfree(data); error0: @@ -326,10 +379,10 @@ error0: static void adm1021_init_client(struct i2c_client *client) { /* Enable ADC and disable suspend mode */ - adm1021_write_value(client, ADM1021_REG_CONFIG_W, - adm1021_read_value(client, ADM1021_REG_CONFIG_R) & 0xBF); + i2c_smbus_write_byte_data(client, ADM1021_REG_CONFIG_W, + i2c_smbus_read_byte_data(client, ADM1021_REG_CONFIG_R) & 0xBF); /* Set Conversion rate to 1/sec (this can be tinkered with) */ - adm1021_write_value(client, ADM1021_REG_CONV_RATE_W, 0x04); + i2c_smbus_write_byte_data(client, ADM1021_REG_CONV_RATE_W, 0x04); } static int adm1021_detach_client(struct i2c_client *client) @@ -337,7 +390,7 @@ static int adm1021_detach_client(struct i2c_client *client) struct adm1021_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1021_group); if ((err = i2c_detach_client(client))) @@ -347,19 +400,6 @@ static int adm1021_detach_client(struct i2c_client *client) return 0; } -/* All registers are byte-sized */ -static int adm1021_read_value(struct i2c_client *client, u8 reg) -{ - return i2c_smbus_read_byte_data(client, reg); -} - -static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value) -{ - if (!read_only) - return i2c_smbus_write_byte_data(client, reg, value); - return 0; -} - static struct adm1021_data *adm1021_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -369,21 +409,36 @@ static struct adm1021_data *adm1021_update_device(struct device *dev) if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { + int i; + dev_dbg(&client->dev, "Starting adm1021 update\n"); - data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0x7c; + for (i = 0; i < 2; i++) { + data->temp[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_TEMP(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_TOS_R(i)); + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADM1021_REG_THYST_R(i)); + } + data->alarms = i2c_smbus_read_byte_data(client, + ADM1021_REG_STATUS) & 0x7c; if (data->type == adm1023) { - data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + data->remote_temp_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_THYST_PREC); + data->remote_temp_offset = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_OFFSET); + data->remote_temp_offset_prec = + i2c_smbus_read_byte_data(client, + ADM1023_REG_REM_OFFSET_PREC); } data->last_updated = jiffies; data->valid = 1; diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 8c562885b54..041ecb0bdf4 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -133,7 +133,7 @@ static struct i2c_driver adm1025_driver = { struct adm1025_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -292,7 +292,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm1025_data *data = adm1025_update_device(dev); + struct adm1025_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -472,9 +472,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -538,7 +538,7 @@ static int adm1025_detach_client(struct i2c_client *client) struct adm1025_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1025_group); sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index ba80cd3258c..aa875ca50d9 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -260,7 +260,7 @@ struct pwm_data { struct adm1026_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -1221,7 +1221,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct adm1026_data *data = adm1026_update_device(dev); + struct adm1026_data *data = dev_get_drvdata(dev); return sprintf(buf,"%d\n", data->vrm); } static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, @@ -1676,9 +1676,9 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address, if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group))) goto exitdetach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exitremove; } @@ -1698,7 +1698,7 @@ exit: static int adm1026_detach_client(struct i2c_client *client) { struct adm1026_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1026_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 73ce31b3151..0bc897dffa2 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -141,7 +141,7 @@ static struct i2c_driver adm1029_driver = { struct adm1029_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -391,9 +391,9 @@ static int adm1029_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&client->dev.kobj, &adm1029_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -431,7 +431,7 @@ static int adm1029_detach_client(struct i2c_client *client) struct adm1029_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1029_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 122683fc91d..37cfc101da5 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -70,7 +70,7 @@ typedef u8 auto_chan_table_t[8][2]; /* Each client has this additional data */ struct adm1031_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; int chip_type; char valid; /* !=0 if following fields are valid */ @@ -853,9 +853,9 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -877,7 +877,7 @@ static int adm1031_detach_client(struct i2c_client *client) struct adm1031_data *data = i2c_get_clientdata(client); int ret; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1031_group); sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt); if ((ret = i2c_detach_client(client)) != 0) { diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index aad594adf0c..c17d0b6b328 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -150,7 +150,7 @@ static struct i2c_driver adm9240_driver = { struct adm9240_data { enum chips type; struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated_measure; @@ -590,9 +590,9 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -620,7 +620,7 @@ static int adm9240_detach_client(struct i2c_client *client) struct adm9240_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm9240_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c new file mode 100644 index 00000000000..9810aaa0489 --- /dev/null +++ b/drivers/hwmon/adt7470.c @@ -0,0 +1,1050 @@ +/* + * A hwmon driver for the Analog Devices ADT7470 + * Copyright (C) 2007 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.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/delay.h> +#include <linux/log2.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(adt7470); + +/* ADT7470 registers */ +#define ADT7470_REG_BASE_ADDR 0x20 +#define ADT7470_REG_TEMP_BASE_ADDR 0x20 +#define ADT7470_REG_TEMP_MAX_ADDR 0x29 +#define ADT7470_REG_FAN_BASE_ADDR 0x2A +#define ADT7470_REG_FAN_MAX_ADDR 0x31 +#define ADT7470_REG_PWM_BASE_ADDR 0x32 +#define ADT7470_REG_PWM_MAX_ADDR 0x35 +#define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38 +#define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B +#define ADT7470_REG_CFG 0x40 +#define ADT7470_FSPD_MASK 0x04 +#define ADT7470_REG_ALARM1 0x41 +#define ADT7470_REG_ALARM2 0x42 +#define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44 +#define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57 +#define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58 +#define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F +#define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60 +#define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67 +#define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68 +#define ADT7470_REG_PWM12_CFG 0x68 +#define ADT7470_PWM2_AUTO_MASK 0x40 +#define ADT7470_PWM1_AUTO_MASK 0x80 +#define ADT7470_REG_PWM34_CFG 0x69 +#define ADT7470_PWM3_AUTO_MASK 0x40 +#define ADT7470_PWM4_AUTO_MASK 0x80 +#define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A +#define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D +#define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E +#define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71 +#define ADT7470_REG_ACOUSTICS12 0x75 +#define ADT7470_REG_ACOUSTICS34 0x76 +#define ADT7470_REG_DEVICE 0x3D +#define ADT7470_REG_VENDOR 0x3E +#define ADT7470_REG_REVISION 0x3F +#define ADT7470_REG_ALARM1_MASK 0x72 +#define ADT7470_REG_ALARM2_MASK 0x73 +#define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C +#define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D +#define ADT7470_REG_MAX_ADDR 0x81 + +#define ADT7470_TEMP_COUNT 10 +#define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x)) +#define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2)) +#define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \ + ((x) * 2) + 1) + +#define ADT7470_FAN_COUNT 4 +#define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2)) +#define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2)) +#define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2)) + +#define ADT7470_PWM_COUNT 4 +#define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x)) +#define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2)) +#define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \ + ((x) / 2)) + +#define ADT7470_VENDOR 0x41 +#define ADT7470_DEVICE 0x70 +/* datasheet only mentions a revision 2 */ +#define ADT7470_REVISION 0x02 + +/* "all temps" according to hwmon sysfs interface spec */ +#define ADT7470_PWM_ALL_TEMPS 0x3FF + +/* How often do we reread sensors values? (In jiffies) */ +#define SENSOR_REFRESH_INTERVAL (5 * HZ) + +/* How often do we reread sensor limit values? (In jiffies) */ +#define LIMIT_REFRESH_INTERVAL (60 * HZ) + +/* sleep 1s while gathering temperature data */ +#define TEMP_COLLECTION_TIME 1000 + +#define power_of_2(x) (((x) & ((x) - 1)) == 0) + +/* datasheet says to divide this number by the fan reading to get fan rpm */ +#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) +#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM +#define FAN_PERIOD_INVALID 65535 +#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) + +struct adt7470_data { + struct i2c_client client; + struct device *hwmon_dev; + struct attribute_group attrs; + struct mutex lock; + char sensors_valid; + char limits_valid; + unsigned long sensors_last_updated; /* In jiffies */ + unsigned long limits_last_updated; /* In jiffies */ + + s8 temp[ADT7470_TEMP_COUNT]; + s8 temp_min[ADT7470_TEMP_COUNT]; + s8 temp_max[ADT7470_TEMP_COUNT]; + u16 fan[ADT7470_FAN_COUNT]; + u16 fan_min[ADT7470_FAN_COUNT]; + u16 fan_max[ADT7470_FAN_COUNT]; + u16 alarms, alarms_mask; + u8 force_pwm_max; + u8 pwm[ADT7470_PWM_COUNT]; + u8 pwm_max[ADT7470_PWM_COUNT]; + u8 pwm_automatic[ADT7470_PWM_COUNT]; + u8 pwm_min[ADT7470_PWM_COUNT]; + s8 pwm_tmin[ADT7470_PWM_COUNT]; + u8 pwm_auto_temp[ADT7470_PWM_COUNT]; +}; + +static int adt7470_attach_adapter(struct i2c_adapter *adapter); +static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind); +static int adt7470_detach_client(struct i2c_client *client); + +static struct i2c_driver adt7470_driver = { + .driver = { + .name = "adt7470", + }, + .attach_adapter = adt7470_attach_adapter, + .detach_client = adt7470_detach_client, +}; + +/* + * 16-bit registers on the ADT7470 are low-byte first. The data sheet says + * that the low byte must be read before the high byte. + */ +static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg) +{ + u16 foo; + foo = i2c_smbus_read_byte_data(client, reg); + foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8); + return foo; +} + +static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg, + u16 value) +{ + return i2c_smbus_write_byte_data(client, reg, value & 0xFF) + && i2c_smbus_write_byte_data(client, reg + 1, value >> 8); +} + +static void adt7470_init_client(struct i2c_client *client) +{ + int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + + if (reg < 0) { + dev_err(&client->dev, "cannot read configuration register\n"); + } else { + /* start monitoring (and do a self-test) */ + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3); + } +} + +static struct adt7470_data *adt7470_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + unsigned long local_jiffies = jiffies; + u8 cfg; + int i; + + mutex_lock(&data->lock); + if (time_before(local_jiffies, data->sensors_last_updated + + SENSOR_REFRESH_INTERVAL) + && data->sensors_valid) + goto no_sensor_update; + + /* start reading temperature sensors */ + cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + cfg |= 0x80; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); + + /* + * Delay is 200ms * number of tmp05 sensors. Too bad + * there's no way to figure out how many are connected. + * For now, assume 1s will work. + */ + msleep(TEMP_COLLECTION_TIME); + + /* done reading temperature sensors */ + cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + cfg &= ~0x80; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_REG(i)); + + for (i = 0; i < ADT7470_FAN_COUNT; i++) + data->fan[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN(i)); + + for (i = 0; i < ADT7470_PWM_COUNT; i++) { + int reg; + int reg_mask; + + data->pwm[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM(i)); + + if (i % 2) + reg_mask = ADT7470_PWM2_AUTO_MASK; + else + reg_mask = ADT7470_PWM1_AUTO_MASK; + + reg = ADT7470_REG_PWM_CFG(i); + if (i2c_smbus_read_byte_data(client, reg) & reg_mask) + data->pwm_automatic[i] = 1; + else + data->pwm_automatic[i] = 0; + + reg = ADT7470_REG_PWM_AUTO_TEMP(i); + cfg = i2c_smbus_read_byte_data(client, reg); + if (!(i % 2)) + data->pwm_auto_temp[i] = cfg >> 4; + else + data->pwm_auto_temp[i] = cfg & 0xF; + } + + if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) & + ADT7470_FSPD_MASK) + data->force_pwm_max = 1; + else + data->force_pwm_max = 0; + + data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1); + data->alarms_mask = adt7470_read_word_data(client, + ADT7470_REG_ALARM1_MASK); + + data->sensors_last_updated = local_jiffies; + data->sensors_valid = 1; + +no_sensor_update: + if (time_before(local_jiffies, data->limits_last_updated + + LIMIT_REFRESH_INTERVAL) + && data->limits_valid) + goto out; + + for (i = 0; i < ADT7470_TEMP_COUNT; i++) { + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_MIN_REG(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADT7470_TEMP_MAX_REG(i)); + } + + for (i = 0; i < ADT7470_FAN_COUNT; i++) { + data->fan_min[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN_MIN(i)); + data->fan_max[i] = adt7470_read_word_data(client, + ADT7470_REG_FAN_MAX(i)); + } + + for (i = 0; i < ADT7470_PWM_COUNT; i++) { + data->pwm_max[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_MAX(i)); + data->pwm_min[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_MIN(i)); + data->pwm_tmin[i] = i2c_smbus_read_byte_data(client, + ADT7470_REG_PWM_TMIN(i)); + } + + data->limits_last_updated = local_jiffies; + data->limits_valid = 1; + +out: + mutex_unlock(&data->lock); + return data; +} + +static ssize_t show_temp_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]); +} + +static ssize_t set_temp_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->temp_min[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]); +} + +static ssize_t set_temp_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->temp_max[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]); +} + +static ssize_t show_alarms(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (attr->index) + return sprintf(buf, "%x\n", data->alarms); + else + return sprintf(buf, "%x\n", data->alarms_mask); +} + +static ssize_t show_fan_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan_max[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan_max[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t set_fan_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + if (!temp) + return -EINVAL; + temp = FAN_RPM_TO_PERIOD(temp); + + mutex_lock(&data->lock); + data->fan_max[attr->index] = temp; + adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_fan_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan_min[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan_min[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t set_fan_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + if (!temp) + return -EINVAL; + temp = FAN_RPM_TO_PERIOD(temp); + + mutex_lock(&data->lock); + data->fan_min[attr->index] = temp; + adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + + if (FAN_DATA_VALID(data->fan[attr->index])) + return sprintf(buf, "%d\n", + FAN_PERIOD_TO_RPM(data->fan[attr->index])); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_force_pwm_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->force_pwm_max); +} + +static ssize_t set_force_pwm_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + u8 reg; + + mutex_lock(&data->lock); + data->force_pwm_max = temp; + reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); + if (temp) + reg |= ADT7470_FSPD_MASK; + else + reg &= ~ADT7470_FSPD_MASK; + i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm[attr->index]); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_max(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_max[attr->index]); +} + +static ssize_t set_pwm_max(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm_max[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_min[attr->index]); +} + +static ssize_t set_pwm_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->lock); + data->pwm_min[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_tmax(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + /* the datasheet says that tmax = tmin + 20C */ + return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index])); +} + +static ssize_t show_pwm_tmin(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]); +} + +static ssize_t set_pwm_tmin(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10) / 1000; + + mutex_lock(&data->lock); + data->pwm_tmin[attr->index] = temp; + i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index), + temp); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_auto(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]); +} + +static ssize_t set_pwm_auto(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = simple_strtol(buf, NULL, 10); + int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index); + int pwm_auto_reg_mask; + u8 reg; + + if (attr->index % 2) + pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK; + else + pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK; + + if (temp != 2 && temp != 1) + return -EINVAL; + temp--; + + mutex_lock(&data->lock); + data->pwm_automatic[attr->index] = temp; + reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); + if (temp) + reg |= pwm_auto_reg_mask; + else + reg &= ~pwm_auto_reg_mask; + i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); + mutex_unlock(&data->lock); + + return count; +} + +static ssize_t show_pwm_auto_temp(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7470_data *data = adt7470_update_device(dev); + u8 ctrl = data->pwm_auto_temp[attr->index]; + + if (ctrl) + return sprintf(buf, "%d\n", 1 << (ctrl - 1)); + else + return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS); +} + +static int cvt_auto_temp(int input) +{ + if (input == ADT7470_PWM_ALL_TEMPS) + return 0; + if (input < 1 || !power_of_2(input)) + return -EINVAL; + return ilog2(input) + 1; +} + +static ssize_t set_pwm_auto_temp(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7470_data *data = i2c_get_clientdata(client); + int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10)); + int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index); + u8 reg; + + if (temp < 0) + return temp; + + mutex_lock(&data->lock); + data->pwm_automatic[attr->index] = temp; + reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); + + if (!(attr->index % 2)) { + reg &= 0xF; + reg |= (temp << 4) & 0xF0; + } else { + reg &= 0xF0; + reg |= temp & 0xF; + } + + i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); + mutex_unlock(&data->lock); + + return count; +} + +static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0); +static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1); + +static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 2); +static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 3); +static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 4); +static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 5); +static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 6); +static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 7); +static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 8); +static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max, + set_temp_max, 9); + +static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 0); +static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 1); +static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 2); +static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 3); +static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 4); +static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 5); +static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 6); +static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 7); +static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 8); +static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min, + set_temp_min, 9); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6); +static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7); +static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8); +static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9); + +static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 0); +static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 1); +static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 2); +static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max, + set_fan_max, 3); + +static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 2); +static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, + set_fan_min, 3); + +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); + +static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO, + show_force_pwm_max, set_force_pwm_max, 0); + +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO, + show_pwm_min, set_pwm_min, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO, + show_pwm_max, set_pwm_max, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO, + show_pwm_tmin, set_pwm_tmin, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax, + NULL, 3); + +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 0); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 1); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 2); +static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto, + set_pwm_auto, 3); + +static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 0); +static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 1); +static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 2); +static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, + show_pwm_auto_temp, set_pwm_auto_temp, 3); + +static struct attribute *adt7470_attr[] = +{ + &sensor_dev_attr_alarms.dev_attr.attr, + &sensor_dev_attr_alarm_mask.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + &sensor_dev_attr_temp6_max.dev_attr.attr, + &sensor_dev_attr_temp7_max.dev_attr.attr, + &sensor_dev_attr_temp8_max.dev_attr.attr, + &sensor_dev_attr_temp9_max.dev_attr.attr, + &sensor_dev_attr_temp10_max.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp4_min.dev_attr.attr, + &sensor_dev_attr_temp5_min.dev_attr.attr, + &sensor_dev_attr_temp6_min.dev_attr.attr, + &sensor_dev_attr_temp7_min.dev_attr.attr, + &sensor_dev_attr_temp8_min.dev_attr.attr, + &sensor_dev_attr_temp9_min.dev_attr.attr, + &sensor_dev_attr_temp10_min.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_temp7_input.dev_attr.attr, + &sensor_dev_attr_temp8_input.dev_attr.attr, + &sensor_dev_attr_temp9_input.dev_attr.attr, + &sensor_dev_attr_temp10_input.dev_attr.attr, + &sensor_dev_attr_fan1_max.dev_attr.attr, + &sensor_dev_attr_fan2_max.dev_attr.attr, + &sensor_dev_attr_fan3_max.dev_attr.attr, + &sensor_dev_attr_fan4_max.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_force_pwm_max.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm4.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + &sensor_dev_attr_pwm4_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, + &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr, + NULL +}; + +static int adt7470_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, adt7470_detect); +} + +static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct adt7470_data *data; + int err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto exit; + + if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + client->addr = address; + client->adapter = adapter; + client->driver = &adt7470_driver; + + i2c_set_clientdata(client, data); + + mutex_init(&data->lock); + + if (kind <= 0) { + int vendor, device, revision; + + vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR); + if (vendor != ADT7470_VENDOR) { + err = -ENODEV; + goto exit_free; + } + + device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE); + if (device != ADT7470_DEVICE) { + err = -ENODEV; + goto exit_free; + } + + revision = i2c_smbus_read_byte_data(client, + ADT7470_REG_REVISION); + if (revision != ADT7470_REVISION) { + err = -ENODEV; + goto exit_free; + } + } else + dev_dbg(&adapter->dev, "detection forced\n"); + + strlcpy(client->name, "adt7470", I2C_NAME_SIZE); + + if ((err = i2c_attach_client(client))) + goto exit_free; + + dev_info(&client->dev, "%s chip found\n", client->name); + + /* Initialize the ADT7470 chip */ + adt7470_init_client(client); + + /* Register sysfs hooks */ + data->attrs.attrs = adt7470_attr; + if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attrs); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int adt7470_detach_client(struct i2c_client *client) +{ + struct adt7470_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->attrs); + i2c_detach_client(client); + kfree(data); + return 0; +} + +static int __init adt7470_init(void) +{ + return i2c_add_driver(&adt7470_driver); +} + +static void __exit adt7470_exit(void) +{ + i2c_del_driver(&adt7470_driver); +} + +MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_DESCRIPTION("ADT7470 driver"); +MODULE_LICENSE("GPL"); + +module_init(adt7470_init); +module_exit(adt7470_exit); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 56213b7f818..f37fd7ebf65 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -127,7 +127,7 @@ static s16 rest_x; static s16 rest_y; static struct timer_list applesmc_timer; static struct input_dev *applesmc_idev; -static struct class_device *hwmon_class_dev; +static struct device *hwmon_dev; /* Indicates whether this computer has an accelerometer. */ static unsigned int applesmc_accelerometer; @@ -1287,9 +1287,9 @@ static int __init applesmc_init(void) goto out_light_wq; } - hwmon_class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(hwmon_class_dev)) { - ret = PTR_ERR(hwmon_class_dev); + hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon_dev)) { + ret = PTR_ERR(hwmon_dev); goto out_light_ledclass; } @@ -1331,7 +1331,7 @@ out: static void __exit applesmc_exit(void) { - hwmon_device_unregister(hwmon_class_dev); + hwmon_device_unregister(hwmon_dev); if (applesmc_light) { led_classdev_unregister(&applesmc_backlight); destroy_workqueue(applesmc_led_wq); diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 57b1c7b7ac3..9460dba4cf7 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -143,7 +143,7 @@ static int FAN_FROM_REG(u8 val, int div) /* TEMP: 0.001C/bit (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) +static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, ASB100_TEMP_MIN, ASB100_TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -182,7 +182,7 @@ static u8 DIV_TO_REG(long val) dynamically allocated, at the same time the client itself is allocated. */ struct asb100_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -448,7 +448,7 @@ static ssize_t set_##reg(struct device *dev, const char *buf, \ { \ struct i2c_client *client = to_i2c_client(dev); \ struct asb100_data *data = i2c_get_clientdata(client); \ - unsigned long val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ switch (nr) { \ @@ -514,7 +514,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); /* VRM */ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct asb100_data *data = asb100_update_device(dev); + struct asb100_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -844,9 +844,9 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -874,7 +874,7 @@ static int asb100_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &asb100_group); } diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index 0ccdd0750c4..cce3350e539 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -61,7 +61,7 @@ static struct i2c_driver atxp1_driver = { struct atxp1_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; u8 valid; @@ -335,9 +335,9 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -361,7 +361,7 @@ static int atxp1_detach_client(struct i2c_client * client) struct atxp1_data * data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &atxp1_group); err = i2c_detach_client(client); diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 7c1795225b0..6f66551d9e5 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -47,7 +47,7 @@ typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW; static struct coretemp_data *coretemp_update_device(struct device *dev); struct coretemp_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; const char *name; u32 id; @@ -58,8 +58,6 @@ struct coretemp_data { u8 alarm; }; -static struct coretemp_data *coretemp_update_device(struct device *dev); - /* * Sysfs stuff */ @@ -228,9 +226,9 @@ static int __devinit coretemp_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group))) goto exit_free; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_class; @@ -250,7 +248,7 @@ static int __devexit coretemp_remove(struct platform_device *pdev) { struct coretemp_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &coretemp_group); platform_set_drvdata(pdev, NULL); kfree(data); @@ -350,7 +348,7 @@ static int coretemp_cpu_callback(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __cpuinitdata coretemp_cpu_notifier = { +static struct notifier_block coretemp_cpu_notifier = { .notifier_call = coretemp_cpu_callback, }; #endif /* !CONFIG_HOTPLUG_CPU */ @@ -371,9 +369,10 @@ static int __init coretemp_init(void) for_each_online_cpu(i) { struct cpuinfo_x86 *c = &(cpu_data)[i]; - /* check if family 6, models e, f */ + /* check if family 6, models e, f, 16 */ if ((c->cpuid_level < 0) || (c->x86 != 0x6) || - !((c->x86_model == 0xe) || (c->x86_model == 0xf))) { + !((c->x86_model == 0xe) || (c->x86_model == 0xf) || + (c->x86_model == 0x16))) { /* supported CPU not found, but report the unknown family 6 CPU */ diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index e9cbc727664..a878c98e252 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -1,12 +1,12 @@ /* - * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips - * integrated hardware monitoring features. + * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x + * Super-I/O chips integrated hardware monitoring features. * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com> * - * This driver is based on the LM85 driver. The hardware monitoring - * capabilities of the DME1737 are very similar to the LM85 with some - * additional features. Even though the DME1737 is a Super-I/O chip, the - * hardware monitoring registers are only accessible via SMBus. + * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access + * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a + * SCH311x chip is found. Both types of chips have very similar hardware + * monitoring capabilities but differ in the way they can be accessed. * * 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 @@ -28,6 +28,7 @@ #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> +#include <linux/platform_device.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> @@ -35,6 +36,9 @@ #include <linux/mutex.h> #include <asm/io.h> +/* ISA device, if found */ +static struct platform_device *pdev; + /* Module load parameters */ static int force_start; module_param(force_start, bool, 0); @@ -133,6 +137,7 @@ static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6}; static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; /* Miscellaneous registers */ +#define DME1737_REG_DEVICE 0x3d #define DME1737_REG_COMPANY 0x3e #define DME1737_REG_VERSTEP 0x3f #define DME1737_REG_CONFIG 0x40 @@ -148,14 +153,20 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23}; #define DME1737_COMPANY_SMSC 0x5c #define DME1737_VERSTEP 0x88 #define DME1737_VERSTEP_MASK 0xf8 +#define SCH311X_DEVICE 0x8c + +/* Length of ISA address segment */ +#define DME1737_EXTENT 2 /* --------------------------------------------------------------------- * Data structures and manipulation thereof * --------------------------------------------------------------------- */ +/* For ISA chips, we abuse the i2c_client addr and name fields. We also use + the driver field to differentiate between I2C and ISA chips. */ struct dme1737_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; int valid; /* !=0 if following fields are valid */ @@ -465,27 +476,48 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg) /* --------------------------------------------------------------------- * Device I/O access + * + * ISA access is performed through an index/data register pair and needs to + * be protected by a mutex during runtime (not required for initialization). + * We use data->update_lock for this and need to ensure that we acquire it + * before calling dme1737_read or dme1737_write. * --------------------------------------------------------------------- */ static u8 dme1737_read(struct i2c_client *client, u8 reg) { - s32 val = i2c_smbus_read_byte_data(client, reg); + s32 val; + + if (client->driver) { /* I2C device */ + val = i2c_smbus_read_byte_data(client, reg); - if (val < 0) { - dev_warn(&client->dev, "Read from register 0x%02x failed! " - "Please report to the driver maintainer.\n", reg); + if (val < 0) { + dev_warn(&client->dev, "Read from register " + "0x%02x failed! Please report to the driver " + "maintainer.\n", reg); + } + } else { /* ISA device */ + outb(reg, client->addr); + val = inb(client->addr + 1); } return val; } -static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value) +static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val) { - s32 res = i2c_smbus_write_byte_data(client, reg, value); + s32 res = 0; + + if (client->driver) { /* I2C device */ + res = i2c_smbus_write_byte_data(client, reg, val); - if (res < 0) { - dev_warn(&client->dev, "Write to register 0x%02x failed! " - "Please report to the driver maintainer.\n", reg); + if (res < 0) { + dev_warn(&client->dev, "Write to register " + "0x%02x failed! Please report to the driver " + "maintainer.\n", reg); + } + } else { /* ISA device */ + outb(reg, client->addr); + outb(val, client->addr + 1); } return res; @@ -493,8 +525,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value) static struct dme1737_data *dme1737_update_device(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; int ix; u8 lsb[5]; @@ -630,6 +662,24 @@ static struct dme1737_data *dme1737_update_device(struct device *dev) DME1737_REG_ALARM3) << 16; } + /* The ISA chips require explicit clearing of alarm bits. + * Don't worry, an alarm will come back if the condition + * that causes it still exists */ + if (!client->driver) { + if (data->alarms & 0xff0000) { + dme1737_write(client, DME1737_REG_ALARM3, + 0xff); + } + if (data->alarms & 0xff00) { + dme1737_write(client, DME1737_REG_ALARM2, + 0xff); + } + if (data->alarms & 0xff) { + dme1737_write(client, DME1737_REG_ALARM1, + 0xff); + } + } + data->last_update = jiffies; data->valid = 1; } @@ -674,7 +724,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -683,8 +733,8 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr, static ssize_t set_in(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -704,7 +754,7 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr, data->in_max[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -754,7 +804,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -763,8 +813,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, static ssize_t set_temp(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -789,7 +839,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, data->temp_offset[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -843,7 +893,7 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -852,8 +902,8 @@ static ssize_t show_zone(struct device *dev, struct device_attribute *attr, static ssize_t set_zone(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -898,7 +948,7 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, data->zone_abs[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } mutex_unlock(&data->update_lock); @@ -950,7 +1000,7 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); @@ -959,8 +1009,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, static ssize_t set_fan(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -995,7 +1045,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, /* Only valid for fan[1-4] */ if (!(val == 1 || val == 2 || val == 4)) { count = -EINVAL; - dev_warn(&client->dev, "Fan type value %ld not " + dev_warn(dev, "Fan type value %ld not " "supported. Choose one of 1, 2, or 4.\n", val); goto exit; @@ -1006,7 +1056,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr, data->fan_opt[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } exit: mutex_unlock(&data->update_lock); @@ -1086,20 +1136,20 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, break; default: res = 0; - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } return sprintf(buf, "%d\n", res); } static struct attribute *dme1737_attr_pwm[]; -static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t); +static void dme1737_chmod_file(struct device*, struct attribute*, mode_t); static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; struct sensor_device_attribute_2 *sensor_attr_2 = to_sensor_dev_attr_2(attr); int ix = sensor_attr_2->index; @@ -1122,7 +1172,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, /* Only valid for pwm[1-3] */ if (val < 0 || val > 2) { count = -EINVAL; - dev_warn(&client->dev, "PWM enable %ld not " + dev_warn(dev, "PWM enable %ld not " "supported. Choose one of 0, 1, or 2.\n", val); goto exit; @@ -1156,7 +1206,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, switch (val) { case 0: /* Change permissions of pwm[ix] to read-only */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO); /* Turn fan fully on */ data->pwm_config[ix] = PWM_EN_TO_REG(0, @@ -1171,12 +1221,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, dme1737_write(client, DME1737_REG_PWM_CONFIG(ix), data->pwm_config[ix]); /* Change permissions of pwm[ix] to read-writeable */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO | S_IWUSR); break; case 2: /* Change permissions of pwm[ix] to read-only */ - dme1737_chmod_file(client, dme1737_attr_pwm[ix], + dme1737_chmod_file(dev, dme1737_attr_pwm[ix], S_IRUGO); /* Turn on auto mode using the saved zone channel * assignment */ @@ -1223,7 +1273,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, if (!(val == 1 || val == 2 || val == 4 || val == 6 || val == 7)) { count = -EINVAL; - dev_warn(&client->dev, "PWM auto channels zone %ld " + dev_warn(dev, "PWM auto channels zone %ld " "not supported. Choose one of 1, 2, 4, 6, " "or 7.\n", val); goto exit; @@ -1257,12 +1307,10 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix, dme1737_read(client, DME1737_REG_PWM_RR(0))); - } else { data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix, dme1737_read(client, DME1737_REG_PWM_RR(0))); - } dme1737_write(client, DME1737_REG_PWM_RR(0), data->pwm_rr[0]); @@ -1274,7 +1322,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, data->pwm_min[ix]); break; default: - dev_dbg(dev, "Unknown attr fetch (%d)\n", fn); + dev_dbg(dev, "Unknown function %d.\n", fn); } exit: mutex_unlock(&data->update_lock); @@ -1298,8 +1346,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); long val = simple_strtol(buf, NULL, 10); data->vrm = val; @@ -1314,6 +1361,14 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } +static ssize_t show_name(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", data->client.name); +} + /* --------------------------------------------------------------------- * Sysfs device attribute defines and structs * --------------------------------------------------------------------- */ @@ -1322,13 +1377,13 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, #define SENSOR_DEVICE_ATTR_IN(ix) \ static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \ - show_in, NULL, SYS_IN_INPUT, ix); \ + show_in, NULL, SYS_IN_INPUT, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \ - show_in, set_in, SYS_IN_MIN, ix); \ + show_in, set_in, SYS_IN_MIN, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \ - show_in, set_in, SYS_IN_MAX, ix); \ + show_in, set_in, SYS_IN_MAX, ix); \ static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \ - show_in, NULL, SYS_IN_ALARM, ix) + show_in, NULL, SYS_IN_ALARM, ix) SENSOR_DEVICE_ATTR_IN(0); SENSOR_DEVICE_ATTR_IN(1); @@ -1342,17 +1397,17 @@ SENSOR_DEVICE_ATTR_IN(6); #define SENSOR_DEVICE_ATTR_TEMP(ix) \ static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_INPUT, ix-1); \ + show_temp, NULL, SYS_TEMP_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SYS_TEMP_MIN, ix-1); \ + show_temp, set_temp, SYS_TEMP_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \ - show_temp, set_temp, SYS_TEMP_MAX, ix-1); \ + show_temp, set_temp, SYS_TEMP_MAX, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \ - show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \ + show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_ALARM, ix-1); \ + show_temp, NULL, SYS_TEMP_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \ - show_temp, NULL, SYS_TEMP_FAULT, ix-1) + show_temp, NULL, SYS_TEMP_FAULT, ix-1) SENSOR_DEVICE_ATTR_TEMP(1); SENSOR_DEVICE_ATTR_TEMP(2); @@ -1362,15 +1417,15 @@ SENSOR_DEVICE_ATTR_TEMP(3); #define SENSOR_DEVICE_ATTR_ZONE(ix) \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \ - show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \ + show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \ + show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \ static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \ - show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1) + show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1) SENSOR_DEVICE_ATTR_ZONE(1); SENSOR_DEVICE_ATTR_ZONE(2); @@ -1380,13 +1435,13 @@ SENSOR_DEVICE_ATTR_ZONE(3); #define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \ static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ - show_fan, NULL, SYS_FAN_INPUT, ix-1); \ + show_fan, NULL, SYS_FAN_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MIN, ix-1); \ + show_fan, set_fan, SYS_FAN_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ - show_fan, NULL, SYS_FAN_ALARM, ix-1); \ + show_fan, NULL, SYS_FAN_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_TYPE, ix-1) + show_fan, set_fan, SYS_FAN_TYPE, ix-1) SENSOR_DEVICE_ATTR_FAN_1TO4(1); SENSOR_DEVICE_ATTR_FAN_1TO4(2); @@ -1397,13 +1452,13 @@ SENSOR_DEVICE_ATTR_FAN_1TO4(4); #define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \ static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \ - show_fan, NULL, SYS_FAN_INPUT, ix-1); \ + show_fan, NULL, SYS_FAN_INPUT, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MIN, ix-1); \ + show_fan, set_fan, SYS_FAN_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \ - show_fan, NULL, SYS_FAN_ALARM, ix-1); \ + show_fan, NULL, SYS_FAN_ALARM, ix-1); \ static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \ - show_fan, set_fan, SYS_FAN_MAX, ix-1) + show_fan, set_fan, SYS_FAN_MAX, ix-1) SENSOR_DEVICE_ATTR_FAN_5TO6(5); SENSOR_DEVICE_ATTR_FAN_5TO6(6); @@ -1412,21 +1467,21 @@ SENSOR_DEVICE_ATTR_FAN_5TO6(6); #define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \ static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ + show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \ - show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \ - show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1) + show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1) SENSOR_DEVICE_ATTR_PWM_1TO3(1); SENSOR_DEVICE_ATTR_PWM_1TO3(2); @@ -1436,11 +1491,11 @@ SENSOR_DEVICE_ATTR_PWM_1TO3(3); #define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \ static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, SYS_PWM, ix-1); \ + show_pwm, set_pwm, SYS_PWM, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ + show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \ static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \ - show_pwm, NULL, SYS_PWM_ENABLE, ix-1) + show_pwm, NULL, SYS_PWM_ENABLE, ix-1) SENSOR_DEVICE_ATTR_PWM_5TO6(5); SENSOR_DEVICE_ATTR_PWM_5TO6(6); @@ -1449,6 +1504,7 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6); static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ #define SENSOR_DEV_ATTR_IN(ix) \ &sensor_dev_attr_in##ix##_input.dev_attr.attr, \ @@ -1519,53 +1575,53 @@ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \ * permissions are created read-only and write permissions are added or removed * on the fly when required */ static struct attribute *dme1737_attr[] ={ - /* Voltages */ - SENSOR_DEV_ATTR_IN(0), - SENSOR_DEV_ATTR_IN(1), - SENSOR_DEV_ATTR_IN(2), - SENSOR_DEV_ATTR_IN(3), - SENSOR_DEV_ATTR_IN(4), - SENSOR_DEV_ATTR_IN(5), - SENSOR_DEV_ATTR_IN(6), - /* Temperatures */ - SENSOR_DEV_ATTR_TEMP(1), - SENSOR_DEV_ATTR_TEMP(2), - SENSOR_DEV_ATTR_TEMP(3), - /* Zones */ - SENSOR_DEV_ATTR_ZONE(1), - SENSOR_DEV_ATTR_ZONE(2), - SENSOR_DEV_ATTR_ZONE(3), - /* Misc */ - &dev_attr_vrm.attr, - &dev_attr_cpu0_vid.attr, + /* Voltages */ + SENSOR_DEV_ATTR_IN(0), + SENSOR_DEV_ATTR_IN(1), + SENSOR_DEV_ATTR_IN(2), + SENSOR_DEV_ATTR_IN(3), + SENSOR_DEV_ATTR_IN(4), + SENSOR_DEV_ATTR_IN(5), + SENSOR_DEV_ATTR_IN(6), + /* Temperatures */ + SENSOR_DEV_ATTR_TEMP(1), + SENSOR_DEV_ATTR_TEMP(2), + SENSOR_DEV_ATTR_TEMP(3), + /* Zones */ + SENSOR_DEV_ATTR_ZONE(1), + SENSOR_DEV_ATTR_ZONE(2), + SENSOR_DEV_ATTR_ZONE(3), + /* Misc */ + &dev_attr_vrm.attr, + &dev_attr_cpu0_vid.attr, NULL }; static const struct attribute_group dme1737_group = { - .attrs = dme1737_attr, + .attrs = dme1737_attr, }; /* The following structs hold the PWM attributes, some of which are optional. * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_pwm1[] = { - SENSOR_DEV_ATTR_PWM_1TO3(1), + SENSOR_DEV_ATTR_PWM_1TO3(1), NULL }; static struct attribute *dme1737_attr_pwm2[] = { - SENSOR_DEV_ATTR_PWM_1TO3(2), + SENSOR_DEV_ATTR_PWM_1TO3(2), NULL }; static struct attribute *dme1737_attr_pwm3[] = { - SENSOR_DEV_ATTR_PWM_1TO3(3), + SENSOR_DEV_ATTR_PWM_1TO3(3), NULL }; static struct attribute *dme1737_attr_pwm5[] = { - SENSOR_DEV_ATTR_PWM_5TO6(5), + SENSOR_DEV_ATTR_PWM_5TO6(5), NULL }; static struct attribute *dme1737_attr_pwm6[] = { - SENSOR_DEV_ATTR_PWM_5TO6(6), + SENSOR_DEV_ATTR_PWM_5TO6(6), NULL }; @@ -1582,27 +1638,27 @@ static const struct attribute_group dme1737_pwm_group[] = { * Their creation depends on the chip configuration which is determined during * module load. */ static struct attribute *dme1737_attr_fan1[] = { - SENSOR_DEV_ATTR_FAN_1TO4(1), + SENSOR_DEV_ATTR_FAN_1TO4(1), NULL }; static struct attribute *dme1737_attr_fan2[] = { - SENSOR_DEV_ATTR_FAN_1TO4(2), + SENSOR_DEV_ATTR_FAN_1TO4(2), NULL }; static struct attribute *dme1737_attr_fan3[] = { - SENSOR_DEV_ATTR_FAN_1TO4(3), + SENSOR_DEV_ATTR_FAN_1TO4(3), NULL }; static struct attribute *dme1737_attr_fan4[] = { - SENSOR_DEV_ATTR_FAN_1TO4(4), + SENSOR_DEV_ATTR_FAN_1TO4(4), NULL }; static struct attribute *dme1737_attr_fan5[] = { - SENSOR_DEV_ATTR_FAN_5TO6(5), + SENSOR_DEV_ATTR_FAN_5TO6(5), NULL }; static struct attribute *dme1737_attr_fan6[] = { - SENSOR_DEV_ATTR_FAN_5TO6(6), + SENSOR_DEV_ATTR_FAN_5TO6(6), NULL }; @@ -1637,23 +1693,23 @@ static const struct attribute_group dme1737_lock_group = { * writeable if the chip is *not* locked and the respective PWM is available. * Otherwise they stay read-only. */ static struct attribute *dme1737_attr_pwm1_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1), NULL }; static struct attribute *dme1737_attr_pwm2_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2), NULL }; static struct attribute *dme1737_attr_pwm3_lock[] = { - SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3), + SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3), NULL }; static struct attribute *dme1737_attr_pwm5_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5), + SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5), NULL }; static struct attribute *dme1737_attr_pwm6_lock[] = { - SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6), + SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6), NULL }; @@ -1678,6 +1734,16 @@ static struct attribute *dme1737_attr_pwm[] = { * Super-IO functions * --------------------------------------------------------------------- */ +static inline void dme1737_sio_enter(int sio_cip) +{ + outb(0x55, sio_cip); +} + +static inline void dme1737_sio_exit(int sio_cip) +{ + outb(0xaa, sio_cip); +} + static inline int dme1737_sio_inb(int sio_cip, int reg) { outb(reg, sio_cip); @@ -1690,136 +1756,196 @@ static inline void dme1737_sio_outb(int sio_cip, int reg, int val) outb(val, sio_cip + 1); } -static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client) +/* --------------------------------------------------------------------- + * Device initialization + * --------------------------------------------------------------------- */ + +static int dme1737_i2c_get_features(int, struct dme1737_data*); + +static void dme1737_chmod_file(struct device *dev, + struct attribute *attr, mode_t mode) { - struct dme1737_data *data = i2c_get_clientdata(client); - int err = 0, reg; - u16 addr; + if (sysfs_chmod_file(&dev->kobj, attr, mode)) { + dev_warn(dev, "Failed to change permissions of %s.\n", + attr->name); + } +} - /* Enter configuration mode */ - outb(0x55, sio_cip); +static void dme1737_chmod_group(struct device *dev, + const struct attribute_group *group, + mode_t mode) +{ + struct attribute **attr; - /* Check device ID - * The DME1737 can return either 0x78 or 0x77 as its device ID. */ - reg = dme1737_sio_inb(sio_cip, 0x20); - if (!(reg == 0x77 || reg == 0x78)) { - err = -ENODEV; - goto exit; + for (attr = group->attrs; *attr; attr++) { + dme1737_chmod_file(dev, *attr, mode); } +} - /* Select logical device A (runtime registers) */ - dme1737_sio_outb(sio_cip, 0x07, 0x0a); +static void dme1737_remove_files(struct device *dev) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + int ix; - /* Get the base address of the runtime registers */ - if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | - dme1737_sio_inb(sio_cip, 0x61))) { - err = -ENODEV; - goto exit; + for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { + if (data->has_fan & (1 << ix)) { + sysfs_remove_group(&dev->kobj, + &dme1737_fan_group[ix]); + } } - /* Read the runtime registers to determine which optional features - * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set - * to '10' if the respective feature is enabled. */ - if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ - data->has_fan |= (1 << 5); + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { + if (data->has_pwm & (1 << ix)) { + sysfs_remove_group(&dev->kobj, + &dme1737_pwm_group[ix]); + } } - if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ - data->has_pwm |= (1 << 5); + + sysfs_remove_group(&dev->kobj, &dme1737_group); + + if (!data->client.driver) { + sysfs_remove_file(&dev->kobj, &dev_attr_name.attr); } - if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ - data->has_fan |= (1 << 4); +} + +static int dme1737_create_files(struct device *dev) +{ + struct dme1737_data *data = dev_get_drvdata(dev); + int err, ix; + + /* Create a name attribute for ISA devices */ + if (!data->client.driver && + (err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) { + goto exit; } - if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ - data->has_pwm |= (1 << 4); + + /* Create standard sysfs attributes */ + if ((err = sysfs_create_group(&dev->kobj, &dme1737_group))) { + goto exit_remove; } -exit: - /* Exit configuration mode */ - outb(0xaa, sio_cip); + /* Create fan sysfs attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { + if (data->has_fan & (1 << ix)) { + if ((err = sysfs_create_group(&dev->kobj, + &dme1737_fan_group[ix]))) { + goto exit_remove; + } + } + } - return err; -} + /* Create PWM sysfs attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { + if (data->has_pwm & (1 << ix)) { + if ((err = sysfs_create_group(&dev->kobj, + &dme1737_pwm_group[ix]))) { + goto exit_remove; + } + } + } -/* --------------------------------------------------------------------- - * Device detection, registration and initialization - * --------------------------------------------------------------------- */ + /* Inform if the device is locked. Otherwise change the permissions of + * selected attributes from read-only to read-writeable. */ + if (data->config & 0x02) { + dev_info(dev, "Device is locked. Some attributes " + "will be read-only.\n"); + } else { + /* Change permissions of standard attributes */ + dme1737_chmod_group(dev, &dme1737_lock_group, + S_IRUGO | S_IWUSR); -static struct i2c_driver dme1737_driver; + /* Change permissions of PWM attributes */ + for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { + if (data->has_pwm & (1 << ix)) { + dme1737_chmod_group(dev, + &dme1737_pwm_lock_group[ix], + S_IRUGO | S_IWUSR); + } + } -static void dme1737_chmod_file(struct i2c_client *client, - struct attribute *attr, mode_t mode) -{ - if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) { - dev_warn(&client->dev, "Failed to change permissions of %s.\n", - attr->name); + /* Change permissions of pwm[1-3] if in manual mode */ + for (ix = 0; ix < 3; ix++) { + if ((data->has_pwm & (1 << ix)) && + (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { + dme1737_chmod_file(dev, + dme1737_attr_pwm[ix], + S_IRUGO | S_IWUSR); + } + } } -} -static void dme1737_chmod_group(struct i2c_client *client, - const struct attribute_group *group, - mode_t mode) -{ - struct attribute **attr; + return 0; - for (attr = group->attrs; *attr; attr++) { - dme1737_chmod_file(client, *attr, mode); - } +exit_remove: + dme1737_remove_files(dev); +exit: + return err; } -static int dme1737_init_client(struct i2c_client *client) +static int dme1737_init_device(struct device *dev) { - struct dme1737_data *data = i2c_get_clientdata(client); + struct dme1737_data *data = dev_get_drvdata(dev); + struct i2c_client *client = &data->client; int ix; u8 reg; - data->config = dme1737_read(client, DME1737_REG_CONFIG); - /* Inform if part is not monitoring/started */ - if (!(data->config & 0x01)) { - if (!force_start) { - dev_err(&client->dev, "Device is not monitoring. " - "Use the force_start load parameter to " - "override.\n"); - return -EFAULT; - } - - /* Force monitoring */ - data->config |= 0x01; - dme1737_write(client, DME1737_REG_CONFIG, data->config); - } + data->config = dme1737_read(client, DME1737_REG_CONFIG); + /* Inform if part is not monitoring/started */ + if (!(data->config & 0x01)) { + if (!force_start) { + dev_err(dev, "Device is not monitoring. " + "Use the force_start load parameter to " + "override.\n"); + return -EFAULT; + } + + /* Force monitoring */ + data->config |= 0x01; + dme1737_write(client, DME1737_REG_CONFIG, data->config); + } /* Inform if part is not ready */ if (!(data->config & 0x04)) { - dev_err(&client->dev, "Device is not ready.\n"); + dev_err(dev, "Device is not ready.\n"); return -EFAULT; } - data->config2 = dme1737_read(client, DME1737_REG_CONFIG2); - /* Check if optional fan3 input is enabled */ - if (data->config2 & 0x04) { - data->has_fan |= (1 << 2); - } + /* Determine which optional fan and pwm features are enabled/present */ + if (client->driver) { /* I2C chip */ + data->config2 = dme1737_read(client, DME1737_REG_CONFIG2); + /* Check if optional fan3 input is enabled */ + if (data->config2 & 0x04) { + data->has_fan |= (1 << 2); + } - /* Fan4 and pwm3 are only available if the client's I2C address - * is the default 0x2e. Otherwise the I/Os associated with these - * functions are used for addr enable/select. */ - if (client->addr == 0x2e) { - data->has_fan |= (1 << 3); - data->has_pwm |= (1 << 2); - } + /* Fan4 and pwm3 are only available if the client's I2C address + * is the default 0x2e. Otherwise the I/Os associated with + * these functions are used for addr enable/select. */ + if (data->client.addr == 0x2e) { + data->has_fan |= (1 << 3); + data->has_pwm |= (1 << 2); + } - /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled. - * For this, we need to query the runtime registers through the - * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */ - if (dme1737_sio_get_features(0x2e, client) && - dme1737_sio_get_features(0x4e, client)) { - dev_warn(&client->dev, "Failed to query Super-IO for optional " - "features.\n"); + /* Determine which of the optional fan[5-6] and pwm[5-6] + * features are enabled. For this, we need to query the runtime + * registers through the Super-IO LPC interface. Try both + * config ports 0x2e and 0x4e. */ + if (dme1737_i2c_get_features(0x2e, data) && + dme1737_i2c_get_features(0x4e, data)) { + dev_warn(dev, "Failed to query Super-IO for optional " + "features.\n"); + } + } else { /* ISA chip */ + /* Fan3 and pwm3 are always available. Fan[4-5] and pwm[5-6] + * don't exist in the ISA chip. */ + data->has_fan |= (1 << 2); + data->has_pwm |= (1 << 2); } /* Fan1, fan2, pwm1, and pwm2 are always present */ data->has_fan |= 0x03; data->has_pwm |= 0x03; - dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " + dev_info(dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, " "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n", (data->has_pwm & (1 << 2)) ? "yes" : "no", (data->has_pwm & (1 << 4)) ? "yes" : "no", @@ -1831,13 +1957,19 @@ static int dme1737_init_client(struct i2c_client *client) reg = dme1737_read(client, DME1737_REG_TACH_PWM); /* Inform if fan-to-pwm mapping differs from the default */ - if (reg != 0xa4) { - dev_warn(&client->dev, "Non-standard fan to pwm mapping: " + if (client->driver && reg != 0xa4) { /* I2C chip */ + dev_warn(dev, "Non-standard fan to pwm mapping: " "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, " "fan4->pwm%d. Please report to the driver " "maintainer.\n", (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1); + } else if (!client->driver && reg != 0x24) { /* ISA chip */ + dev_warn(dev, "Non-standard fan to pwm mapping: " + "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. " + "Please report to the driver maintainer.\n", + (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1, + ((reg >> 4) & 0x03) + 1); } /* Switch pwm[1-3] to manual mode if they are currently disabled and @@ -1849,7 +1981,7 @@ static int dme1737_init_client(struct i2c_client *client) DME1737_REG_PWM_CONFIG(ix)); if ((data->has_pwm & (1 << ix)) && (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) { - dev_info(&client->dev, "Switching pwm%d to " + dev_info(dev, "Switching pwm%d to " "manual mode.\n", ix + 1); data->pwm_config[ix] = PWM_EN_TO_REG(1, data->pwm_config[ix]); @@ -1872,13 +2004,67 @@ static int dme1737_init_client(struct i2c_client *client) return 0; } -static int dme1737_detect(struct i2c_adapter *adapter, int address, - int kind) +/* --------------------------------------------------------------------- + * I2C device detection and registration + * --------------------------------------------------------------------- */ + +static struct i2c_driver dme1737_i2c_driver; + +static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data) +{ + int err = 0, reg; + u16 addr; + + dme1737_sio_enter(sio_cip); + + /* Check device ID + * The DME1737 can return either 0x78 or 0x77 as its device ID. */ + reg = dme1737_sio_inb(sio_cip, 0x20); + if (!(reg == 0x77 || reg == 0x78)) { + err = -ENODEV; + goto exit; + } + + /* Select logical device A (runtime registers) */ + dme1737_sio_outb(sio_cip, 0x07, 0x0a); + + /* Get the base address of the runtime registers */ + if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61))) { + err = -ENODEV; + goto exit; + } + + /* Read the runtime registers to determine which optional features + * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set + * to '10' if the respective feature is enabled. */ + if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */ + data->has_fan |= (1 << 5); + } + if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */ + data->has_pwm |= (1 << 5); + } + if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */ + data->has_fan |= (1 << 4); + } + if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */ + data->has_pwm |= (1 << 4); + } + +exit: + dme1737_sio_exit(sio_cip); + + return err; +} + +static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address, + int kind) { u8 company, verstep = 0; struct i2c_client *client; struct dme1737_data *data; - int ix, err = 0; + struct device *dev; + int err = 0; const char *name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { @@ -1894,7 +2080,8 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address, i2c_set_clientdata(client, data); client->addr = address; client->adapter = adapter; - client->driver = &dme1737_driver; + client->driver = &dme1737_i2c_driver; + dev = &client->dev; /* A negative kind means that the driver was loaded with no force * parameter (default), so we must identify the chip. */ @@ -1922,92 +2109,33 @@ static int dme1737_detect(struct i2c_adapter *adapter, int address, goto exit_kfree; } + dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n", + client->addr, verstep); + /* Initialize the DME1737 chip */ - if ((err = dme1737_init_client(client))) { + if ((err = dme1737_init_device(dev))) { + dev_err(dev, "Failed to initialize device.\n"); goto exit_detach; } - /* Create standard sysfs attributes */ - if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) { - goto exit_detach; - } - - /* Create fan sysfs attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &dme1737_fan_group[ix]))) { - goto exit_remove; - } - } - } - - /* Create PWM sysfs attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - if ((err = sysfs_create_group(&client->dev.kobj, - &dme1737_pwm_group[ix]))) { - goto exit_remove; - } - } - } - - /* Inform if the device is locked. Otherwise change the permissions of - * selected attributes from read-only to read-writeable. */ - if (data->config & 0x02) { - dev_info(&client->dev, "Device is locked. Some attributes " - "will be read-only.\n"); - } else { - /* Change permissions of standard attributes */ - dme1737_chmod_group(client, &dme1737_lock_group, - S_IRUGO | S_IWUSR); - - /* Change permissions of PWM attributes */ - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) { - if (data->has_pwm & (1 << ix)) { - dme1737_chmod_group(client, - &dme1737_pwm_lock_group[ix], - S_IRUGO | S_IWUSR); - } - } - - /* Change permissions of pwm[1-3] if in manual mode */ - for (ix = 0; ix < 3; ix++) { - if ((data->has_pwm & (1 << ix)) && - (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) { - dme1737_chmod_file(client, - dme1737_attr_pwm[ix], - S_IRUGO | S_IWUSR); - } - } + /* Create sysfs files */ + if ((err = dme1737_create_files(dev))) { + dev_err(dev, "Failed to create sysfs files.\n"); + goto exit_detach; } /* Register device */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register device.\n"); + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } - dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x " - "(rev 0x%02x)\n", client->addr, verstep); - return 0; exit_remove: - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_fan_group[ix]); - } - } - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_pwm_group[ix]); - } - } - sysfs_remove_group(&client->dev.kobj, &dme1737_group); + dme1737_remove_files(dev); exit_detach: i2c_detach_client(client); exit_kfree: @@ -2016,60 +2144,260 @@ exit: return err; } -static int dme1737_attach_adapter(struct i2c_adapter *adapter) +static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter) { if (!(adapter->class & I2C_CLASS_HWMON)) { return 0; } - return i2c_probe(adapter, &addr_data, dme1737_detect); + return i2c_probe(adapter, &addr_data, dme1737_i2c_detect); } -static int dme1737_detach_client(struct i2c_client *client) +static int dme1737_i2c_detach_client(struct i2c_client *client) { struct dme1737_data *data = i2c_get_clientdata(client); - int ix, err; + int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); + dme1737_remove_files(&client->dev); - for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) { - if (data->has_fan & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_fan_group[ix]); - } + if ((err = i2c_detach_client(client))) { + return err; } - for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) { - if (data->has_pwm & (1 << ix)) { - sysfs_remove_group(&client->dev.kobj, - &dme1737_pwm_group[ix]); - } + + kfree(data); + return 0; +} + +static struct i2c_driver dme1737_i2c_driver = { + .driver = { + .name = "dme1737", + }, + .attach_adapter = dme1737_i2c_attach_adapter, + .detach_client = dme1737_i2c_detach_client, +}; + +/* --------------------------------------------------------------------- + * ISA device detection and registration + * --------------------------------------------------------------------- */ + +static int __init dme1737_isa_detect(int sio_cip, unsigned short *addr) +{ + int err = 0, reg; + unsigned short base_addr; + + dme1737_sio_enter(sio_cip); + + /* Check device ID + * We currently know about SCH3112 (0x7c), SCH3114 (0x7d), and + * SCH3116 (0x7f). */ + reg = dme1737_sio_inb(sio_cip, 0x20); + if (!(reg == 0x7c || reg == 0x7d || reg == 0x7f)) { + err = -ENODEV; + goto exit; } - sysfs_remove_group(&client->dev.kobj, &dme1737_group); - if ((err = i2c_detach_client(client))) { - return err; + /* Select logical device A (runtime registers) */ + dme1737_sio_outb(sio_cip, 0x07, 0x0a); + + /* Get the base address of the runtime registers */ + if (!(base_addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) | + dme1737_sio_inb(sio_cip, 0x61))) { + printk(KERN_ERR "dme1737: Base address not set.\n"); + err = -ENODEV; + goto exit; + } + + /* Access to the hwmon registers is through an index/data register + * pair located at offset 0x70/0x71. */ + *addr = base_addr + 0x70; + +exit: + dme1737_sio_exit(sio_cip); + return err; +} + +static int __init dme1737_isa_device_add(unsigned short addr) +{ + struct resource res = { + .start = addr, + .end = addr + DME1737_EXTENT - 1, + .name = "dme1737", + .flags = IORESOURCE_IO, + }; + int err; + + if (!(pdev = platform_device_alloc("dme1737", addr))) { + printk(KERN_ERR "dme1737: Failed to allocate device.\n"); + err = -ENOMEM; + goto exit; + } + + if ((err = platform_device_add_resources(pdev, &res, 1))) { + printk(KERN_ERR "dme1737: Failed to add device resource " + "(err = %d).\n", err); + goto exit_device_put; + } + + if ((err = platform_device_add(pdev))) { + printk(KERN_ERR "dme1737: Failed to add device (err = %d).\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); + pdev = NULL; +exit: + return err; +} + +static int __devinit dme1737_isa_probe(struct platform_device *pdev) +{ + u8 company, device; + struct resource *res; + struct i2c_client *client; + struct dme1737_data *data; + struct device *dev = &pdev->dev; + int err; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, DME1737_EXTENT, "dme1737")) { + dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n", + (unsigned short)res->start, + (unsigned short)res->start + DME1737_EXTENT - 1); + err = -EBUSY; + goto exit; + } + + if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit_release_region; + } + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = res->start; + platform_set_drvdata(pdev, data); + + company = dme1737_read(client, DME1737_REG_COMPANY); + device = dme1737_read(client, DME1737_REG_DEVICE); + + if (!((company == DME1737_COMPANY_SMSC) && + (device == SCH311X_DEVICE))) { + err = -ENODEV; + goto exit_kfree; + } + + /* Fill in the remaining client fields and initialize the mutex */ + strlcpy(client->name, "sch311x", I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr); + + /* Initialize the chip */ + if ((err = dme1737_init_device(dev))) { + dev_err(dev, "Failed to initialize device.\n"); + goto exit_kfree; } + /* Create sysfs files */ + if ((err = dme1737_create_files(dev))) { + dev_err(dev, "Failed to create sysfs files.\n"); + goto exit_kfree; + } + + /* Register device */ + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + dev_err(dev, "Failed to register device.\n"); + err = PTR_ERR(data->hwmon_dev); + goto exit_remove_files; + } + + return 0; + +exit_remove_files: + dme1737_remove_files(dev); +exit_kfree: + platform_set_drvdata(pdev, NULL); + kfree(data); +exit_release_region: + release_region(res->start, DME1737_EXTENT); +exit: + return err; +} + +static int __devexit dme1737_isa_remove(struct platform_device *pdev) +{ + struct dme1737_data *data = platform_get_drvdata(pdev); + + hwmon_device_unregister(data->hwmon_dev); + dme1737_remove_files(&pdev->dev); + release_region(data->client.addr, DME1737_EXTENT); + platform_set_drvdata(pdev, NULL); kfree(data); + return 0; } -static struct i2c_driver dme1737_driver = { +static struct platform_driver dme1737_isa_driver = { .driver = { + .owner = THIS_MODULE, .name = "dme1737", }, - .attach_adapter = dme1737_attach_adapter, - .detach_client = dme1737_detach_client, + .probe = dme1737_isa_probe, + .remove = __devexit_p(dme1737_isa_remove), }; +/* --------------------------------------------------------------------- + * Module initialization and cleanup + * --------------------------------------------------------------------- */ + static int __init dme1737_init(void) { - return i2c_add_driver(&dme1737_driver); + int err; + unsigned short addr; + + if ((err = i2c_add_driver(&dme1737_i2c_driver))) { + goto exit; + } + + if (dme1737_isa_detect(0x2e, &addr) && + dme1737_isa_detect(0x4e, &addr)) { + /* Return 0 if we didn't find an ISA device */ + return 0; + } + + if ((err = platform_driver_register(&dme1737_isa_driver))) { + goto exit_del_i2c_driver; + } + + /* Sets global pdev as a side effect */ + if ((err = dme1737_isa_device_add(addr))) { + goto exit_del_isa_driver; + } + + return 0; + +exit_del_isa_driver: + platform_driver_unregister(&dme1737_isa_driver); +exit_del_i2c_driver: + i2c_del_driver(&dme1737_i2c_driver); +exit: + return err; } static void __exit dme1737_exit(void) { - i2c_del_driver(&dme1737_driver); + if (pdev) { + platform_device_unregister(pdev); + platform_driver_unregister(&dme1737_isa_driver); + } + + i2c_del_driver(&dme1737_i2c_driver); } MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>"); diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 1212d6b7f31..b7bd000b130 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -73,7 +73,7 @@ static const u8 DS1621_REG_TEMP[3] = { /* Each client has this additional data */ struct ds1621_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -151,7 +151,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); struct ds1621_data *data = ds1621_update_client(dev); - u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); + u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); mutex_lock(&data->update_lock); data->temp[attr->index] = val; @@ -266,9 +266,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address, if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -289,7 +289,7 @@ static int ds1621_detach_client(struct i2c_client *client) struct ds1621_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ds1621_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 6f60715f34f..5d9d5cc816a 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -10,6 +10,9 @@ * The F71872F/FG is almost the same, with two more voltages monitored, * and 6 VID inputs. * + * The F71806F/FG is essentially the same as the F71872F/FG. It even has + * the same chip ID, so the driver can't differentiate between. + * * 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 @@ -159,7 +162,7 @@ struct f71805f_auto_point { struct f71805f_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -1378,9 +1381,9 @@ static int __devinit f71805f_probe(struct platform_device *pdev) } } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_remove_files; } @@ -1407,7 +1410,7 @@ static int __devexit f71805f_remove(struct platform_device *pdev) struct resource *res; int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); for (i = 0; i < 4; i++) sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); @@ -1485,7 +1488,7 @@ static int __init f71805f_find(int sioaddr, unsigned short *address, static const char *names[] = { "F71805F/FG", - "F71872F/FG", + "F71872F/FG or F71806F/FG", }; superio_enter(sioaddr); diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c new file mode 100644 index 00000000000..6db74434a02 --- /dev/null +++ b/drivers/hwmon/f71882fg.c @@ -0,0 +1,950 @@ +/*************************************************************************** + * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * + * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> * + * * + * 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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/err.h> +#include <linux/mutex.h> +#include <asm/io.h> + +#define DRVNAME "f71882fg" + +#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/ +#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ +#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ + +#define SIO_REG_LDSEL 0x07 /* Logical device select */ +#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ +#define SIO_REG_DEVREV 0x22 /* Device revision */ +#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ +#define SIO_REG_ENABLE 0x30 /* Logical device enable */ +#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ + +#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ +#define SIO_F71882_ID 0x0541 /* Chipset ID */ + +#define REGION_LENGTH 8 +#define ADDR_REG_OFFSET 5 +#define DATA_REG_OFFSET 6 + +#define F71882FG_REG_PECI 0x0A + +#define F71882FG_REG_IN_STATUS 0x12 +#define F71882FG_REG_IN_BEEP 0x13 +#define F71882FG_REG_IN(nr) (0x20 + (nr)) +#define F71882FG_REG_IN1_HIGH 0x32 + +#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr))) +#define F71882FG_REG_FAN_STATUS 0x92 +#define F71882FG_REG_FAN_BEEP 0x93 + +#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr)) +#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr)) +#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr)) +#define F71882FG_REG_TEMP_STATUS 0x62 +#define F71882FG_REG_TEMP_BEEP 0x63 +#define F71882FG_REG_TEMP_HYST1 0x6C +#define F71882FG_REG_TEMP_HYST23 0x6D +#define F71882FG_REG_TEMP_TYPE 0x6B +#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F + +#define F71882FG_REG_START 0x01 + +#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */ + +static struct platform_device *f71882fg_pdev = NULL; + +/* Super-I/O Function prototypes */ +static inline int superio_inb(int base, int reg); +static inline int superio_inw(int base, int reg); +static inline void superio_enter(int base); +static inline void superio_select(int base, int ld); +static inline void superio_exit(int base); + +static inline u16 fan_from_reg ( u16 reg ); + +struct f71882fg_data { + unsigned short addr; + struct device *hwmon_dev; + + struct mutex update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ + + /* Register Values */ + u8 in[9]; + u8 in1_max; + u8 in_status; + u8 in_beep; + u16 fan[4]; + u8 fan_status; + u8 fan_beep; + u8 temp[3]; + u8 temp_ovt[3]; + u8 temp_high[3]; + u8 temp_hyst[3]; + u8 temp_type[3]; + u8 temp_status; + u8 temp_beep; + u8 temp_diode_open; +}; + +static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg); +static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg); +static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val); + +/* Sysfs in*/ +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf); +static ssize_t show_in_max(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_in_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_in_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_in_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_in_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs Fan */ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf); +static ssize_t show_fan_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_fan_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_fan_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs Temp */ +static ssize_t show_temp(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_max(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_crit(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_type(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_beep(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t store_temp_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count); +static ssize_t show_temp_alarm(struct device *dev, struct device_attribute + *devattr, char *buf); +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf); +/* Sysfs misc */ +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf); + +static int __devinit f71882fg_probe(struct platform_device * pdev); +static int __devexit f71882fg_remove(struct platform_device *pdev); +static int __init f71882fg_init(void); +static int __init f71882fg_find(int sioaddr, unsigned short *address); +static int __init f71882fg_device_add(unsigned short address); +static void __exit f71882fg_exit(void); + +static struct platform_driver f71882fg_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = f71882fg_probe, + .remove = __devexit_p(f71882fg_remove), +}; + +static struct device_attribute f71882fg_dev_attr[] = +{ + __ATTR( name, S_IRUGO, show_name, NULL ), +}; + +static struct sensor_device_attribute f71882fg_in_temp_attr[] = +{ + SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), + SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1), + SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1), + SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), + SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), + SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), + SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), + SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), + SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), + SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8), + SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0), + SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 0), + SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 0), + SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 0), + SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0), + SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), + SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 0), + SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0), + SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0), + SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1), + SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 1), + SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 1), + SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 1), + SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1), + SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), + SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 1), + SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1), + SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1), + SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2), + SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, + store_temp_max, 2), + SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, + store_temp_max_hyst, 2), + SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, + store_temp_crit, 2), + SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2), + SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), + SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep, + store_temp_beep, 2), + SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2), + SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2) +}; + +static struct sensor_device_attribute f71882fg_fan_attr[] = +{ + SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), + SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 0), + SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0), + SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), + SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 1), + SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1), + SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2), + SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 2), + SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2), + SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3), + SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, + store_fan_beep, 3), + SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3) +}; + + +/* Super I/O functions */ +static inline int superio_inb(int base, int reg) +{ + outb(reg, base); + return inb(base + 1); +} + +static int superio_inw(int base, int reg) +{ + int val; + outb(reg++, base); + val = inb(base + 1) << 8; + outb(reg, base); + val |= inb(base + 1); + return val; +} + +static inline void superio_enter(int base) +{ + /* according to the datasheet the key must be send twice! */ + outb( SIO_UNLOCK_KEY, base); + outb( SIO_UNLOCK_KEY, base); +} + +static inline void superio_select( int base, int ld) +{ + outb(SIO_REG_LDSEL, base); + outb(ld, base + 1); +} + +static inline void superio_exit(int base) +{ + outb(SIO_LOCK_KEY, base); +} + +static inline u16 fan_from_reg(u16 reg) +{ + return reg ? (1500000 / reg) : 0; +} + +static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg) +{ + u8 val; + + outb(reg, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET); + + return val; +} + +static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg) +{ + u16 val; + + outb(reg++, data->addr + ADDR_REG_OFFSET); + val = inb(data->addr + DATA_REG_OFFSET) << 8; + outb(reg, data->addr + ADDR_REG_OFFSET); + val |= inb(data->addr + DATA_REG_OFFSET); + + return val; +} + +static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val) +{ + outb(reg, data->addr + ADDR_REG_OFFSET); + outb(val, data->addr + DATA_REG_OFFSET); +} + +static struct f71882fg_data *f71882fg_update_device(struct device * dev) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr, reg, reg2; + + mutex_lock(&data->update_lock); + + /* Update once every 60 seconds */ + if ( time_after(jiffies, data->last_limits + 60 * HZ ) || + !data->valid) { + data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH); + data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP); + + /* Get High & boundary temps*/ + for (nr = 0; nr < 3; nr++) { + data->temp_ovt[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_OVT(nr)); + data->temp_high[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP_HIGH(nr)); + } + + /* Have to hardcode hyst*/ + data->temp_hyst[0] = f71882fg_read8(data, + F71882FG_REG_TEMP_HYST1) >> 4; + /* Hyst temps 2 & 3 stored in same register */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23); + data->temp_hyst[1] = reg & 0x0F; + data->temp_hyst[2] = reg >> 4; + + /* Have to hardcode type, because temp1 is special */ + reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); + reg2 = f71882fg_read8(data, F71882FG_REG_PECI); + if ((reg2 & 0x03) == 0x01) + data->temp_type[0] = 6 /* PECI */; + else if ((reg2 & 0x03) == 0x02) + data->temp_type[0] = 5 /* AMDSI */; + else + data->temp_type[0] = (reg & 0x02) ? 2 : 4; + + data->temp_type[1] = (reg & 0x04) ? 2 : 4; + data->temp_type[2] = (reg & 0x08) ? 2 : 4; + + data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP); + + data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP); + + data->last_limits = jiffies; + } + + /* Update every second */ + if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { + data->temp_status = f71882fg_read8(data, + F71882FG_REG_TEMP_STATUS); + data->temp_diode_open = f71882fg_read8(data, + F71882FG_REG_TEMP_DIODE_OPEN); + for (nr = 0; nr < 3; nr++) + data->temp[nr] = f71882fg_read8(data, + F71882FG_REG_TEMP(nr)); + + data->fan_status = f71882fg_read8(data, + F71882FG_REG_FAN_STATUS); + for (nr = 0; nr < 4; nr++) + data->fan[nr] = f71882fg_read16(data, + F71882FG_REG_FAN(nr)); + + data->in_status = f71882fg_read8(data, + F71882FG_REG_IN_STATUS); + for (nr = 0; nr < 9; nr++) + data->in[nr] = f71882fg_read8(data, + F71882FG_REG_IN(nr)); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +/* Sysfs Interface */ +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int speed = fan_from_reg(data->fan[nr]); + + if (speed == FAN_MIN_DETECT) + speed = 0; + + return sprintf(buf, "%d\n", speed); +} + +static ssize_t show_fan_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->fan_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_fan_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->fan_beep |= 1 << nr; + else + data->fan_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_fan_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->fan_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_in(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->in[nr] * 8); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + + return sprintf(buf, "%d\n", data->in1_max * 8); +} + +static ssize_t store_in_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int val = simple_strtoul(buf, NULL, 10) / 8; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val); + data->in1_max = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->in_beep & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_in_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->in_beep |= 1 << nr; + else + data->in_beep &= ~(1 << nr); + + f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_in_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->in_status & (1 << nr)) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp[nr] * 1000); +} + +static ssize_t show_temp_max(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_high[nr] * 1000); +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val); + data->temp_high[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", + (data->temp_high[nr] - data->temp_hyst[nr]) * 1000); +} + +static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + ssize_t ret = count; + + mutex_lock(&data->update_lock); + + /* convert abs to relative and check */ + val = data->temp_high[nr] - val; + if (val < 0 || val > 15) { + ret = -EINVAL; + goto store_temp_max_hyst_exit; + } + + data->temp_hyst[nr] = val; + + /* convert value to register contents */ + switch (nr) { + case 0: + val = val << 4; + break; + case 1: + val = val | (data->temp_hyst[2] << 4); + break; + case 2: + val = data->temp_hyst[1] | (val << 4); + break; + } + + f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 : + F71882FG_REG_TEMP_HYST1, val); + +store_temp_max_hyst_exit: + mutex_unlock(&data->update_lock); + return ret; +} + +static ssize_t show_temp_crit(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000); +} + +static ssize_t store_temp_crit(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10) / 1000; + + if (val > 255) + val = 255; + + mutex_lock(&data->update_lock); + f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val); + data->temp_ovt[nr] = val; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", + (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000); +} + +static ssize_t show_temp_type(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + return sprintf(buf, "%d\n", data->temp_type[nr]); +} + +static ssize_t show_temp_beep(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_beep & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_temp_beep(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + struct f71882fg_data *data = dev_get_drvdata(dev); + int nr = to_sensor_dev_attr(devattr)->index; + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + if (val) + data->temp_beep |= 1 << (nr + 1); + else + data->temp_beep &= ~(1 << (nr + 1)); + + f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_alarm(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_status & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_temp_fault(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct f71882fg_data *data = f71882fg_update_device(dev); + int nr = to_sensor_dev_attr(devattr)->index; + + if (data->temp_diode_open & (1 << (nr + 1))) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, DRVNAME "\n"); +} + + +static int __devinit f71882fg_probe(struct platform_device * pdev) +{ + struct f71882fg_data *data; + int err, i; + u8 start_reg; + + if (!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL))) + return -ENOMEM; + + data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; + mutex_init(&data->update_lock); + platform_set_drvdata(pdev, data); + + /* Register sysfs interface files */ + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) { + err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]); + if (err) + goto exit_unregister_sysfs; + } + + start_reg = f71882fg_read8(data, F71882FG_REG_START); + if (start_reg & 0x01) { + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) { + err = device_create_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + if (err) + goto exit_unregister_sysfs; + } + } + + if (start_reg & 0x02) { + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) { + err = device_create_file(&pdev->dev, + &f71882fg_fan_attr[i].dev_attr); + if (err) + goto exit_unregister_sysfs; + } + } + + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_unregister_sysfs; + } + + return 0; + +exit_unregister_sysfs: + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]); + + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) + device_remove_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr); + + kfree(data); + + return err; +} + +static int __devexit f71882fg_remove(struct platform_device *pdev) +{ + int i; + struct f71882fg_data *data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]); + + for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) + device_remove_file(&pdev->dev, + &f71882fg_in_temp_attr[i].dev_attr); + + for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) + device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr); + + kfree(data); + + return 0; +} + +static int __init f71882fg_find(int sioaddr, unsigned short *address) +{ + int err = -ENODEV; + u16 devid; + u8 start_reg; + struct f71882fg_data data; + + superio_enter(sioaddr); + + devid = superio_inw(sioaddr, SIO_REG_MANID); + if (devid != SIO_FINTEK_ID) { + printk(KERN_INFO DRVNAME ": Not a Fintek device\n"); + goto exit; + } + + devid = superio_inw(sioaddr, SIO_REG_DEVID); + if (devid != SIO_F71882_ID) { + printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n"); + goto exit; + } + + superio_select(sioaddr, SIO_F71882FG_LD_HWM); + if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { + printk(KERN_WARNING DRVNAME ": Device not activated\n"); + goto exit; + } + + *address = superio_inw(sioaddr, SIO_REG_ADDR); + if (*address == 0) + { + printk(KERN_WARNING DRVNAME ": Base address not set\n"); + goto exit; + } + *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */ + + data.addr = *address; + start_reg = f71882fg_read8(&data, F71882FG_REG_START); + if (!(start_reg & 0x03)) { + printk(KERN_WARNING DRVNAME + ": Hardware monitoring not activated\n"); + goto exit; + } + + err = 0; + printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n", + (unsigned int)*address, + (int)superio_inb(sioaddr, SIO_REG_DEVREV)); +exit: + superio_exit(sioaddr); + return err; +} + +static int __init f71882fg_device_add(unsigned short address) +{ + struct resource res = { + .start = address, + .end = address + REGION_LENGTH - 1, + .flags = IORESOURCE_IO, + }; + int err; + + f71882fg_pdev = platform_device_alloc(DRVNAME, address); + if (!f71882fg_pdev) + return -ENOMEM; + + res.name = f71882fg_pdev->name; + err = platform_device_add_resources(f71882fg_pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed\n"); + goto exit_device_put; + } + + err = platform_device_add(f71882fg_pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed\n"); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(f71882fg_pdev); + + return err; +} + +static int __init f71882fg_init(void) +{ + int err = -ENODEV; + unsigned short address; + + if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address)) + goto exit; + + if ((err = platform_driver_register(&f71882fg_driver))) + goto exit; + + if ((err = f71882fg_device_add(address))) + goto exit_driver; + + return 0; + +exit_driver: + platform_driver_unregister(&f71882fg_driver); +exit: + return err; +} + +static void __exit f71882fg_exit(void) +{ + platform_device_unregister(f71882fg_pdev); + platform_driver_unregister(&f71882fg_driver); +} + +MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver"); +MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)"); +MODULE_LICENSE("GPL"); + +module_init(f71882fg_init); +module_exit(f71882fg_exit); diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c new file mode 100644 index 00000000000..13a041326a0 --- /dev/null +++ b/drivers/hwmon/f75375s.c @@ -0,0 +1,691 @@ +/* + * f75375s.c - driver for the Fintek F75375/SP and F75373 + * hardware monitoring features + * Copyright (C) 2006-2007 Riku Voipio <riku.voipio@movial.fi> + * + * Datasheets available at: + * + * f75375: + * http://www.fintek.com.tw/files/productfiles/2005111152950.pdf + * + * f75373: + * http://www.fintek.com.tw/files/productfiles/2005111153128.pdf + * + * 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. + * + */ + +#include <linux/module.h> +#include <linux/jiffies.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/mutex.h> + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2d, 0x2e, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_2(f75373, f75375); + +/* Fintek F75375 registers */ +#define F75375_REG_CONFIG0 0x0 +#define F75375_REG_CONFIG1 0x1 +#define F75375_REG_CONFIG2 0x2 +#define F75375_REG_CONFIG3 0x3 +#define F75375_REG_ADDR 0x4 +#define F75375_REG_INTR 0x31 +#define F75375_CHIP_ID 0x5A +#define F75375_REG_VERSION 0x5C +#define F75375_REG_VENDOR 0x5D +#define F75375_REG_FAN_TIMER 0x60 + +#define F75375_REG_VOLT(nr) (0x10 + (nr)) +#define F75375_REG_VOLT_HIGH(nr) (0x20 + (nr) * 2) +#define F75375_REG_VOLT_LOW(nr) (0x21 + (nr) * 2) + +#define F75375_REG_TEMP(nr) (0x14 + (nr)) +#define F75375_REG_TEMP_HIGH(nr) (0x28 + (nr) * 2) +#define F75375_REG_TEMP_HYST(nr) (0x29 + (nr) * 2) + +#define F75375_REG_FAN(nr) (0x16 + (nr) * 2) +#define F75375_REG_FAN_MIN(nr) (0x2C + (nr) * 2) +#define F75375_REG_FAN_FULL(nr) (0x70 + (nr) * 0x10) +#define F75375_REG_FAN_PWM_DUTY(nr) (0x76 + (nr) * 0x10) +#define F75375_REG_FAN_PWM_CLOCK(nr) (0x7D + (nr) * 0x10) + +#define F75375_REG_FAN_EXP(nr) (0x74 + (nr) * 0x10) +#define F75375_REG_FAN_B_TEMP(nr, step) ((0xA0 + (nr) * 0x10) + (step)) +#define F75375_REG_FAN_B_SPEED(nr, step) \ + ((0xA5 + (nr) * 0x10) + (step) * 2) + +#define F75375_REG_PWM1_RAISE_DUTY 0x69 +#define F75375_REG_PWM2_RAISE_DUTY 0x6A +#define F75375_REG_PWM1_DROP_DUTY 0x6B +#define F75375_REG_PWM2_DROP_DUTY 0x6C + +#define FAN_CTRL_LINEAR(nr) (4 + nr) +#define FAN_CTRL_MODE(nr) (5 + ((nr) * 2)) + +/* + * Data structures and manipulation thereof + */ + +struct f75375_data { + unsigned short addr; + struct i2c_client client; + struct device *hwmon_dev; + + const char *name; + int kind; + struct mutex update_lock; /* protect register access */ + char valid; + unsigned long last_updated; /* In jiffies */ + unsigned long last_limits; /* In jiffies */ + + /* Register values */ + u8 in[4]; + u8 in_max[4]; + u8 in_min[4]; + u16 fan[2]; + u16 fan_min[2]; + u16 fan_full[2]; + u16 fan_exp[2]; + u8 fan_timer; + u8 pwm[2]; + u8 pwm_mode[2]; + u8 pwm_enable[2]; + s8 temp[2]; + s8 temp_high[2]; + s8 temp_max_hyst[2]; +}; + +static int f75375_attach_adapter(struct i2c_adapter *adapter); +static int f75375_detect(struct i2c_adapter *adapter, int address, int kind); +static int f75375_detach_client(struct i2c_client *client); + +static struct i2c_driver f75375_driver = { + .driver = { + .name = "f75375", + }, + .attach_adapter = f75375_attach_adapter, + .detach_client = f75375_detach_client, +}; + +static inline int f75375_read8(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +/* in most cases, should be called while holding update_lock */ +static inline u16 f75375_read16(struct i2c_client *client, u8 reg) +{ + return ((i2c_smbus_read_byte_data(client, reg) << 8) + | i2c_smbus_read_byte_data(client, reg + 1)); +} + +static inline void f75375_write8(struct i2c_client *client, u8 reg, + u8 value) +{ + i2c_smbus_write_byte_data(client, reg, value); +} + +static inline void f75375_write16(struct i2c_client *client, u8 reg, + u16 value) +{ + int err = i2c_smbus_write_byte_data(client, reg, (value << 8)); + if (err) + return; + i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); +} + +static struct f75375_data *f75375_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int nr; + + mutex_lock(&data->update_lock); + + /* Limit registers cache is refreshed after 60 seconds */ + if (time_after(jiffies, data->last_limits + 60 * HZ) + || !data->valid) { + for (nr = 0; nr < 2; nr++) { + data->temp_high[nr] = + f75375_read8(client, F75375_REG_TEMP_HIGH(nr)); + data->temp_max_hyst[nr] = + f75375_read8(client, F75375_REG_TEMP_HYST(nr)); + data->fan_full[nr] = + f75375_read16(client, F75375_REG_FAN_FULL(nr)); + data->fan_min[nr] = + f75375_read16(client, F75375_REG_FAN_MIN(nr)); + data->fan_exp[nr] = + f75375_read16(client, F75375_REG_FAN_EXP(nr)); + data->pwm[nr] = f75375_read8(client, + F75375_REG_FAN_PWM_DUTY(nr)); + + } + for (nr = 0; nr < 4; nr++) { + data->in_max[nr] = + f75375_read8(client, F75375_REG_VOLT_HIGH(nr)); + data->in_min[nr] = + f75375_read8(client, F75375_REG_VOLT_LOW(nr)); + } + data->fan_timer = f75375_read8(client, F75375_REG_FAN_TIMER); + data->last_limits = jiffies; + } + + /* Measurement registers cache is refreshed after 2 second */ + if (time_after(jiffies, data->last_updated + 2 * HZ) + || !data->valid) { + for (nr = 0; nr < 2; nr++) { + data->temp[nr] = + f75375_read8(client, F75375_REG_TEMP(nr)); + data->fan[nr] = + f75375_read16(client, F75375_REG_FAN(nr)); + } + for (nr = 0; nr < 4; nr++) + data->in[nr] = + f75375_read8(client, F75375_REG_VOLT(nr)); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + return data; +} + +static inline u16 rpm_from_reg(u16 reg) +{ + if (reg == 0 || reg == 0xffff) + return 0; + return (1500000 / reg); +} + +static inline u16 rpm_to_reg(int rpm) +{ + if (rpm < 367 || rpm > 0xffff) + return 0xffff; + return (1500000 / rpm); +} + +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_min[nr] = rpm_to_reg(val); + f75375_write16(client, F75375_REG_FAN_MIN(nr), data->fan_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_fan_exp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->fan_exp[nr] = rpm_to_reg(val); + f75375_write16(client, F75375_REG_FAN_EXP(nr), data->fan_exp[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->pwm[nr] = SENSORS_LIMIT(val, 0, 255); + f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), data->pwm[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_enable[nr]); +} + +static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 fanmode; + + if (val < 0 || val > 4) + return -EINVAL; + + mutex_lock(&data->update_lock); + fanmode = f75375_read8(client, F75375_REG_FAN_TIMER); + fanmode = ~(3 << FAN_CTRL_MODE(nr)); + + switch (val) { + case 0: /* Full speed */ + fanmode |= (3 << FAN_CTRL_MODE(nr)); + data->pwm[nr] = 255; + f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), + data->pwm[nr]); + break; + case 1: /* PWM */ + fanmode |= (3 << FAN_CTRL_MODE(nr)); + break; + case 2: /* AUTOMATIC*/ + fanmode |= (2 << FAN_CTRL_MODE(nr)); + break; + case 3: /* fan speed */ + break; + } + f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); + data->pwm_enable[nr] = val; + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + u8 conf = 0; + + if (val != 0 || val != 1 || data->kind == f75373) + return -EINVAL; + + mutex_lock(&data->update_lock); + conf = f75375_read8(client, F75375_REG_CONFIG1); + conf = ~(1 << FAN_CTRL_LINEAR(nr)); + + if (val == 0) + conf |= (1 << FAN_CTRL_LINEAR(nr)) ; + + f75375_write8(client, F75375_REG_CONFIG1, conf); + data->pwm_mode[nr] = val; + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm[nr]); +} + +static ssize_t show_pwm_mode(struct device *dev, struct device_attribute + *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", data->pwm_mode[nr]); +} + +#define VOLT_FROM_REG(val) ((val) * 8) +#define VOLT_TO_REG(val) ((val) / 8) + +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in[nr])); +} + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_max[nr])); +} + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", VOLT_FROM_REG(data->in_min[nr])); +} + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + mutex_lock(&data->update_lock); + data->in_max[nr] = val; + f75375_write8(client, F75375_REG_VOLT_HIGH(nr), data->in_max[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtoul(buf, NULL, 10); + val = SENSORS_LIMIT(VOLT_TO_REG(val), 0, 0xff); + mutex_lock(&data->update_lock); + data->in_min[nr] = val; + f75375_write8(client, F75375_REG_VOLT_LOW(nr), data->in_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} +#define TEMP_FROM_REG(val) ((val) * 1000) +#define TEMP_TO_REG(val) ((val) / 1000) + +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); +} + +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); +} + +static ssize_t show_temp_max_hyst(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct f75375_data *data = f75375_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[nr])); +} + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + mutex_lock(&data->update_lock); + data->temp_high[nr] = val; + f75375_write8(client, F75375_REG_TEMP_HIGH(nr), data->temp_high[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_temp_max_hyst(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct f75375_data *data = i2c_get_clientdata(client); + int val = simple_strtol(buf, NULL, 10); + val = SENSORS_LIMIT(TEMP_TO_REG(val), 0, 127); + mutex_lock(&data->update_lock); + data->temp_max_hyst[nr] = val; + f75375_write8(client, F75375_REG_TEMP_HYST(nr), + data->temp_max_hyst[nr]); + mutex_unlock(&data->update_lock); + return count; +} + +#define show_fan(thing) \ +static ssize_t show_##thing(struct device *dev, struct device_attribute *attr, \ + char *buf)\ +{\ + int nr = to_sensor_dev_attr(attr)->index;\ + struct f75375_data *data = f75375_update_device(dev); \ + return sprintf(buf, "%d\n", rpm_from_reg(data->thing[nr])); \ +} + +show_fan(fan); +show_fan(fan_min); +show_fan(fan_full); +show_fan(fan_exp); + +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 0); +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO|S_IWUSR, + show_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO|S_IWUSR, + show_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, + show_temp_max_hyst, set_temp_max_hyst, 0); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO|S_IWUSR, + show_temp_max, set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, + show_temp_max_hyst, set_temp_max_hyst, 1); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO|S_IWUSR, + show_temp_max, set_temp_max, 1); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_full, S_IRUGO, show_fan_full, NULL, 0); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO|S_IWUSR, + show_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan1_exp, S_IRUGO|S_IWUSR, + show_fan_exp, set_fan_exp, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_full, S_IRUGO, show_fan_full, NULL, 1); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO|S_IWUSR, + show_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan2_exp, S_IRUGO|S_IWUSR, + show_fan_exp, set_fan_exp, 1); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, + show_pwm, set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, + show_pwm_enable, set_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO|S_IWUSR, + show_pwm_mode, set_pwm_mode, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, + show_pwm, set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, + show_pwm_enable, set_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm2_mode, S_IRUGO|S_IWUSR, + show_pwm_mode, set_pwm_mode, 1); + +static struct attribute *f75375_attributes[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_full.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan1_exp.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_full.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan2_exp.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_mode.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_mode.dev_attr.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + NULL +}; + +static const struct attribute_group f75375_group = { + .attrs = f75375_attributes, +}; + +static int f75375_detach_client(struct i2c_client *client) +{ + struct f75375_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &f75375_group); + + err = i2c_detach_client(client); + if (err) { + dev_err(&client->dev, + "Client deregistration failed, " + "client not detached.\n"); + return err; + } + kfree(data); + return 0; +} + +static int f75375_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, f75375_detect); +} + +/* This function is called by i2c_probe */ +static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct f75375_data *data; + u8 version = 0; + int err = 0; + const char *name = ""; + + if (!(data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &f75375_driver; + + if (kind < 0) { + u16 vendid = f75375_read16(client, F75375_REG_VENDOR); + u16 chipid = f75375_read16(client, F75375_CHIP_ID); + version = f75375_read8(client, F75375_REG_VERSION); + if (chipid == 0x0306 && vendid == 0x1934) { + kind = f75375; + } else if (chipid == 0x0204 && vendid == 0x1934) { + kind = f75373; + } else { + dev_err(&adapter->dev, + "failed,%02X,%02X,%02X\n", + chipid, version, vendid); + goto exit_free; + } + } + + if (kind == f75375) { + name = "f75375"; + } else if (kind == f75373) { + name = "f75373"; + } + + dev_info(&adapter->dev, "found %s version: %02X\n", name, version); + strlcpy(client->name, name, I2C_NAME_SIZE); + data->kind = kind; + mutex_init(&data->update_lock); + if ((err = i2c_attach_client(client))) + goto exit_free; + + if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) + goto exit_detach; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &f75375_group); +exit_detach: + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int __init sensors_f75375_init(void) +{ + return i2c_add_driver(&f75375_driver); +} + +static void __exit sensors_f75375_exit(void) +{ + i2c_del_driver(&f75375_driver); +} + +MODULE_AUTHOR("Riku Voipio <riku.voipio@movial.fi>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("F75373/F75375 hardware monitoring driver"); + +module_init(sensors_f75375_init); +module_exit(sensors_f75375_exit); diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c index b34b546c68b..e67c36953b2 100644 --- a/drivers/hwmon/fscher.c +++ b/drivers/hwmon/fscher.c @@ -134,7 +134,7 @@ static struct i2c_driver fscher_driver = { struct fscher_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -344,9 +344,9 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -367,7 +367,7 @@ static int fscher_detach_client(struct i2c_client *client) struct fscher_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &fscher_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c new file mode 100644 index 00000000000..63a4df0580d --- /dev/null +++ b/drivers/hwmon/fschmd.c @@ -0,0 +1,778 @@ +/* fschmd.c + * + * Copyright (C) 2007 Hans de Goede <j.w.r.degoede@hhs.nl> + * + * 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. + */ + +/* + * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, + * Scylla, Heracles and Heimdall chips + * + * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 + * (candidate) fschmd drivers: + * Copyright (C) 2006 Thilo Cestonaro + * <thilo.cestonaro.external@fujitsu-siemens.com> + * Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch> + * Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de> + * Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de> + * Copyright (C) 2000 Hermann Jung <hej@odn.de> + */ + +#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 unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); + +/* + * The FSCHMD registers and other defines + */ + +/* chip identification */ +#define FSCHMD_REG_IDENT_0 0x00 +#define FSCHMD_REG_IDENT_1 0x01 +#define FSCHMD_REG_IDENT_2 0x02 +#define FSCHMD_REG_REVISION 0x03 + +/* global control and status */ +#define FSCHMD_REG_EVENT_STATE 0x04 +#define FSCHMD_REG_CONTROL 0x05 + +#define FSCHMD_CONTROL_ALERT_LED_MASK 0x01 + +/* watchdog (support to be implemented) */ +#define FSCHMD_REG_WDOG_PRESET 0x28 +#define FSCHMD_REG_WDOG_STATE 0x23 +#define FSCHMD_REG_WDOG_CONTROL 0x21 + +/* voltages, weird order is to keep the same order as the old drivers */ +static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; + +/* minimum pwm at which the fan is driven (pwm can by increased depending on + the temp. Notice that for the scy some fans share there minimum speed. + Also notice that with the scy the sensor order is different then with the + other chips, this order was in the 2.4 driver and kept for consistency. */ +static const u8 FSCHMD_REG_FAN_MIN[5][6] = { + { 0x55, 0x65 }, /* pos */ + { 0x55, 0x65, 0xb5 }, /* her */ + { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ + { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ + { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ +}; + +/* actual fan speed */ +static const u8 FSCHMD_REG_FAN_ACT[5][6] = { + { 0x0e, 0x6b, 0xab }, /* pos */ + { 0x0e, 0x6b, 0xbb }, /* her */ + { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ + { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ + { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ +}; + +/* fan status registers */ +static const u8 FSCHMD_REG_FAN_STATE[5][6] = { + { 0x0d, 0x62, 0xa2 }, /* pos */ + { 0x0d, 0x62, 0xb2 }, /* her */ + { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ + { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ + { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ +}; + +/* fan ripple / divider registers */ +static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { + { 0x0f, 0x6f, 0xaf }, /* pos */ + { 0x0f, 0x6f, 0xbf }, /* her */ + { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ + { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ + { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ +}; + +static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; + +/* Fan status register bitmasks */ +#define FSCHMD_FAN_ALARM_MASK 0x04 /* called fault by FSC! */ +#define FSCHMD_FAN_NOT_PRESENT_MASK 0x08 /* not documented */ + + +/* actual temperature registers */ +static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { + { 0x64, 0x32, 0x35 }, /* pos */ + { 0x64, 0x32, 0x35 }, /* her */ + { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ + { 0x64, 0x32, 0x35 }, /* hrc */ + { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ +}; + +/* temperature state registers */ +static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { + { 0x71, 0x81, 0x91 }, /* pos */ + { 0x71, 0x81, 0x91 }, /* her */ + { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ + { 0x71, 0x81, 0x91 }, /* hrc */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /*Â hmd */ +}; + +/* temperature high limit registers, FSC does not document these. Proven to be + there with field testing on the fscher and fschrc, already supported / used + in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers + at these addresses, but doesn't want to confirm they are the same as with + the fscher?? */ +static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { + { 0, 0, 0 }, /* pos */ + { 0x76, 0x86, 0x96 }, /* her */ + { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ + { 0x76, 0x86, 0x96 }, /* hrc */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /*Â hmd */ +}; + +/* These were found through experimenting with an fscher, currently they are + not used, but we keep them around for future reference. +static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; +static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ + +static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; + +/* temp status register bitmasks */ +#define FSCHMD_TEMP_WORKING_MASK 0x01 +#define FSCHMD_TEMP_ALERT_MASK 0x02 +/* there only really is an alarm if the sensor is working and alert == 1 */ +#define FSCHMD_TEMP_ALARM_MASK \ + (FSCHMD_TEMP_WORKING_MASK | FSCHMD_TEMP_ALERT_MASK) + +/* our driver name */ +#define FSCHMD_NAME "fschmd" + +/* + * Functions declarations + */ + +static int fschmd_attach_adapter(struct i2c_adapter *adapter); +static int fschmd_detach_client(struct i2c_client *client); +static struct fschmd_data *fschmd_update_device(struct device *dev); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver fschmd_driver = { + .driver = { + .name = FSCHMD_NAME, + }, + .attach_adapter = fschmd_attach_adapter, + .detach_client = fschmd_detach_client, +}; + +/* + * Client data (each client gets its own) + */ + +struct fschmd_data { + struct i2c_client client; + struct device *hwmon_dev; + struct mutex update_lock; + int kind; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 global_control; /* global control register */ + u8 volt[3]; /* 12, 5, battery voltage */ + u8 temp_act[5]; /* temperature */ + u8 temp_status[5]; /* status of sensor */ + u8 temp_max[5]; /* high temp limit, notice: undocumented! */ + u8 fan_act[6]; /* fans revolutions per second */ + u8 fan_status[6]; /* fan status */ + u8 fan_min[6]; /* fan min value for rps */ + u8 fan_ripple[6]; /* divider for rps */ +}; + +/* + * Sysfs attr show / store functions + */ + +static ssize_t show_in_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + const int max_reading[3] = { 14200, 6600, 3300 }; + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", (data->volt[index] * + max_reading[index] + 128) / 255); +} + + +#define TEMP_FROM_REG(val) (((val) - 128) * 1000) + +static ssize_t show_temp_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index])); +} + +static ssize_t show_temp_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index])); +} + +static ssize_t store_temp_max(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + long v = simple_strtol(buf, NULL, 10) / 1000; + + v = SENSORS_LIMIT(v, -128, 127) + 128; + + mutex_lock(&data->update_lock); + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_TEMP_LIMIT[data->kind][index], v); + data->temp_max[index] = v; + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_temp_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + /* bit 0 set means sensor working ok, so no fault! */ + if (data->temp_status[index] & FSCHMD_TEMP_WORKING_MASK) + return sprintf(buf, "0\n"); + else + return sprintf(buf, "1\n"); +} + +static ssize_t show_temp_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) == + FSCHMD_TEMP_ALARM_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + + +#define RPM_FROM_REG(val) ((val) * 60) + +static ssize_t show_fan_value(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index])); +} + +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + /* bits 2..7 reserved => mask with 3 */ + return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3)); +} + +static ssize_t store_fan_div(struct device *dev, struct device_attribute + *devattr, const char *buf, size_t count) +{ + u8 reg; + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + /* supported values: 2, 4, 8 */ + unsigned long v = simple_strtoul(buf, NULL, 10); + + switch (v) { + case 2: v = 1; break; + case 4: v = 2; break; + case 8: v = 3; break; + default: + dev_err(dev, "fan_div value %lu not supported. " + "Choose one of 2, 4 or 8!\n", v); + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + reg = i2c_smbus_read_byte_data(&data->client, + FSCHMD_REG_FAN_RIPPLE[data->kind][index]); + + /* bits 2..7 reserved => mask with 0x03 */ + reg &= ~0x03; + reg |= v; + + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg); + + data->fan_ripple[index] = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_fan_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->fan_status[index] & FSCHMD_FAN_ALARM_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t show_fan_fault(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + + +static ssize_t show_pwm_auto_point1_pwm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int index = to_sensor_dev_attr(devattr)->index; + int val = fschmd_update_device(dev)->fan_min[index]; + + /* 0 = allow turning off, 1-255 = 50-100% */ + if (val) + val = val / 2 + 128; + + return sprintf(buf, "%d\n", val); +} + +static ssize_t store_pwm_auto_point1_pwm(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(devattr)->index; + struct fschmd_data *data = dev_get_drvdata(dev); + unsigned long v = simple_strtoul(buf, NULL, 10); + + /* register: 0 = allow turning off, 1-255 = 50-100% */ + if (v) { + v = SENSORS_LIMIT(v, 128, 255); + v = (v - 128) * 2 + 1; + } + + mutex_lock(&data->update_lock); + + i2c_smbus_write_byte_data(&data->client, + FSCHMD_REG_FAN_MIN[data->kind][index], v); + data->fan_min[index] = v; + + mutex_unlock(&data->update_lock); + + return count; +} + + +/* The FSC hwmon family has the ability to force an attached alert led to flash + from software, we export this as an alert_led sysfs attr */ +static ssize_t show_alert_led(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct fschmd_data *data = fschmd_update_device(dev); + + if (data->global_control & FSCHMD_CONTROL_ALERT_LED_MASK) + return sprintf(buf, "1\n"); + else + return sprintf(buf, "0\n"); +} + +static ssize_t store_alert_led(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + u8 reg; + struct fschmd_data *data = dev_get_drvdata(dev); + unsigned long v = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + reg = i2c_smbus_read_byte_data(&data->client, FSCHMD_REG_CONTROL); + + if (v) + reg |= FSCHMD_CONTROL_ALERT_LED_MASK; + else + reg &= ~FSCHMD_CONTROL_ALERT_LED_MASK; + + i2c_smbus_write_byte_data(&data->client, FSCHMD_REG_CONTROL, reg); + + data->global_control = reg; + + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute fschmd_attr[] = { + SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), + SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), + SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), + SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), +}; + +static struct sensor_device_attribute fschmd_temp_attr[] = { + SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), + SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), + SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0), + SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0), + SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), + SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), + SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1), + SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1), + SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2), + SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2), + SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2), + SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2), + SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3), + SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3), + SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3), + SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3), + SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4), + SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), + SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), + SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), +}; + +static struct sensor_device_attribute fschmd_fan_attr[] = { + SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0), + SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0), + SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0), + SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0), + SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 0), + SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1), + SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1), + SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1), + SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1), + SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 1), + SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2), + SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2), + SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2), + SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2), + SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 2), + SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3), + SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3), + SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3), + SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3), + SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 3), + SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4), + SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4), + SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4), + SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4), + SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 4), + SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5), + SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5), + SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5), + SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), + SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, + store_pwm_auto_point1_pwm, 5), +}; + + +/* + * Real code + */ + +static int fschmd_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct fschmd_data *data; + u8 revision; + const char * const names[5] = { "Poseidon", "Hermes", "Scylla", + "Heracles", "Heimdall" }; + const char * const client_names[5] = { "fscpos", "fscher", "fscscy", + "fschrc", "fschmd" }; + int i, err = 0; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return 0; + + /* OK. For now, we presume we have a valid client. We now create the + * client structure, even though we cannot fill it completely yet. + * But it allows us to access i2c_smbus_read_byte_data. */ + if (!(data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL))) + return -ENOMEM; + + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &fschmd_driver; + mutex_init(&data->update_lock); + + /* Detect & Identify the chip */ + if (kind <= 0) { + char id[4]; + + id[0] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_0); + id[1] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_1); + id[2] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_IDENT_2); + id[3] = '\0'; + + if (!strcmp(id, "PEG")) + kind = fscpos; + else if (!strcmp(id, "HER")) + kind = fscher; + else if (!strcmp(id, "SCY")) + kind = fscscy; + else if (!strcmp(id, "HRC")) + kind = fschrc; + else if (!strcmp(id, "HMD")) + kind = fschmd; + else + goto exit_free; + } + + if (kind == fscpos) { + /* The Poseidon has hardwired temp limits, fill these + in for the alarm resetting code */ + data->temp_max[0] = 70 + 128; + data->temp_max[1] = 50 + 128; + data->temp_max[2] = 50 + 128; + } + + /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ + data->kind = kind - 1; + strlcpy(client->name, client_names[data->kind], I2C_NAME_SIZE); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { + err = device_create_file(&client->dev, + &fschmd_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) { + /* Poseidon doesn't have TEMP_LIMIT registers */ + if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show == + show_temp_max) + continue; + + err = device_create_file(&client->dev, + &fschmd_temp_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) { + /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */ + if (kind == fscpos && + !strcmp(fschmd_fan_attr[i].dev_attr.attr.name, + "pwm3_auto_point1_pwm")) + continue; + + err = device_create_file(&client->dev, + &fschmd_fan_attr[i].dev_attr); + if (err) + goto exit_detach; + } + + 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_detach; + } + + revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); + printk(KERN_INFO FSCHMD_NAME ": Detected FSC %s chip, revision: %d\n", + names[data->kind], (int) revision); + + return 0; + +exit_detach: + fschmd_detach_client(client); /* will also free data for us */ + return err; + +exit_free: + kfree(data); + return err; +} + +static int fschmd_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, fschmd_detect); +} + +static int fschmd_detach_client(struct i2c_client *client) +{ + struct fschmd_data *data = i2c_get_clientdata(client); + int i, err; + + /* Check if registered in case we're called from fschmd_detect + to cleanup after an error */ + if (data->hwmon_dev) + hwmon_device_unregister(data->hwmon_dev); + + for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) + device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); + for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) + device_remove_file(&client->dev, + &fschmd_temp_attr[i].dev_attr); + for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) + device_remove_file(&client->dev, + &fschmd_fan_attr[i].dev_attr); + + if ((err = i2c_detach_client(client))) + return err; + + kfree(data); + return 0; +} + +static struct fschmd_data *fschmd_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct fschmd_data *data = i2c_get_clientdata(client); + int i; + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) { + + for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) { + data->temp_act[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_TEMP_ACT[data->kind][i]); + data->temp_status[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_TEMP_STATE[data->kind][i]); + + /* The fscpos doesn't have TEMP_LIMIT registers */ + if (FSCHMD_REG_TEMP_LIMIT[data->kind][i]) + data->temp_max[i] = i2c_smbus_read_byte_data( + client, + FSCHMD_REG_TEMP_LIMIT[data->kind][i]); + + /* reset alarm if the alarm condition is gone, + the chip doesn't do this itself */ + if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) == + FSCHMD_TEMP_ALARM_MASK && + data->temp_act[i] < data->temp_max[i]) + i2c_smbus_write_byte_data(client, + FSCHMD_REG_TEMP_STATE[data->kind][i], + FSCHMD_TEMP_ALERT_MASK); + } + + for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { + data->fan_act[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_ACT[data->kind][i]); + data->fan_status[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_STATE[data->kind][i]); + data->fan_ripple[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_FAN_RIPPLE[data->kind][i]); + + /* The fscpos third fan doesn't have a fan_min */ + if (FSCHMD_REG_FAN_MIN[data->kind][i]) + data->fan_min[i] = i2c_smbus_read_byte_data( + client, + FSCHMD_REG_FAN_MIN[data->kind][i]); + + /* reset fan status if speed is back to > 0 */ + if ((data->fan_status[i] & FSCHMD_FAN_ALARM_MASK) && + data->fan_act[i]) + i2c_smbus_write_byte_data(client, + FSCHMD_REG_FAN_STATE[data->kind][i], + FSCHMD_FAN_ALARM_MASK); + } + + for (i = 0; i < 3; i++) + data->volt[i] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_VOLT[i]); + + data->global_control = i2c_smbus_read_byte_data(client, + FSCHMD_REG_CONTROL); + + /* To be implemented in the future + data->watchdog[0] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_PRESET); + data->watchdog[1] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_STATE); + data->watchdog[2] = i2c_smbus_read_byte_data(client, + FSCHMD_REG_WDOG_CONTROL); */ + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init fschmd_init(void) +{ + return i2c_add_driver(&fschmd_driver); +} + +static void __exit fschmd_exit(void) +{ + i2c_del_driver(&fschmd_driver); +} + +MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); +MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " + "Heimdall driver"); +MODULE_LICENSE("GPL"); + +module_init(fschmd_init); +module_exit(fschmd_exit); diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c index ea506a77f9c..92c9703d0ac 100644 --- a/drivers/hwmon/fscpos.c +++ b/drivers/hwmon/fscpos.c @@ -115,7 +115,7 @@ static struct i2c_driver fscpos_driver = { */ struct fscpos_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* 0 until following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -539,9 +539,9 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -562,7 +562,7 @@ static int fscpos_detach_client(struct i2c_client *client) struct fscpos_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &fscpos_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index c103640455a..bb58d9866a3 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -119,7 +119,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* Each client has this additional data */ struct gl518_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -460,9 +460,9 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -502,7 +502,7 @@ static int gl518_detach_client(struct i2c_client *client) struct gl518_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl518_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index ebe7b9aaa91..a3b56c816e1 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -122,7 +122,7 @@ static struct i2c_driver gl520_driver = { /* Client data */ struct gl520_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until the following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -622,9 +622,9 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -685,7 +685,7 @@ static int gl520_detach_client(struct i2c_client *client) struct gl520_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl520_group); sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index affcc00764d..3db28450a3b 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -28,17 +28,17 @@ static DEFINE_IDR(hwmon_idr); static DEFINE_SPINLOCK(idr_lock); /** - * hwmon_device_register - register w/ hwmon sysfs class + * hwmon_device_register - register w/ hwmon * @dev: the device to register * - * hwmon_device_unregister() must be called when the class device is no + * hwmon_device_unregister() must be called when the device is no * longer needed. * - * Returns the pointer to the new struct class device. + * Returns the pointer to the new device. */ -struct class_device *hwmon_device_register(struct device *dev) +struct device *hwmon_device_register(struct device *dev) { - struct class_device *cdev; + struct device *hwdev; int id, err; again: @@ -55,34 +55,33 @@ again: return ERR_PTR(err); id = id & MAX_ID_MASK; - cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, - HWMON_ID_FORMAT, id); + hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id); - if (IS_ERR(cdev)) { + if (IS_ERR(hwdev)) { spin_lock(&idr_lock); idr_remove(&hwmon_idr, id); spin_unlock(&idr_lock); } - return cdev; + return hwdev; } /** * hwmon_device_unregister - removes the previously registered class device * - * @cdev: the class device to destroy + * @dev: the class device to destroy */ -void hwmon_device_unregister(struct class_device *cdev) +void hwmon_device_unregister(struct device *dev) { int id; - if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) { - class_device_unregister(cdev); + if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) { + device_unregister(dev); spin_lock(&idr_lock); idr_remove(&hwmon_idr, id); spin_unlock(&idr_lock); } else - dev_dbg(cdev->dev, + dev_dbg(dev->parent, "hwmon_device_unregister() failed: bad class ID!\n"); } diff --git a/drivers/hwmon/ibmpex.c b/drivers/hwmon/ibmpex.c new file mode 100644 index 00000000000..c462824ffcc --- /dev/null +++ b/drivers/hwmon/ibmpex.c @@ -0,0 +1,607 @@ +/* + * A hwmon driver for the IBM PowerExecutive temperature/power sensors + * Copyright (C) 2007 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/ipmi.h> +#include <linux/module.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> + +#define REFRESH_INTERVAL (2 * HZ) +#define DRVNAME "ibmpex" + +#define PEX_GET_VERSION 1 +#define PEX_GET_SENSOR_COUNT 2 +#define PEX_GET_SENSOR_NAME 3 +#define PEX_RESET_HIGH_LOW 4 +#define PEX_GET_SENSOR_DATA 6 + +#define PEX_NET_FUNCTION 0x3A +#define PEX_COMMAND 0x3C + +static inline u16 extract_value(const char *data, int offset) +{ + return be16_to_cpup((u16 *)&data[offset]); +} + +#define TEMP_SENSOR 1 +#define POWER_SENSOR 2 + +#define PEX_SENSOR_TYPE_LEN 3 +static u8 const power_sensor_sig[] = {0x70, 0x77, 0x72}; +static u8 const temp_sensor_sig[] = {0x74, 0x65, 0x6D}; + +#define PEX_MULT_LEN 2 +static u8 const watt_sensor_sig[] = {0x41, 0x43}; + +#define PEX_NUM_SENSOR_FUNCS 3 +static char const * const power_sensor_name_templates[] = { + "%s%d_average", + "%s%d_average_lowest", + "%s%d_average_highest" +}; +static char const * const temp_sensor_name_templates[] = { + "%s%d_input", + "%s%d_input_lowest", + "%s%d_input_highest" +}; + +static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); +static void ibmpex_register_bmc(int iface, struct device *dev); +static void ibmpex_bmc_gone(int iface); + +struct ibmpex_sensor_data { + int in_use; + s16 values[PEX_NUM_SENSOR_FUNCS]; + int multiplier; + + struct sensor_device_attribute_2 attr[PEX_NUM_SENSOR_FUNCS]; +}; + +struct ibmpex_bmc_data { + struct list_head list; + struct device *hwmon_dev; + struct device *bmc_device; + struct mutex lock; + char valid; + unsigned long last_updated; /* In jiffies */ + + struct ipmi_addr address; + struct completion read_complete; + ipmi_user_t user; + int interface; + + struct kernel_ipmi_msg tx_message; + unsigned char tx_msg_data[IPMI_MAX_MSG_LENGTH]; + long tx_msgid; + + unsigned char rx_msg_data[IPMI_MAX_MSG_LENGTH]; + unsigned long rx_msg_len; + unsigned char rx_result; + int rx_recv_type; + + unsigned char sensor_major; + unsigned char sensor_minor; + + unsigned char num_sensors; + struct ibmpex_sensor_data *sensors; +}; + +struct ibmpex_driver_data { + struct list_head bmc_data; + struct ipmi_smi_watcher bmc_events; + struct ipmi_user_hndl ipmi_hndlrs; +}; + +static struct ibmpex_driver_data driver_data = { + .bmc_data = LIST_HEAD_INIT(driver_data.bmc_data), + .bmc_events = { + .owner = THIS_MODULE, + .new_smi = ibmpex_register_bmc, + .smi_gone = ibmpex_bmc_gone, + }, + .ipmi_hndlrs = { + .ipmi_recv_hndl = ibmpex_msg_handler, + }, +}; + +static int ibmpex_send_message(struct ibmpex_bmc_data *data) +{ + int err; + + err = ipmi_validate_addr(&data->address, sizeof(data->address)); + if (err) + goto out; + + data->tx_msgid++; + err = ipmi_request_settime(data->user, &data->address, data->tx_msgid, + &data->tx_message, data, 0, 0, 0); + if (err) + goto out1; + + return 0; +out1: + printk(KERN_ERR "%s: request_settime=%x\n", __FUNCTION__, err); + return err; +out: + printk(KERN_ERR "%s: validate_addr=%x\n", __FUNCTION__, err); + return err; +} + +static int ibmpex_ver_check(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_GET_VERSION; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len != 6) + return -ENOENT; + + data->sensor_major = data->rx_msg_data[0]; + data->sensor_minor = data->rx_msg_data[1]; + + printk(KERN_INFO DRVNAME ": Found BMC with sensor interface " + "v%d.%d %d-%02d-%02d on interface %d\n", + data->sensor_major, + data->sensor_minor, + extract_value(data->rx_msg_data, 2), + data->rx_msg_data[4], + data->rx_msg_data[5], + data->interface); + + return 0; +} + +static int ibmpex_query_sensor_count(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_COUNT; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len != 1) + return -ENOENT; + + return data->rx_msg_data[0]; +} + +static int ibmpex_query_sensor_name(struct ibmpex_bmc_data *data, int sensor) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_NAME; + data->tx_msg_data[1] = sensor; + data->tx_message.data_len = 2; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len < 1) + return -ENOENT; + + return 0; +} + +static int ibmpex_query_sensor_data(struct ibmpex_bmc_data *data, int sensor) +{ + data->tx_msg_data[0] = PEX_GET_SENSOR_DATA; + data->tx_msg_data[1] = sensor; + data->tx_message.data_len = 2; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + if (data->rx_result || data->rx_msg_len < 26) { + printk(KERN_ERR "Error reading sensor %d, please check.\n", + sensor); + return -ENOENT; + } + + return 0; +} + +static int ibmpex_reset_high_low_data(struct ibmpex_bmc_data *data) +{ + data->tx_msg_data[0] = PEX_RESET_HIGH_LOW; + data->tx_message.data_len = 1; + ibmpex_send_message(data); + + wait_for_completion(&data->read_complete); + + return 0; +} + +static void ibmpex_update_device(struct ibmpex_bmc_data *data) +{ + int i, err; + + mutex_lock(&data->lock); + if (time_before(jiffies, data->last_updated + REFRESH_INTERVAL) && + data->valid) + goto out; + + for (i = 0; i < data->num_sensors; i++) { + if (!data->sensors[i].in_use) + continue; + err = ibmpex_query_sensor_data(data, i); + if (err) + continue; + data->sensors[i].values[0] = + extract_value(data->rx_msg_data, 16); + data->sensors[i].values[1] = + extract_value(data->rx_msg_data, 18); + data->sensors[i].values[2] = + extract_value(data->rx_msg_data, 20); + } + + data->last_updated = jiffies; + data->valid = 1; + +out: + mutex_unlock(&data->lock); +} + +static struct ibmpex_bmc_data *get_bmc_data(int iface) +{ + struct ibmpex_bmc_data *p, *next; + + list_for_each_entry_safe(p, next, &driver_data.bmc_data, list) + if (p->interface == iface) + return p; + + return NULL; +} + +static ssize_t show_name(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "%s\n", DRVNAME); +} +static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); + +static ssize_t ibmpex_show_sensor(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + int mult = data->sensors[attr->index].multiplier; + ibmpex_update_device(data); + + return sprintf(buf, "%d\n", + data->sensors[attr->index].values[attr->nr] * mult); +} + +static ssize_t ibmpex_reset_high_low(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct ibmpex_bmc_data *data = dev_get_drvdata(dev); + + ibmpex_reset_high_low_data(data); + + return count; +} + +static SENSOR_DEVICE_ATTR(reset_high_low, S_IWUSR, NULL, + ibmpex_reset_high_low, 0); + +static int is_power_sensor(const char *sensor_id, int len) +{ + if (len < PEX_SENSOR_TYPE_LEN) + return 0; + + if (!memcmp(sensor_id, power_sensor_sig, PEX_SENSOR_TYPE_LEN)) + return 1; + return 0; +} + +static int is_temp_sensor(const char *sensor_id, int len) +{ + if (len < PEX_SENSOR_TYPE_LEN) + return 0; + + if (!memcmp(sensor_id, temp_sensor_sig, PEX_SENSOR_TYPE_LEN)) + return 1; + return 0; +} + +static int power_sensor_multiplier(const char *sensor_id, int len) +{ + int i; + + for (i = PEX_SENSOR_TYPE_LEN; i < len - 1; i++) + if (!memcmp(&sensor_id[i], watt_sensor_sig, PEX_MULT_LEN)) + return 1000000; + + return 100000; +} + +static int create_sensor(struct ibmpex_bmc_data *data, int type, + int counter, int sensor, int func) +{ + int err; + char *n; + + n = kmalloc(32, GFP_KERNEL); + if (!n) + return -ENOMEM; + + if (type == TEMP_SENSOR) + sprintf(n, temp_sensor_name_templates[func], "temp", counter); + else if (type == POWER_SENSOR) + sprintf(n, power_sensor_name_templates[func], "power", counter); + + data->sensors[sensor].attr[func].dev_attr.attr.name = n; + data->sensors[sensor].attr[func].dev_attr.attr.mode = S_IRUGO; + data->sensors[sensor].attr[func].dev_attr.show = ibmpex_show_sensor; + data->sensors[sensor].attr[func].index = sensor; + data->sensors[sensor].attr[func].nr = func; + + err = device_create_file(data->bmc_device, + &data->sensors[sensor].attr[func].dev_attr); + if (err) { + data->sensors[sensor].attr[func].dev_attr.attr.name = NULL; + kfree(n); + return err; + } + + return 0; +} + +static int ibmpex_find_sensors(struct ibmpex_bmc_data *data) +{ + int i, j, err; + int sensor_type; + int sensor_counter; + int num_power = 0; + int num_temp = 0; + + err = ibmpex_query_sensor_count(data); + if (err <= 0) + return -ENOENT; + data->num_sensors = err; + + data->sensors = kzalloc(data->num_sensors * sizeof(*data->sensors), + GFP_KERNEL); + if (!data->sensors) + return -ENOMEM; + + for (i = 0; i < data->num_sensors; i++) { + err = ibmpex_query_sensor_name(data, i); + if (err) + continue; + + if (is_power_sensor(data->rx_msg_data, data->rx_msg_len)) { + sensor_type = POWER_SENSOR; + num_power++; + sensor_counter = num_power; + data->sensors[i].multiplier = + power_sensor_multiplier(data->rx_msg_data, + data->rx_msg_len); + } else if (is_temp_sensor(data->rx_msg_data, + data->rx_msg_len)) { + sensor_type = TEMP_SENSOR; + num_temp++; + sensor_counter = num_temp; + data->sensors[i].multiplier = 1; + } else + continue; + + data->sensors[i].in_use = 1; + + /* Create attributes */ + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + err = create_sensor(data, sensor_type, sensor_counter, + i, j); + if (err) + goto exit_remove; + } + } + + err = device_create_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + if (err) + goto exit_remove; + + err = device_create_file(data->bmc_device, + &sensor_dev_attr_name.dev_attr); + if (err) + goto exit_remove; + + return 0; + +exit_remove: + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); + for (i = 0; i < data->num_sensors; i++) + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + if (!data->sensors[i].attr[j].dev_attr.attr.name) + continue; + device_remove_file(data->bmc_device, + &data->sensors[i].attr[j].dev_attr); + kfree(data->sensors[i].attr[j].dev_attr.attr.name); + } + + kfree(data->sensors); + return err; +} + +static void ibmpex_register_bmc(int iface, struct device *dev) +{ + struct ibmpex_bmc_data *data; + int err; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) { + printk(KERN_ERR DRVNAME ": Insufficient memory for BMC " + "interface %d.\n", data->interface); + return; + } + + data->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + data->address.channel = IPMI_BMC_CHANNEL; + data->address.data[0] = 0; + data->interface = iface; + data->bmc_device = dev; + + /* Create IPMI messaging interface user */ + err = ipmi_create_user(data->interface, &driver_data.ipmi_hndlrs, + data, &data->user); + if (err < 0) { + printk(KERN_ERR DRVNAME ": Error, unable to register user with " + "ipmi interface %d\n", + data->interface); + goto out; + } + + mutex_init(&data->lock); + + /* Initialize message */ + data->tx_msgid = 0; + init_completion(&data->read_complete); + data->tx_message.netfn = PEX_NET_FUNCTION; + data->tx_message.cmd = PEX_COMMAND; + data->tx_message.data = data->tx_msg_data; + + /* Does this BMC support PowerExecutive? */ + err = ibmpex_ver_check(data); + if (err) + goto out_user; + + /* Register the BMC as a HWMON class device */ + data->hwmon_dev = hwmon_device_register(data->bmc_device); + + if (IS_ERR(data->hwmon_dev)) { + printk(KERN_ERR DRVNAME ": Error, unable to register hwmon " + "class device for interface %d\n", + data->interface); + goto out_user; + } + + /* finally add the new bmc data to the bmc data list */ + dev_set_drvdata(dev, data); + list_add_tail(&data->list, &driver_data.bmc_data); + + /* Now go find all the sensors */ + err = ibmpex_find_sensors(data); + if (err) { + printk(KERN_ERR "Error %d allocating memory\n", err); + goto out_register; + } + + return; + +out_register: + hwmon_device_unregister(data->hwmon_dev); +out_user: + ipmi_destroy_user(data->user); +out: + kfree(data); +} + +static void ibmpex_bmc_delete(struct ibmpex_bmc_data *data) +{ + int i, j; + + device_remove_file(data->bmc_device, + &sensor_dev_attr_reset_high_low.dev_attr); + device_remove_file(data->bmc_device, &sensor_dev_attr_name.dev_attr); + for (i = 0; i < data->num_sensors; i++) + for (j = 0; j < PEX_NUM_SENSOR_FUNCS; j++) { + if (!data->sensors[i].attr[j].dev_attr.attr.name) + continue; + device_remove_file(data->bmc_device, + &data->sensors[i].attr[j].dev_attr); + kfree(data->sensors[i].attr[j].dev_attr.attr.name); + } + + list_del(&data->list); + dev_set_drvdata(data->bmc_device, NULL); + hwmon_device_unregister(data->hwmon_dev); + ipmi_destroy_user(data->user); + kfree(data->sensors); + kfree(data); +} + +static void ibmpex_bmc_gone(int iface) +{ + struct ibmpex_bmc_data *data = get_bmc_data(iface); + + if (!data) + return; + + ibmpex_bmc_delete(data); +} + +static void ibmpex_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) +{ + struct ibmpex_bmc_data *data = (struct ibmpex_bmc_data *)user_msg_data; + + if (msg->msgid != data->tx_msgid) { + printk(KERN_ERR "Received msgid (%02x) and transmitted " + "msgid (%02x) mismatch!\n", + (int)msg->msgid, + (int)data->tx_msgid); + ipmi_free_recv_msg(msg); + return; + } + + data->rx_recv_type = msg->recv_type; + if (msg->msg.data_len > 0) + data->rx_result = msg->msg.data[0]; + else + data->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + if (msg->msg.data_len > 1) { + data->rx_msg_len = msg->msg.data_len - 1; + memcpy(data->rx_msg_data, msg->msg.data + 1, data->rx_msg_len); + } else + data->rx_msg_len = 0; + + ipmi_free_recv_msg(msg); + complete(&data->read_complete); +} + +static int __init ibmpex_init(void) +{ + return ipmi_smi_watcher_register(&driver_data.bmc_events); +} + +static void __exit ibmpex_exit(void) +{ + struct ibmpex_bmc_data *p, *next; + + ipmi_smi_watcher_unregister(&driver_data.bmc_events); + list_for_each_entry_safe(p, next, &driver_data.bmc_data, list) + ibmpex_bmc_delete(p); +} + +MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); +MODULE_DESCRIPTION("IBM PowerExecutive power/temperature sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(ibmpex_init); +module_exit(ibmpex_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index d75dba9b810..6a182e14cf5 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -141,10 +141,10 @@ static int fix_pwm_polarity; /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */ -#define IT87_REG_FAN(nr) (0x0d + (nr)) -#define IT87_REG_FAN_MIN(nr) (0x10 + (nr)) -#define IT87_REG_FANX(nr) (0x18 + (nr)) -#define IT87_REG_FANX_MIN(nr) (0x1b + (nr)) +static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; +static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; +static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; +static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) @@ -222,7 +222,7 @@ struct it87_sio_data { /* For each registered chip, we need to keep some data in memory. The structure is dynamically allocated. */ struct it87_data { - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; unsigned short addr; @@ -235,8 +235,8 @@ struct it87_data { u8 in_max[8]; /* Register value */ u8 in_min[8]; /* Register value */ u8 has_fan; /* Bitfield, fans enabled */ - u16 fan[3]; /* Register values, possibly combined */ - u16 fan_min[3]; /* Register values, possibly combined */ + u16 fan[5]; /* Register values, possibly combined */ + u16 fan_min[5]; /* Register values, possibly combined */ u8 temp[3]; /* Register value */ u8 temp_high[3]; /* Register value */ u8 temp_low[3]; /* Register value */ @@ -555,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, } data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } @@ -596,7 +596,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, /* Restore fan min limit */ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; @@ -729,9 +729,9 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, mutex_lock(&data->update_lock); data->fan_min[nr] = FAN16_TO_REG(val); - it87_write_value(data, IT87_REG_FAN_MIN(nr), + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr] & 0xff); - it87_write_value(data, IT87_REG_FANX_MIN(nr), + it87_write_value(data, IT87_REG_FANX_MIN[nr], data->fan_min[nr] >> 8); mutex_unlock(&data->update_lock); return count; @@ -751,6 +751,8 @@ static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ show_fan16_offset(1); show_fan16_offset(2); show_fan16_offset(3); +show_fan16_offset(4); +show_fan16_offset(5); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) @@ -763,7 +765,7 @@ static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct it87_data *data = it87_update_device(dev); + struct it87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t @@ -851,6 +853,10 @@ static struct attribute *it87_attributes_opt[] = { &sensor_dev_attr_fan2_min16.dev_attr.attr, &sensor_dev_attr_fan3_input16.dev_attr.attr, &sensor_dev_attr_fan3_min16.dev_attr.attr, + &sensor_dev_attr_fan4_input16.dev_attr.attr, + &sensor_dev_attr_fan4_min16.dev_attr.attr, + &sensor_dev_attr_fan5_input16.dev_attr.attr, + &sensor_dev_attr_fan5_min16.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, @@ -1024,6 +1030,20 @@ static int __devinit it87_probe(struct platform_device *pdev) &sensor_dev_attr_fan3_min16.dev_attr))) goto ERROR4; } + if (data->has_fan & (1 << 3)) { + if ((err = device_create_file(dev, + &sensor_dev_attr_fan4_input16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan4_min16.dev_attr))) + goto ERROR4; + } + if (data->has_fan & (1 << 4)) { + if ((err = device_create_file(dev, + &sensor_dev_attr_fan5_input16.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan5_min16.dev_attr))) + goto ERROR4; + } } else { /* 8-bit tachometers with clock divider */ if (data->has_fan & (1 << 0)) { @@ -1089,9 +1109,9 @@ static int __devinit it87_probe(struct platform_device *pdev) goto ERROR4; } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1113,7 +1133,7 @@ static int __devexit it87_remove(struct platform_device *pdev) { struct it87_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &it87_group); sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt); @@ -1260,6 +1280,10 @@ static void __devinit it87_init_device(struct platform_device *pdev) it87_write_value(data, IT87_REG_FAN_16BIT, tmp | 0x07); } + if (tmp & (1 << 4)) + data->has_fan |= (1 << 3); /* fan4 enabled */ + if (tmp & (1 << 5)) + data->has_fan |= (1 << 4); /* fan5 enabled */ } /* Set current fan mode registers and the default settings for the @@ -1314,21 +1338,21 @@ static struct it87_data *it87_update_device(struct device *dev) data->in[8] = it87_read_value(data, IT87_REG_VIN(8)); - for (i = 0; i < 3; i++) { + for (i = 0; i < 5; i++) { /* Skip disabled fans */ if (!(data->has_fan & (1 << i))) continue; data->fan_min[i] = - it87_read_value(data, IT87_REG_FAN_MIN(i)); + it87_read_value(data, IT87_REG_FAN_MIN[i]); data->fan[i] = it87_read_value(data, - IT87_REG_FAN(i)); + IT87_REG_FAN[i]); /* Add high byte if in 16-bit mode */ if (data->type == it8716 || data->type == it8718) { data->fan[i] |= it87_read_value(data, - IT87_REG_FANX(i)) << 8; + IT87_REG_FANX[i]) << 8; data->fan_min[i] |= it87_read_value(data, - IT87_REG_FANX_MIN(i)) << 8; + IT87_REG_FANX_MIN[i]) << 8; } } for (i = 0; i < 3; i++) { diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 5d8d0ca08fa..bd2bde0ef95 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -38,7 +38,7 @@ #define SEL_CORE 0x04 struct k8temp_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; const char *name; char valid; /* zero until following fields are valid */ @@ -225,10 +225,10 @@ static int __devinit k8temp_probe(struct pci_dev *pdev, if (err) goto exit_remove; - data->class_dev = hwmon_device_register(&pdev->dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -255,7 +255,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev) { struct k8temp_data *data = dev_get_drvdata(&pdev->dev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_input.dev_attr); device_remove_file(&pdev->dev, diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 2162d69a8c0..f207434730d 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -154,7 +154,7 @@ static struct i2c_driver lm63_driver = { struct lm63_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -502,9 +502,9 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -561,7 +561,7 @@ static int lm63_detach_client(struct i2c_client *client) struct lm63_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm63_group); sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1); diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 275d392eca6..dd366889ce9 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -37,7 +37,7 @@ #define DRVNAME "lm70" struct lm70 { - struct class_device *cdev; + struct device *hwmon_dev; struct semaphore sem; }; @@ -81,7 +81,7 @@ static ssize_t lm70_sense_temp(struct device *dev, * So it's equivalent to multiplying by 0.25 * 1000 = 250. */ val = ((int)raw/32) * 250; - status = sprintf(buf, "%+d\n", val); /* millidegrees Celsius */ + status = sprintf(buf, "%d\n", val); /* millidegrees Celsius */ out: up(&p_lm70->sem); return status; @@ -89,6 +89,14 @@ out: static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); +static ssize_t lm70_show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + return sprintf(buf, "lm70\n"); +} + +static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); + /*----------------------------------------------------------------------*/ static int __devinit lm70_probe(struct spi_device *spi) @@ -107,15 +115,16 @@ static int __devinit lm70_probe(struct spi_device *spi) init_MUTEX(&p_lm70->sem); /* sysfs hook */ - p_lm70->cdev = hwmon_device_register(&spi->dev); - if (IS_ERR(p_lm70->cdev)) { + p_lm70->hwmon_dev = hwmon_device_register(&spi->dev); + if (IS_ERR(p_lm70->hwmon_dev)) { dev_dbg(&spi->dev, "hwmon_device_register failed.\n"); - status = PTR_ERR(p_lm70->cdev); + status = PTR_ERR(p_lm70->hwmon_dev); goto out_dev_reg_failed; } dev_set_drvdata(&spi->dev, p_lm70); - if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))) { + if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input)) + || (status = device_create_file(&spi->dev, &dev_attr_name))) { dev_dbg(&spi->dev, "device_create_file failure.\n"); goto out_dev_create_file_failed; } @@ -123,7 +132,8 @@ static int __devinit lm70_probe(struct spi_device *spi) return 0; out_dev_create_file_failed: - hwmon_device_unregister(p_lm70->cdev); + device_remove_file(&spi->dev, &dev_attr_temp1_input); + hwmon_device_unregister(p_lm70->hwmon_dev); out_dev_reg_failed: dev_set_drvdata(&spi->dev, NULL); kfree(p_lm70); @@ -135,7 +145,8 @@ static int __devexit lm70_remove(struct spi_device *spi) struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev); device_remove_file(&spi->dev, &dev_attr_temp1_input); - hwmon_device_unregister(p_lm70->cdev); + device_remove_file(&spi->dev, &dev_attr_name); + hwmon_device_unregister(p_lm70->hwmon_dev); dev_set_drvdata(&spi->dev, NULL); kfree(p_lm70); diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index a40166ffad1..37a8cc032ff 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -50,7 +50,7 @@ static const u8 LM75_REG_TEMP[3] = { /* Each client has this additional data */ struct lm75_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -95,7 +95,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); struct lm75_data *data = i2c_get_clientdata(client); int nr = attr->index; - unsigned long temp = simple_strtoul(buf, NULL, 10); + long temp = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp[nr] = LM75_TEMP_TO_REG(temp); @@ -219,9 +219,9 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -240,7 +240,7 @@ exit: static int lm75_detach_client(struct i2c_client *client) { struct lm75_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm75_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h index af7dc650ee1..7c93454bb4e 100644 --- a/drivers/hwmon/lm75.h +++ b/drivers/hwmon/lm75.h @@ -33,7 +33,7 @@ /* TEMP: 0.001C/bit (-55C to +125C) REG: (0.5C/bit, two's complement) << 7 */ -static inline u16 LM75_TEMP_TO_REG(int temp) +static inline u16 LM75_TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, LM75_TEMP_MIN, LM75_TEMP_MAX); ntemp += (ntemp<0 ? -250 : 250); diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index dd969f1e841..cee5c2e8cfa 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c @@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD_1(lm77); /* Each client has this additional data */ struct lm77_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; unsigned long last_updated; /* In jiffies */ @@ -138,7 +138,7 @@ static ssize_t set_##value(struct device *dev, struct device_attribute *attr, co { \ struct i2c_client *client = to_i2c_client(dev); \ struct lm77_data *data = i2c_get_clientdata(client); \ - long val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->value = val; \ @@ -337,9 +337,9 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -358,7 +358,7 @@ exit: static int lm77_detach_client(struct i2c_client *client) { struct lm77_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm77_group); i2c_detach_client(client); kfree(data); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 6eea3476b90..3f7055ee679 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -131,7 +131,7 @@ static inline int TEMP_FROM_REG(s8 val) the driver field to differentiate between I2C and ISA chips. */ struct lm78_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -438,6 +438,25 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *da, } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct lm78_data *data = lm78_update_device(dev); + int nr = to_sensor_dev_attr(da)->index; + return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); + /* This function is called when: * lm78_driver is inserted (when this module is loaded), for each available adapter @@ -453,36 +472,47 @@ static struct attribute *lm78_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, &sensor_dev_attr_in1_min.dev_attr.attr, &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, &sensor_dev_attr_in2_min.dev_attr.attr, &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_in3_min.dev_attr.attr, &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, &sensor_dev_attr_in4_min.dev_attr.attr, &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, &sensor_dev_attr_in5_min.dev_attr.attr, &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, &sensor_dev_attr_in6_min.dev_attr.attr, &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_max_hyst.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, @@ -585,9 +615,9 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -608,7 +638,7 @@ static int lm78_detach_client(struct i2c_client *client) struct lm78_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm78_group); if ((err = i2c_detach_client(client))) @@ -659,9 +689,9 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev) || (err = device_create_file(&pdev->dev, &dev_attr_name))) goto exit_remove_files; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -681,7 +711,7 @@ static int __devexit lm78_isa_remove(struct platform_device *pdev) { struct lm78_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &lm78_group); device_remove_file(&pdev->dev, &dev_attr_name); release_region(data->client.addr, LM78_EXTENT); diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 064516d824a..063cdba00a8 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -108,7 +108,7 @@ static inline long TEMP_FROM_REG(u16 temp) struct lm80_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -497,9 +497,9 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group))) goto error_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove; } @@ -520,7 +520,7 @@ static int lm80_detach_client(struct i2c_client *client) struct lm80_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm80_group); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 654c0f73464..0336b4572a6 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -144,7 +144,7 @@ static struct i2c_driver lm83_driver = { struct lm83_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -400,9 +400,9 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -424,7 +424,7 @@ static int lm83_detach_client(struct i2c_client *client) struct lm83_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm83_group); sysfs_remove_group(&client->dev.kobj, &lm83_group_opt); diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 20a8c648280..a02480be65f 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -30,6 +30,7 @@ #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-vid.h> +#include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> @@ -122,23 +123,6 @@ I2C_CLIENT_INSMOD_6(lm85b, lm85c, adm1027, adt7463, emc6d100, emc6d102); #define EMC6D102_REG_EXTEND_ADC3 0x87 #define EMC6D102_REG_EXTEND_ADC4 0x88 -#define LM85_ALARM_IN0 0x0001 -#define LM85_ALARM_IN1 0x0002 -#define LM85_ALARM_IN2 0x0004 -#define LM85_ALARM_IN3 0x0008 -#define LM85_ALARM_TEMP1 0x0010 -#define LM85_ALARM_TEMP2 0x0020 -#define LM85_ALARM_TEMP3 0x0040 -#define LM85_ALARM_ALARM2 0x0080 -#define LM85_ALARM_IN4 0x0100 -#define LM85_ALARM_RESERVED 0x0200 -#define LM85_ALARM_FAN1 0x0400 -#define LM85_ALARM_FAN2 0x0800 -#define LM85_ALARM_FAN3 0x1000 -#define LM85_ALARM_FAN4 0x2000 -#define LM85_ALARM_TEMP1_FAULT 0x4000 -#define LM85_ALARM_TEMP3_FAULT 0x8000 - /* Conversions. Rounding and limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments @@ -155,22 +139,26 @@ static int lm85_scaling[] = { /* .001 Volts */ #define INS_TO_REG(n,val) \ SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255) -#define INSEXT_FROM_REG(n,val,ext,scale) \ - SCALE((val)*(scale) + (ext),192*(scale),lm85_scaling[n]) +#define INSEXT_FROM_REG(n,val,ext) \ + SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n]) -#define INS_FROM_REG(n,val) INSEXT_FROM_REG(n,val,0,1) +#define INS_FROM_REG(n,val) SCALE((val), 192, lm85_scaling[n]) /* FAN speed is measured using 90kHz clock */ -#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534)) +static inline u16 FAN_TO_REG(unsigned long val) +{ + if (!val) + return 0xffff; + return SENSORS_LIMIT(5400000 / val, 1, 0xfffe); +} #define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val)) /* Temperature is reported in .001 degC increments */ #define TEMP_TO_REG(val) \ SENSORS_LIMIT(SCALE(val,1000,1),-127,127) -#define TEMPEXT_FROM_REG(val,ext,scale) \ - SCALE((val)*scale + (ext),scale,1000) -#define TEMP_FROM_REG(val) \ - TEMPEXT_FROM_REG(val,0,1) +#define TEMPEXT_FROM_REG(val,ext) \ + SCALE(((val) << 4) + (ext), 16, 1000) +#define TEMP_FROM_REG(val) ((val) * 1000) #define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255)) #define PWM_FROM_REG(val) (val) @@ -328,7 +316,7 @@ struct lm85_autofan { The structure is dynamically allocated. */ struct lm85_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -350,7 +338,6 @@ struct lm85_data { u8 tach_mode; /* Register encoding, combined */ u8 temp_ext[3]; /* Decoded values */ u8 in_ext[8]; /* Decoded values */ - u8 adc_scale; /* ADC Extended bits scaling factor */ u8 fan_ppr; /* Register value */ u8 smooth[3]; /* Register encoding */ u8 vid; /* Register value */ @@ -387,22 +374,29 @@ static struct i2c_driver lm85_driver = { /* 4 Fans */ -static ssize_t show_fan(struct device *dev, char *buf, int nr) +static ssize_t show_fan(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan[nr]) ); } -static ssize_t show_fan_min(struct device *dev, char *buf, int nr) + +static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr]) ); } -static ssize_t set_fan_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); - long val = simple_strtol(buf, NULL, 10); + unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); data->fan_min[nr] = FAN_TO_REG(val); @@ -412,23 +406,10 @@ static ssize_t set_fan_min(struct device *dev, const char *buf, } #define show_fan_offset(offset) \ -static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset - 1); \ -} \ -static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_fan_min(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, \ - NULL); \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_##offset##_min, set_fan_##offset##_min); +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, set_fan_min, offset - 1) show_fan_offset(1); show_fan_offset(2); @@ -457,7 +438,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct lm85_data *data = lm85_update_device(dev); + struct lm85_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } @@ -482,16 +463,46 @@ static ssize_t show_alarms_reg(struct device *dev, struct device_attribute *attr static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct lm85_data *data = lm85_update_device(dev); + return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 18); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 13); + /* pwm */ -static ssize_t show_pwm(struct device *dev, char *buf, int nr) +static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", PWM_FROM_REG(data->pwm[nr]) ); } -static ssize_t set_pwm(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -502,8 +513,11 @@ static ssize_t set_pwm(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_enable(struct device *dev, struct device_attribute + *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); int pwm_zone; @@ -512,23 +526,10 @@ static ssize_t show_pwm_enable(struct device *dev, char *buf, int nr) } #define show_pwm_reg(offset) \ -static ssize_t show_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm_enable##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_enable(dev, buf, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm_##offset, set_pwm_##offset); \ -static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ - show_pwm_enable##offset, NULL); +static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ + show_pwm, set_pwm, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO, \ + show_pwm_enable, NULL, offset - 1) show_pwm_reg(1); show_pwm_reg(2); @@ -536,22 +537,28 @@ show_pwm_reg(3); /* Voltages */ -static ssize_t show_in(struct device *dev, char *buf, int nr) +static ssize_t show_in(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf( buf, "%d\n", INSEXT_FROM_REG(nr, data->in[nr], - data->in_ext[nr], - data->adc_scale) ); + data->in_ext[nr])); } -static ssize_t show_in_min(struct device *dev, char *buf, int nr) + +static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_min[nr]) ); } -static ssize_t set_in_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -562,14 +569,19 @@ static ssize_t set_in_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_in_max(struct device *dev, char *buf, int nr) + +static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", INS_FROM_REG(nr, data->in_max[nr]) ); } -static ssize_t set_in_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -580,59 +592,47 @@ static ssize_t set_in_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define show_in_reg(offset) \ -static ssize_t show_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_min(dev, buf, offset); \ -} \ -static ssize_t show_in_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_max(dev, buf, offset); \ -} \ -static ssize_t set_in_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_min(dev, buf, count, offset); \ -} \ -static ssize_t set_in_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_in_max(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in_##offset, \ - NULL); \ -static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_##offset##_min, set_in_##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_##offset##_max, set_in_##offset##_max); +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ + show_in_max, set_in_max, offset) show_in_reg(0); show_in_reg(1); show_in_reg(2); show_in_reg(3); show_in_reg(4); +show_in_reg(5); +show_in_reg(6); +show_in_reg(7); /* Temps */ -static ssize_t show_temp(struct device *dev, char *buf, int nr) +static ssize_t show_temp(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMPEXT_FROM_REG(data->temp[nr], - data->temp_ext[nr], - data->adc_scale) ); + data->temp_ext[nr])); } -static ssize_t show_temp_min(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_min[nr]) ); } -static ssize_t set_temp_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -643,14 +643,19 @@ static ssize_t set_temp_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_max(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->temp_max[nr]) ); } -static ssize_t set_temp_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -661,35 +666,14 @@ static ssize_t set_temp_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define show_temp_reg(offset) \ -static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t show_temp_##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t set_temp_##offset##_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_max(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, \ - NULL); \ -static DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_min, set_temp_##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_##offset##_max, set_temp_##offset##_max); +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ + show_temp_max, set_temp_max, offset - 1); show_temp_reg(1); show_temp_reg(2); @@ -698,14 +682,18 @@ show_temp_reg(3); /* Automatic PWM control */ -static ssize_t show_pwm_auto_channels(struct device *dev, char *buf, int nr) +static ssize_t show_pwm_auto_channels(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", ZONE_FROM_REG(data->autofan[nr].config)); } -static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_channels(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -718,14 +706,19 @@ static ssize_t set_pwm_auto_channels(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_min(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", PWM_FROM_REG(data->autofan[nr].min_pwm)); } -static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_min(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -737,14 +730,19 @@ static ssize_t set_pwm_auto_pwm_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_minctl(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", data->autofan[nr].min_off); } -static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -760,14 +758,19 @@ static ssize_t set_pwm_auto_pwm_minctl(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_pwm_auto_pwm_freq(struct device *dev, char *buf, int nr) + +static ssize_t show_pwm_auto_pwm_freq(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", FREQ_FROM_REG(data->autofan[nr].freq)); } -static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_pwm_auto_pwm_freq(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -781,74 +784,40 @@ static ssize_t set_pwm_auto_pwm_freq(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define pwm_auto(offset) \ -static ssize_t show_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_channels(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_channels (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_channels(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_minctl(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_minctl (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_minctl(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_pwm##offset##_auto_pwm_freq (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_pwm_auto_pwm_freq(dev, buf, offset - 1); \ -} \ -static ssize_t set_pwm##offset##_auto_pwm_freq(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_pwm_auto_pwm_freq(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(pwm##offset##_auto_channels, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_channels, \ - set_pwm##offset##_auto_channels); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_min, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_min, \ - set_pwm##offset##_auto_pwm_min); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_minctl, \ - set_pwm##offset##_auto_pwm_minctl); \ -static DEVICE_ATTR(pwm##offset##_auto_pwm_freq, S_IRUGO | S_IWUSR, \ - show_pwm##offset##_auto_pwm_freq, \ - set_pwm##offset##_auto_pwm_freq); +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels, \ + S_IRUGO | S_IWUSR, show_pwm_auto_channels, \ + set_pwm_auto_channels, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_min, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_min, \ + set_pwm_auto_pwm_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_minctl, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_minctl, \ + set_pwm_auto_pwm_minctl, offset - 1); \ +static SENSOR_DEVICE_ATTR(pwm##offset##_auto_pwm_freq, \ + S_IRUGO | S_IWUSR, show_pwm_auto_pwm_freq, \ + set_pwm_auto_pwm_freq, offset - 1); + pwm_auto(1); pwm_auto(2); pwm_auto(3); /* Temperature settings for automatic PWM control */ -static ssize_t show_temp_auto_temp_off(struct device *dev, char *buf, int nr) +static ssize_t show_temp_auto_temp_off(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) - HYST_FROM_REG(data->zone[nr].hyst)); } -static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_off(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; @@ -871,14 +840,19 @@ static ssize_t set_temp_auto_temp_off(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_min(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_min(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) ); } -static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_min(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -913,15 +887,20 @@ static ssize_t set_temp_auto_temp_min(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_max(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_max(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].limit) + RANGE_FROM_REG(data->zone[nr].range)); } -static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_max(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); int min; @@ -938,14 +917,19 @@ static ssize_t set_temp_auto_temp_max(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } -static ssize_t show_temp_auto_temp_crit(struct device *dev, char *buf, int nr) + +static ssize_t show_temp_auto_temp_crit(struct device *dev, + struct device_attribute *attr, char *buf) { + int nr = to_sensor_dev_attr(attr)->index; struct lm85_data *data = lm85_update_device(dev); return sprintf(buf,"%d\n", TEMP_FROM_REG(data->zone[nr].critical)); } -static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, - size_t count, int nr) + +static ssize_t set_temp_auto_temp_crit(struct device *dev, + struct device_attribute *attr,const char *buf, size_t count) { + int nr = to_sensor_dev_attr(attr)->index; struct i2c_client *client = to_i2c_client(dev); struct lm85_data *data = i2c_get_clientdata(client); long val = simple_strtol(buf, NULL, 10); @@ -957,59 +941,21 @@ static ssize_t set_temp_auto_temp_crit(struct device *dev, const char *buf, mutex_unlock(&data->update_lock); return count; } + #define temp_auto(offset) \ -static ssize_t show_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_off(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_off (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_off(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_min(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_min (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_min(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_max(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_max (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_max(dev, buf, count, offset - 1); \ -} \ -static ssize_t show_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_temp_auto_temp_crit(dev, buf, offset - 1); \ -} \ -static ssize_t set_temp##offset##_auto_temp_crit (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return set_temp_auto_temp_crit(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(temp##offset##_auto_temp_off, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_off, \ - set_temp##offset##_auto_temp_off); \ -static DEVICE_ATTR(temp##offset##_auto_temp_min, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_min, \ - set_temp##offset##_auto_temp_min); \ -static DEVICE_ATTR(temp##offset##_auto_temp_max, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_max, \ - set_temp##offset##_auto_temp_max); \ -static DEVICE_ATTR(temp##offset##_auto_temp_crit, S_IRUGO | S_IWUSR, \ - show_temp##offset##_auto_temp_crit, \ - set_temp##offset##_auto_temp_crit); +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_off, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_off, \ + set_temp_auto_temp_off, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_min, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_min, \ + set_temp_auto_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_max, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_max, \ + set_temp_auto_temp_max, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_auto_temp_crit, \ + S_IRUGO | S_IWUSR, show_temp_auto_temp_crit, \ + set_temp_auto_temp_crit, offset - 1); + temp_auto(1); temp_auto(2); temp_auto(3); @@ -1022,69 +968,87 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *lm85_attributes[] = { - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan3_input.attr, - &dev_attr_fan4_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan4_min.attr, - &dev_attr_pwm1.attr, - &dev_attr_pwm2.attr, - &dev_attr_pwm3.attr, - &dev_attr_pwm1_enable.attr, - &dev_attr_pwm2_enable.attr, - &dev_attr_pwm3_enable.attr, - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, - &dev_attr_in3_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in1_min.attr, - &dev_attr_in2_min.attr, - &dev_attr_in3_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_max.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp3_input.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp3_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp3_max.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, + + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, + &sensor_dev_attr_pwm3.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm2_enable.dev_attr.attr, + &sensor_dev_attr_pwm3_enable.dev_attr.attr, + + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, + + &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_channels.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_minctl.dev_attr.attr, + &sensor_dev_attr_pwm1_auto_pwm_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_auto_pwm_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_auto_pwm_freq.dev_attr.attr, + + &sensor_dev_attr_temp1_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_off.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_min.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_max.dev_attr.attr, + &sensor_dev_attr_temp1_auto_temp_crit.dev_attr.attr, + &sensor_dev_attr_temp2_auto_temp_crit.dev_attr.attr, + &sensor_dev_attr_temp3_auto_temp_crit.dev_attr.attr, + &dev_attr_vrm.attr, &dev_attr_cpu0_vid.attr, &dev_attr_alarms.attr, - &dev_attr_pwm1_auto_channels.attr, - &dev_attr_pwm2_auto_channels.attr, - &dev_attr_pwm3_auto_channels.attr, - &dev_attr_pwm1_auto_pwm_min.attr, - &dev_attr_pwm2_auto_pwm_min.attr, - &dev_attr_pwm3_auto_pwm_min.attr, - &dev_attr_pwm1_auto_pwm_minctl.attr, - &dev_attr_pwm2_auto_pwm_minctl.attr, - &dev_attr_pwm3_auto_pwm_minctl.attr, - &dev_attr_pwm1_auto_pwm_freq.attr, - &dev_attr_pwm2_auto_pwm_freq.attr, - &dev_attr_pwm3_auto_pwm_freq.attr, - &dev_attr_temp1_auto_temp_off.attr, - &dev_attr_temp2_auto_temp_off.attr, - &dev_attr_temp3_auto_temp_off.attr, - &dev_attr_temp1_auto_temp_min.attr, - &dev_attr_temp2_auto_temp_min.attr, - &dev_attr_temp3_auto_temp_min.attr, - &dev_attr_temp1_auto_temp_max.attr, - &dev_attr_temp2_auto_temp_max.attr, - &dev_attr_temp3_auto_temp_max.attr, - &dev_attr_temp1_auto_temp_crit.attr, - &dev_attr_temp2_auto_temp_crit.attr, - &dev_attr_temp3_auto_temp_crit.attr, - NULL }; @@ -1092,16 +1056,36 @@ static const struct attribute_group lm85_group = { .attrs = lm85_attributes, }; -static struct attribute *lm85_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, +static struct attribute *lm85_attributes_in4[] = { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + NULL +}; + +static const struct attribute_group lm85_group_in4 = { + .attrs = lm85_attributes_in4, +}; +static struct attribute *lm85_attributes_in567[] = { + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, NULL }; -static const struct attribute_group lm85_group_opt = { - .attrs = lm85_attributes_opt, +static const struct attribute_group lm85_group_in567 = { + .attrs = lm85_attributes_in567, }; static int lm85_detect(struct i2c_adapter *adapter, int address, @@ -1249,17 +1233,19 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, as a sixth digital VID input rather than an analog input. */ data->vid = lm85_read_value(new_client, LM85_REG_VID); if (!(kind == adt7463 && (data->vid & 0x80))) - if ((err = device_create_file(&new_client->dev, - &dev_attr_in4_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_min)) - || (err = device_create_file(&new_client->dev, - &dev_attr_in4_max))) + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm85_group_in4))) goto ERROR3; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + /* The EMC6D100 has 3 additional voltage inputs */ + if (kind == emc6d100) + if ((err = sysfs_create_group(&new_client->dev.kobj, + &lm85_group_in567))) + goto ERROR3; + + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR3; } @@ -1268,7 +1254,9 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, /* Error out and cleanup code */ ERROR3: sysfs_remove_group(&new_client->dev.kobj, &lm85_group); - sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt); + sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in4); + if (kind == emc6d100) + sysfs_remove_group(&new_client->dev.kobj, &lm85_group_in567); ERROR2: i2c_detach_client(new_client); ERROR1: @@ -1280,9 +1268,11 @@ static int lm85_detect(struct i2c_adapter *adapter, int address, static int lm85_detach_client(struct i2c_client *client) { struct lm85_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm85_group); - sysfs_remove_group(&client->dev.kobj, &lm85_group_opt); + sysfs_remove_group(&client->dev.kobj, &lm85_group_in4); + if (data->type == emc6d100) + sysfs_remove_group(&client->dev.kobj, &lm85_group_in567); i2c_detach_client(client); kfree(data); return 0; @@ -1405,6 +1395,8 @@ static struct lm85_data *lm85_update_device(struct device *dev) /* Have to read extended bits first to "freeze" the * more significant bits that are read later. + * There are 2 additional resolution bits per channel and we + * have room for 4, so we shift them to the left. */ if ( (data->type == adm1027) || (data->type == adt7463) ) { int ext1 = lm85_read_value(client, @@ -1414,18 +1406,12 @@ static struct lm85_data *lm85_update_device(struct device *dev) int val = (ext1 << 8) + ext2; for(i = 0; i <= 4; i++) - data->in_ext[i] = (val>>(i * 2))&0x03; + data->in_ext[i] = ((val>>(i * 2))&0x03) << 2; for(i = 0; i <= 2; i++) - data->temp_ext[i] = (val>>((i + 5) * 2))&0x03; + data->temp_ext[i] = (val>>((i + 4) * 2))&0x0c; } - /* adc_scale is 2^(number of LSBs). There are 4 extra bits in - the emc6d102 and 2 in the adt7463 and adm1027. In all - other chips ext is always 0 and the value of scale is - irrelevant. So it is left in 4*/ - data->adc_scale = (data->type == emc6d102 ) ? 16 : 4; - data->vid = lm85_read_value(client, LM85_REG_VID); for (i = 0; i <= 3; ++i) { diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 988ae1c4aad..28cdff0c556 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -58,6 +58,7 @@ #include <linux/jiffies.h> #include <linux/i2c.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -129,7 +130,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; (((val) < 0 ? (val)-500 : (val)+500) / 1000)) #define FAN_FROM_REG(reg,div) ((reg) == 255 || (reg) == 0 ? 0 : \ - 1350000 + (reg)*(div) / 2) / ((reg)*(div)) + (1350000 + (reg)*(div) / 2) / ((reg)*(div))) #define FAN_TO_REG(val,div) ((val)*(div) * 255 <= 1350000 ? 255 : \ (1350000 + (val)*(div) / 2) / ((val)*(div))) @@ -145,7 +146,7 @@ static u8 LM87_REG_TEMP_LOW[3] = { 0x3A, 0x38, 0x2C }; #define CHAN_NO_FAN(nr) (1 << (nr)) #define CHAN_TEMP3 (1 << 2) #define CHAN_VCC_5V (1 << 3) -#define CHAN_NO_VID (1 << 8) +#define CHAN_NO_VID (1 << 7) /* * Functions declaration @@ -176,7 +177,7 @@ static struct i2c_driver lm87_driver = { struct lm87_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -500,7 +501,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct lm87_data *data = lm87_update_device(dev); + struct lm87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -531,6 +532,29 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct lm87_data *data = lm87_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 14); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 15); + /* * Real code */ @@ -546,24 +570,31 @@ static struct attribute *lm87_attributes[] = { &dev_attr_in1_input.attr, &dev_attr_in1_min.attr, &dev_attr_in1_max.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &dev_attr_in2_input.attr, &dev_attr_in2_min.attr, &dev_attr_in2_max.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &dev_attr_in3_input.attr, &dev_attr_in3_min.attr, &dev_attr_in3_max.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &dev_attr_in4_input.attr, &dev_attr_in4_min.attr, &dev_attr_in4_max.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &dev_attr_temp1_input.attr, &dev_attr_temp1_max.attr, &dev_attr_temp1_min.attr, &dev_attr_temp1_crit.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &dev_attr_temp2_input.attr, &dev_attr_temp2_max.attr, &dev_attr_temp2_min.attr, &dev_attr_temp2_crit.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_aout_output.attr, @@ -579,30 +610,38 @@ static struct attribute *lm87_attributes_opt[] = { &dev_attr_in6_input.attr, &dev_attr_in6_min.attr, &dev_attr_in6_max.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &dev_attr_fan1_input.attr, &dev_attr_fan1_min.attr, &dev_attr_fan1_div.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &dev_attr_in7_input.attr, &dev_attr_in7_min.attr, &dev_attr_in7_max.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, &dev_attr_fan2_input.attr, &dev_attr_fan2_min.attr, &dev_attr_fan2_div.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &dev_attr_temp3_input.attr, &dev_attr_temp3_max.attr, &dev_attr_temp3_min.attr, &dev_attr_temp3_crit.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, &dev_attr_in0_max.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &dev_attr_in5_input.attr, &dev_attr_in5_min.attr, &dev_attr_in5_max.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -690,7 +729,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in6_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in6_max))) + &dev_attr_in6_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in6_alarm.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -698,7 +739,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_fan1_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_fan1_div))) + &dev_attr_fan1_div)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan1_alarm.dev_attr))) goto exit_remove; } @@ -708,7 +751,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in7_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in7_max))) + &dev_attr_in7_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in7_alarm.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -716,7 +761,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_fan2_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_fan2_div))) + &dev_attr_fan2_div)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_fan2_alarm.dev_attr))) goto exit_remove; } @@ -728,7 +775,11 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_temp3_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_temp3_crit))) + &dev_attr_temp3_crit)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_alarm.dev_attr)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp3_fault.dev_attr))) goto exit_remove; } else { if ((err = device_create_file(&new_client->dev, @@ -738,11 +789,15 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) || (err = device_create_file(&new_client->dev, &dev_attr_in0_max)) || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in0_alarm.dev_attr)) + || (err = device_create_file(&new_client->dev, &dev_attr_in5_input)) || (err = device_create_file(&new_client->dev, &dev_attr_in5_min)) || (err = device_create_file(&new_client->dev, - &dev_attr_in5_max))) + &dev_attr_in5_max)) + || (err = device_create_file(&new_client->dev, + &sensor_dev_attr_in5_alarm.dev_attr))) goto exit_remove; } @@ -755,9 +810,9 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -816,7 +871,7 @@ static int lm87_detach_client(struct i2c_client *client) struct lm87_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm87_group); sysfs_remove_group(&client->dev.kobj, &lm87_group_opt); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index af541d67245..960df9fa75a 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -41,7 +41,8 @@ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578 * Note that there is no easy way to differentiate between the three * variants. The extra address and features of the MAX6659 are not - * supported by this driver. + * supported by this driver. These chips lack the remote temperature + * offset feature. * * This driver also supports the MAX6680 and MAX6681, two other sensor * chips made by Maxim. These are quite similar to the other Maxim @@ -214,7 +215,7 @@ static struct i2c_driver lm90_driver = { struct lm90_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -226,9 +227,10 @@ struct lm90_data { 2: local high limit 3: local critical limit 4: remote critical limit */ - s16 temp11[3]; /* 0: remote input + s16 temp11[4]; /* 0: remote input 1: remote low limit - 2: remote high limit */ + 2: remote high limit + 3: remote offset (except max6657) */ u8 temp_hyst; u8 alarms; /* bitvector */ }; @@ -282,11 +284,13 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr, static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { - static const u8 reg[4] = { + static const u8 reg[6] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL, LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL, + LM90_REG_W_REMOTE_OFFSH, + LM90_REG_W_REMOTE_OFFSL, }; struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); @@ -367,6 +371,8 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8, static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst, set_temphyst, 3); static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, + set_temp11, 3); /* Individual alarm files */ static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0); @@ -652,10 +658,15 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) &dev_attr_pec))) goto exit_remove_files; } + if (data->kind != max6657) { + if ((err = device_create_file(&new_client->dev, + &sensor_dev_attr_temp2_offset.dev_attr))) + goto exit_remove_files; + } - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -707,9 +718,12 @@ static int lm90_detach_client(struct i2c_client *client) struct lm90_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm90_group); device_remove_file(&client->dev, &dev_attr_pec); + if (data->kind != max6657) + device_remove_file(&client->dev, + &sensor_dev_attr_temp2_offset.dev_attr); if ((err = i2c_detach_client(client))) return err; @@ -763,6 +777,13 @@ static struct lm90_data *lm90_update_device(struct device *dev) if (lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH, &newh) == 0 && lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL, &l) == 0) data->temp11[2] = (newh << 8) | l; + if (data->kind != max6657) { + if (lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSH, + &newh) == 0 + && lm90_read_reg(client, LM90_REG_R_REMOTE_OFFSL, + &l) == 0) + data->temp11[3] = (newh << 8) | l; + } lm90_read_reg(client, LM90_REG_R_STATUS, &data->alarms); data->last_updated = jiffies; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index 30b536333f1..61d1bd1d5b6 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -96,7 +96,7 @@ static struct i2c_driver lm92_driver; /* Client data (each client gets its own) */ struct lm92_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -379,9 +379,9 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -409,7 +409,7 @@ static int lm92_detach_client(struct i2c_client *client) struct lm92_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm92_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index d84f8bf6f28..ea61946a4bf 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -201,7 +201,7 @@ struct block1_t { */ struct lm93_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; /* In jiffies */ @@ -413,7 +413,7 @@ static int LM93_TEMP_FROM_REG(u8 reg) /* TEMP: 1/1000 degrees C (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 LM93_TEMP_TO_REG(int temp) +static u8 LM93_TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -1268,7 +1268,7 @@ static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_lim[nr].min = LM93_TEMP_TO_REG(val); @@ -1298,7 +1298,7 @@ static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->temp_lim[nr].max = LM93_TEMP_TO_REG(val); @@ -1329,7 +1329,7 @@ static ssize_t store_temp_auto_base(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->block10.base[nr] = LM93_TEMP_TO_REG(val); @@ -1360,7 +1360,7 @@ static ssize_t store_temp_auto_boost(struct device *dev, int nr = (to_sensor_dev_attr(attr))->index; struct i2c_client *client = to_i2c_client(dev); struct lm93_data *data = i2c_get_clientdata(client); - u32 val = simple_strtoul(buf, NULL, 10); + long val = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); data->boost[nr] = LM93_TEMP_TO_REG(val); @@ -2078,8 +2078,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr])); } -static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0); -static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1); +static SENSOR_DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL, 0); +static SENSOR_DEVICE_ATTR(cpu1_vid, S_IRUGO, show_vid, NULL, 1); static ssize_t show_prochot(struct device *dev, struct device_attribute *attr, char *buf) @@ -2431,8 +2431,8 @@ static struct attribute *lm93_attrs[] = { &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr, &dev_attr_pwm_auto_prochot_ramp.attr, &dev_attr_pwm_auto_vrdhot_ramp.attr, - &sensor_dev_attr_vid1.dev_attr.attr, - &sensor_dev_attr_vid2.dev_attr.attr, + &sensor_dev_attr_cpu0_vid.dev_attr.attr, + &sensor_dev_attr_cpu1_vid.dev_attr.attr, &sensor_dev_attr_prochot1.dev_attr.attr, &sensor_dev_attr_prochot2.dev_attr.attr, &sensor_dev_attr_prochot1_avg.dev_attr.attr, @@ -2590,11 +2590,11 @@ static int lm93_detect(struct i2c_adapter *adapter, int address, int kind) goto err_detach; /* Register hwmon driver class */ - data->class_dev = hwmon_device_register(&client->dev); - if ( !IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&client->dev); + if ( !IS_ERR(data->hwmon_dev)) return 0; - err = PTR_ERR(data->class_dev); + err = PTR_ERR(data->hwmon_dev); dev_err(&client->dev, "error registering hwmon device.\n"); sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp); err_detach: @@ -2619,7 +2619,7 @@ static int lm93_detach_client(struct i2c_client *client) struct lm93_data *data = i2c_get_clientdata(client); int err = 0; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp); err = i2c_detach_client(client); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index 2f58f651f03..38a44c3d6ce 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -105,7 +105,7 @@ static struct i2c_driver max1619_driver = { struct max1619_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -293,9 +293,9 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group))) goto exit_detach; - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -331,7 +331,7 @@ static int max1619_detach_client(struct i2c_client *client) struct max1619_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &max1619_group); if ((err = i2c_detach_client(client))) diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index 8415664f33c..755570c1f4e 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -128,7 +128,7 @@ static struct i2c_driver max6650_driver = { struct max6650_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -523,11 +523,11 @@ static int max6650_detect(struct i2c_adapter *adapter, int address, int kind) if (err) goto err_detach; - data->class_dev = hwmon_device_register(&client->dev); - if (!IS_ERR(data->class_dev)) + data->hwmon_dev = hwmon_device_register(&client->dev); + if (!IS_ERR(data->hwmon_dev)) return 0; - err = PTR_ERR(data->class_dev); + err = PTR_ERR(data->hwmon_dev); dev_err(&client->dev, "error registering hwmon device.\n"); sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); err_detach: @@ -543,7 +543,7 @@ static int max6650_detach_client(struct i2c_client *client) int err; sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); err = i2c_detach_client(client); if (!err) kfree(data); diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index f57c75d59a5..9d660133d51 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -180,7 +180,7 @@ static inline u8 PWM_TO_REG(int val, int inv) struct pc87360_data { const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -500,7 +500,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct pc87360_data *data = pc87360_update_device(dev); + struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -1054,9 +1054,9 @@ static int __devinit pc87360_probe(struct platform_device *pdev) if ((err = device_create_file(dev, &dev_attr_name))) goto ERROR3; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR3; } return 0; @@ -1083,7 +1083,7 @@ static int __devexit pc87360_remove(struct platform_device *pdev) struct pc87360_data *data = platform_get_drvdata(pdev); int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &dev_attr_name); sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index 2915bc4ad0d..d40509ad6ae 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -42,7 +42,7 @@ static struct platform_device *pdev; device is using banked registers) and the register cache (needed to keep the data in the registers and the cache in sync at any time). */ struct pc87427_data { - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; int address[2]; const char *name; @@ -454,9 +454,9 @@ static int __devinit pc87427_probe(struct platform_device *pdev) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(&pdev->dev, "Class registration failed (%d)\n", err); goto exit_remove_files; } @@ -484,7 +484,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev) struct resource *res; int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&pdev->dev, &dev_attr_name); for (i = 0; i < 8; i++) { if (!(data->fan_enabled & (1 << i))) diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 92956eb3f3c..860b71ccbb8 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -163,7 +163,7 @@ static inline u8 DIV_TO_REG(int val) struct sis5595_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -517,7 +517,7 @@ static int __devinit sis5595_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); /* Check revision and pin registers to determine whether 4 or 5 voltages */ - pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision); + data->revision = s_bridge->revision; /* 4 voltages, 1 temp */ data->maxins = 3; if (data->revision >= REV2MIN) { @@ -557,9 +557,9 @@ static int __devinit sis5595_probe(struct platform_device *pdev) goto exit_remove_files; } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -580,7 +580,7 @@ static int __devexit sis5595_remove(struct platform_device *pdev) { struct sis5595_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group); sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt); @@ -739,11 +739,10 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev, int *i; for (i = blacklist; *i != 0; i++) { - struct pci_dev *dev; - dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL); - if (dev) { - dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); - pci_dev_put(dev); + struct pci_dev *d; + if ((d = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL))) { + dev_err(&d->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i); + pci_dev_put(d); return -ENODEV; } } diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 45266b30ce1..0b57d2ea2cf 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -94,7 +94,7 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80}; struct smsc47b397_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -222,7 +222,7 @@ static int __devexit smsc47b397_remove(struct platform_device *pdev) struct smsc47b397_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group); res = platform_get_resource(pdev, IORESOURCE_IO, 0); release_region(res->start, SMSC_EXTENT); @@ -272,9 +272,9 @@ static int __devinit smsc47b397_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group))) goto error_free; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove; } diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index d3181967f16..a10a380868e 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -116,7 +116,7 @@ struct smsc47m1_data { unsigned short addr; const char *name; enum chips type; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; unsigned long last_updated; /* In jiffies */ @@ -553,7 +553,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_fan3_div.dev_attr))) goto error_remove_files; - } else + } else if (data->type == smsc47m2) dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n"); if (pwm1) { @@ -580,7 +580,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) || (err = device_create_file(dev, &sensor_dev_attr_pwm3_enable.dev_attr))) goto error_remove_files; - } else + } else if (data->type == smsc47m2) dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n"); if ((err = device_create_file(dev, &dev_attr_alarms))) @@ -588,9 +588,9 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev) if ((err = device_create_file(dev, &dev_attr_name))) goto error_remove_files; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error_remove_files; } @@ -611,7 +611,7 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev) struct smsc47m1_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); res = platform_get_resource(pdev, IORESOURCE_IO, 0); diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index d3a3ba04cb0..b8755265258 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -97,7 +97,7 @@ static inline int TEMP_FROM_REG(s8 val) struct smsc47m192_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -334,7 +334,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { - struct smsc47m192_data *data = smsc47m192_update_device(dev); + struct smsc47m192_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -553,9 +553,9 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address, goto exit_remove_files; } - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -577,7 +577,7 @@ static int smsc47m192_detach_client(struct i2c_client *client) struct smsc47m192_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &smsc47m192_group); sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4); diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c index 9395b52d9b9..04dd7699b3a 100644 --- a/drivers/hwmon/thmc50.c +++ b/drivers/hwmon/thmc50.c @@ -46,6 +46,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs " #define THMC50_REG_COMPANY_ID 0x3E #define THMC50_REG_DIE_CODE 0x3F #define THMC50_REG_ANALOG_OUT 0x19 +/* + * The mirror status register cannot be used as + * reading it does not clear alarms. + */ +#define THMC50_REG_INTR 0x41 const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 }; const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C }; @@ -56,7 +61,7 @@ const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B }; /* Each client has this additional data */ struct thmc50_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; enum chips type; @@ -69,6 +74,7 @@ struct thmc50_data { s8 temp_max[3]; s8 temp_min[3]; u8 analog_out; + u8 alarms; }; static int thmc50_attach_adapter(struct i2c_adapter *adapter); @@ -180,6 +186,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct thmc50_data *data = thmc50_update_device(dev); + + return sprintf(buf, "%u\n", (data->alarms >> index) & 1); +} + #define temp_reg(offset) \ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \ NULL, offset - 1); \ @@ -192,6 +207,12 @@ temp_reg(1); temp_reg(2); temp_reg(3); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2); + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out, set_analog_out, 0); static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0); @@ -200,9 +221,12 @@ static struct attribute *thmc50_attributes[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_min.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, NULL @@ -213,15 +237,17 @@ static const struct attribute_group thmc50_group = { }; /* for ADM1022 3rd temperature mode */ -static struct attribute *adm1022_attributes[] = { +static struct attribute *temp3_attributes[] = { &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, NULL }; -static const struct attribute_group adm1022_group = { - .attrs = adm1022_attributes, +static const struct attribute_group temp3_group = { + .attrs = temp3_attributes, }; static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) @@ -233,7 +259,7 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) struct thmc50_data *data; struct device *dev; int err = 0; - const char *type_name = ""; + const char *type_name; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { pr_debug("thmc50: detect failed, " @@ -283,13 +309,9 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n"); goto exit_free; } - pr_debug("thmc50: Detected %s (version %x, revision %x)\n", - type_name, (revision >> 4) - 0xc, revision & 0xf); data->type = kind; - if (kind == thmc50) - type_name = "thmc50"; - else if (kind == adm1022) { + if (kind == adm1022) { int id = i2c_adapter_id(client->adapter); int i; @@ -302,7 +324,11 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) data->has_temp3 = 1; break; } + } else { + type_name = "thmc50"; } + pr_debug("thmc50: Detected %s (version %x, revision %x)\n", + type_name, (revision >> 4) - 0xc, revision & 0xf); /* Fill in the remaining client fields & put it into the global list */ strlcpy(client->name, type_name, I2C_NAME_SIZE); @@ -319,23 +345,23 @@ static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_detach; /* Register ADM1022 sysfs hooks */ - if (data->type == adm1022) + if (data->has_temp3) if ((err = sysfs_create_group(&client->dev.kobj, - &adm1022_group))) + &temp3_group))) goto exit_remove_sysfs_thmc50; /* Register a new directory entry with module sensors */ - data->class_dev = hwmon_device_register(&client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_sysfs; } return 0; exit_remove_sysfs: - if (data->type == adm1022) - sysfs_remove_group(&client->dev.kobj, &adm1022_group); + if (data->has_temp3) + sysfs_remove_group(&client->dev.kobj, &temp3_group); exit_remove_sysfs_thmc50: sysfs_remove_group(&client->dev.kobj, &thmc50_group); exit_detach: @@ -358,10 +384,10 @@ static int thmc50_detach_client(struct i2c_client *client) struct thmc50_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &thmc50_group); - if (data->type == adm1022) - sysfs_remove_group(&client->dev.kobj, &adm1022_group); + if (data->has_temp3) + sysfs_remove_group(&client->dev.kobj, &temp3_group); if ((err = i2c_detach_client(client))) return err; @@ -414,6 +440,8 @@ static struct thmc50_data *thmc50_update_device(struct device *dev) } data->analog_out = i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT); + data->alarms = + i2c_smbus_read_byte_data(client, THMC50_REG_INTR); data->last_updated = jiffies; data->valid = 1; } diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 696c8a2e537..8f63dada601 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -294,7 +294,7 @@ static inline long TEMP_FROM_REG10(u16 val) struct via686a_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -627,9 +627,9 @@ static int __devinit via686a_probe(struct platform_device *pdev) if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group))) goto exit_free; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -648,7 +648,7 @@ static int __devexit via686a_remove(struct platform_device *pdev) { struct via686a_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &via686a_group); release_region(data->addr, VIA686A_EXTENT); diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index 9f3e332c5b7..e69416465e6 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -108,7 +108,7 @@ static const u8 bitalarmfan[] = {6, 7}; struct vt1211_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -1191,9 +1191,9 @@ static int __devinit vt1211_probe(struct platform_device *pdev) } /* Register device */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); dev_err(dev, "Class registration failed (%d)\n", err); goto EXIT_DEV_REMOVE_SILENT; } @@ -1217,7 +1217,7 @@ static int __devexit vt1211_remove(struct platform_device *pdev) struct vt1211_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); vt1211_remove_sysfs(pdev); platform_set_drvdata(pdev, NULL); kfree(data); diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 3e63eaf1904..2196a84603f 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -148,7 +148,7 @@ struct vt8231_data { const char *name; struct mutex update_lock; - struct class_device *class_dev; + struct device *hwmon_dev; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -676,7 +676,7 @@ static struct pci_driver vt8231_pci_driver = { .probe = vt8231_pci_probe, }; -int vt8231_probe(struct platform_device *pdev) +static int vt8231_probe(struct platform_device *pdev) { struct resource *res; struct vt8231_data *data; @@ -726,9 +726,9 @@ int vt8231_probe(struct platform_device *pdev) } } - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } return 0; @@ -756,7 +756,7 @@ static int __devexit vt8231_remove(struct platform_device *pdev) struct vt8231_data *data = platform_get_drvdata(pdev); int i; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]); diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index d9a9ec7dd84..b15c6a998b7 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -223,7 +223,7 @@ temp1_from_reg(s8 reg) } static inline s8 -temp1_to_reg(int temp, int min, int max) +temp1_to_reg(long temp, int min, int max) { if (temp <= min) return min / 1000; @@ -256,7 +256,7 @@ struct w83627ehf_data { int addr; /* IO base of hw monitor block */ const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; struct mutex update_lock; @@ -805,7 +805,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct w83627ehf_data *data = dev_get_drvdata(dev); \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \ @@ -840,7 +840,7 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ struct w83627ehf_data *data = dev_get_drvdata(dev); \ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \ int nr = sensor_attr->index; \ - u32 val = simple_strtoul(buf, NULL, 10); \ + long val = simple_strtol(buf, NULL, 10); \ \ mutex_lock(&data->update_lock); \ data->reg[nr] = LM75_TEMP_TO_REG(val); \ @@ -1384,9 +1384,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) goto exit_remove; } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -1406,7 +1406,7 @@ static int __devexit w83627ehf_remove(struct platform_device *pdev) { struct w83627ehf_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); w83627ehf_device_remove_files(&pdev->dev); release_region(data->addr, IOREGION_LENGTH); platform_set_drvdata(pdev, NULL); diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 7a4a15f4bf8..20ae425a198 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -45,6 +45,7 @@ #include <linux/jiffies.h> #include <linux/platform_device.h> #include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/mutex.h> @@ -218,7 +219,7 @@ static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, W83627THF_REG_PWM3 }; #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ - regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) + regpwm_627hf[nr] : regpwm[nr]) #define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */ @@ -263,7 +264,7 @@ static inline u8 FAN_TO_REG(long rpm, int div) /* TEMP: 0.001C/bit (-128C to +127C) REG: 1C/bit, two's complement */ -static u8 TEMP_TO_REG(int temp) +static u8 TEMP_TO_REG(long temp) { int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); ntemp += (ntemp<0 ? -500 : 500); @@ -346,7 +347,7 @@ static inline u8 DIV_TO_REG(long val) struct w83627hf_data { unsigned short addr; const char *name; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -372,11 +373,8 @@ struct w83627hf_data { u8 beep_enable; /* Boolean */ u8 pwm[3]; /* Register value */ u8 pwm_freq[3]; /* Register value */ - u16 sens[3]; /* 782D/783S only. - 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ + u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode; + 4 = thermistor */ u8 vrm; u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ }; @@ -391,6 +389,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev); static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); +static void w83627hf_update_fan_div(struct w83627hf_data *data); static struct w83627hf_data *w83627hf_update_device(struct device *dev); static void w83627hf_init_device(struct platform_device *pdev); @@ -403,72 +402,71 @@ static struct platform_driver w83627hf_driver = { .remove = __devexit_p(w83627hf_remove), }; -/* following are the sysfs callback functions */ -#define show_in_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ +static ssize_t +show_in_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in[nr])); } -show_in_reg(in) -show_in_reg(in_min) -show_in_reg(in_max) - -#define store_in_reg(REG, reg) \ -static ssize_t \ -store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct w83627hf_data *data = dev_get_drvdata(dev); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_##reg[nr] = IN_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \ - data->in_##reg[nr]); \ - \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t +show_in_min(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_min[nr])); } -store_in_reg(MIN, min) -store_in_reg(MAX, max) +static ssize_t +show_in_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", (long)IN_FROM_REG(data->in_max[nr])); +} +static ssize_t +store_in_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_in_offset(offset) \ -static ssize_t \ -show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in(dev, buf, offset); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); + mutex_lock(&data->update_lock); + data->in_min[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MIN(nr), data->in_min[nr]); + mutex_unlock(&data->update_lock); + return count; +} +static ssize_t +store_in_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_in_reg_offset(reg, offset) \ -static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_in_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_in_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_in_##reg##offset, store_regs_in_##reg##offset); - -#define sysfs_in_offsets(offset) \ -sysfs_in_offset(offset) \ -sysfs_in_reg_offset(min, offset) \ -sysfs_in_reg_offset(max, offset) - -sysfs_in_offsets(1); -sysfs_in_offsets(2); -sysfs_in_offsets(3); -sysfs_in_offsets(4); -sysfs_in_offsets(5); -sysfs_in_offsets(6); -sysfs_in_offsets(7); -sysfs_in_offsets(8); + mutex_lock(&data->update_lock); + data->in_max[nr] = IN_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_IN_MAX(nr), data->in_max[nr]); + mutex_unlock(&data->update_lock); + return count; +} +#define sysfs_vin_decl(offset) \ +static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ + show_in_input, NULL, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO|S_IWUSR, \ + show_in_min, store_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO|S_IWUSR, \ + show_in_max, store_in_max, offset); + +sysfs_vin_decl(1); +sysfs_vin_decl(2); +sysfs_vin_decl(3); +sysfs_vin_decl(4); +sysfs_vin_decl(5); +sysfs_vin_decl(6); +sysfs_vin_decl(7); +sysfs_vin_decl(8); /* use a different set of functions for in0 */ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) @@ -566,134 +564,148 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, show_regs_in_max0, store_regs_in_max0); -#define show_fan_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - return sprintf(buf,"%ld\n", \ - FAN_FROM_REG(data->reg[nr-1], \ - (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +static ssize_t +show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); } -show_fan_reg(fan); -show_fan_reg(fan_min); - static ssize_t -store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +show_fan_min(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + return sprintf(buf, "%ld\n", FAN_FROM_REG(data->fan_min[nr], + (long)DIV_FROM_REG(data->fan_div[nr]))); +} +static ssize_t +store_fan_min(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; - - val = simple_strtoul(buf, NULL, 10); + u32 val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); - data->fan_min[nr - 1] = - FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); - w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr), - data->fan_min[nr - 1]); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), + data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } +#define sysfs_fan_decl(offset) \ +static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ + show_fan_input, NULL, offset - 1); \ +static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ + show_fan_min, store_fan_min, offset - 1); -#define sysfs_fan_offset(offset) \ -static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan(dev, buf, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); +sysfs_fan_decl(1); +sysfs_fan_decl(2); +sysfs_fan_decl(3); -#define sysfs_fan_min_offset(offset) \ -static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_min(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_fan_min(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_regs_fan_min##offset, store_regs_fan_min##offset); - -sysfs_fan_offset(1); -sysfs_fan_min_offset(1); -sysfs_fan_offset(2); -sysfs_fan_min_offset(2); -sysfs_fan_offset(3); -sysfs_fan_min_offset(3); - -#define show_temp_reg(reg) \ -static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ -{ \ - struct w83627hf_data *data = w83627hf_update_device(dev); \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - return sprintf(buf,"%ld\n", \ - (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ - } else { /* TEMP1 */ \ - return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ - } \ +static ssize_t +show_temp(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", (long)TEMP_FROM_REG(data->temp)); + } } -show_temp_reg(temp); -show_temp_reg(temp_max); -show_temp_reg(temp_max_hyst); -#define store_temp_reg(REG, reg) \ -static ssize_t \ -store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ -{ \ - struct w83627hf_data *data = dev_get_drvdata(dev); \ - u32 val; \ - \ - val = simple_strtoul(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - \ - if (nr >= 2) { /* TEMP2 and TEMP3 */ \ - data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg##_add[nr-2]); \ - } else { /* TEMP1 */ \ - data->temp_##reg = TEMP_TO_REG(val); \ - w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \ - data->temp_##reg); \ - } \ - \ - mutex_unlock(&data->update_lock); \ - return count; \ +static ssize_t +show_temp_max(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_max_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", + (long)TEMP_FROM_REG(data->temp_max)); + } } -store_temp_reg(OVER, max); -store_temp_reg(HYST, max_hyst); -#define sysfs_temp_offset(offset) \ -static ssize_t \ -show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp(dev, buf, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); +static ssize_t +show_temp_max_hyst(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = w83627hf_update_device(dev); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + return sprintf(buf, "%ld\n", + (long)LM75_TEMP_FROM_REG(data->temp_max_hyst_add[nr-2])); + } else { /* TEMP1 */ + return sprintf(buf, "%ld\n", + (long)TEMP_FROM_REG(data->temp_max_hyst)); + } +} -#define sysfs_temp_reg_offset(reg, offset) \ -static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_temp_##reg (dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_temp_##reg (dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ - show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); +static ssize_t +store_temp_max(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); -#define sysfs_temp_offsets(offset) \ -sysfs_temp_offset(offset) \ -sysfs_temp_reg_offset(max, offset) \ -sysfs_temp_reg_offset(max_hyst, offset) + mutex_lock(&data->update_lock); -sysfs_temp_offsets(1); -sysfs_temp_offsets(2); -sysfs_temp_offsets(3); + if (nr >= 2) { /* TEMP2 and TEMP3 */ + data->temp_max_add[nr-2] = LM75_TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr), + data->temp_max_add[nr-2]); + } else { /* TEMP1 */ + data->temp_max = TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_OVER(nr), + data->temp_max); + } + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_temp_max_hyst(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + int nr = to_sensor_dev_attr(devattr)->index; + struct w83627hf_data *data = dev_get_drvdata(dev); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + + if (nr >= 2) { /* TEMP2 and TEMP3 */ + data->temp_max_hyst_add[nr-2] = LM75_TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr), + data->temp_max_hyst_add[nr-2]); + } else { /* TEMP1 */ + data->temp_max_hyst = TEMP_TO_REG(val); + w83627hf_write_value(data, W83781D_REG_TEMP_HYST(nr), + data->temp_max_hyst); + } + mutex_unlock(&data->update_lock); + return count; +} + +#define sysfs_temp_decl(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ + show_temp, NULL, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO|S_IWUSR, \ + show_temp_max, store_temp_max, offset); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO|S_IWUSR, \ + show_temp_max_hyst, store_temp_max_hyst, offset); + +sysfs_temp_decl(1); +sysfs_temp_decl(2); +sysfs_temp_decl(3); static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) @@ -706,7 +718,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83627hf_data *data = w83627hf_update_device(dev); + struct w83627hf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t @@ -791,20 +803,22 @@ sysfs_beep(ENABLE, enable); sysfs_beep(MASK, mask); static ssize_t -show_fan_div_reg(struct device *dev, char *buf, int nr) +show_fan_div(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", - (long) DIV_FROM_REG(data->fan_div[nr - 1])); + (long) DIV_FROM_REG(data->fan_div[nr])); } - /* Note: we save and restore the fan minimum here, because its value is determined in part by the fan divisor. This follows the principle of least surprise; the user doesn't expect the fan minimum to change just because the divisor changed. */ static ssize_t -store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +store_fan_div(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long min; u8 reg; @@ -836,92 +850,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_fan_div(offset) \ -static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_fan_div_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - return store_fan_div_reg(dev, buf, count, offset - 1); \ -} \ -static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_regs_fan_div_##offset, store_regs_fan_div_##offset); - -sysfs_fan_div(1); -sysfs_fan_div(2); -sysfs_fan_div(3); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO|S_IWUSR, + show_fan_div, store_fan_div, 2); static ssize_t -show_pwm_reg(struct device *dev, char *buf, int nr) +show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); + return sprintf(buf, "%ld\n", (long) data->pwm[nr]); } static ssize_t -store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); - u32 val; - - val = simple_strtoul(buf, NULL, 10); + u32 val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); if (data->type == w83627thf) { /* bits 0-3 are reserved in 627THF */ - data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; + data->pwm[nr] = PWM_TO_REG(val) & 0xf0; w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1] | + data->pwm[nr] | (w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); } else { - data->pwm[nr - 1] = PWM_TO_REG(val); + data->pwm[nr] = PWM_TO_REG(val); w83627hf_write_value(data, W836X7HF_REG_PWM(data->type, nr), - data->pwm[nr - 1]); + data->pwm[nr]); } mutex_unlock(&data->update_lock); return count; } -#define sysfs_pwm(offset) \ -static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_regs_pwm_##offset, store_regs_pwm_##offset); - -sysfs_pwm(1); -sysfs_pwm(2); -sysfs_pwm(3); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2); static ssize_t -show_pwm_freq_reg(struct device *dev, char *buf, int nr) +show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); if (data->type == w83627hf) return sprintf(buf, "%ld\n", - pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1])); + pwm_freq_from_reg_627hf(data->pwm_freq[nr])); else return sprintf(buf, "%ld\n", - pwm_freq_from_reg(data->pwm_freq[nr - 1])); + pwm_freq_from_reg(data->pwm_freq[nr])); } static ssize_t -store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr) +store_pwm_freq(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); static const u8 mask[]={0xF8, 0x8F}; u32 val; @@ -931,50 +925,42 @@ store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr) mutex_lock(&data->update_lock); if (data->type == w83627hf) { - data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val); + data->pwm_freq[nr] = pwm_freq_to_reg_627hf(val); w83627hf_write_value(data, W83627HF_REG_PWM_FREQ, - (data->pwm_freq[nr - 1] << ((nr - 1)*4)) | + (data->pwm_freq[nr] << (nr*4)) | (w83627hf_read_value(data, - W83627HF_REG_PWM_FREQ) & mask[nr - 1])); + W83627HF_REG_PWM_FREQ) & mask[nr])); } else { - data->pwm_freq[nr - 1] = pwm_freq_to_reg(val); - w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1], - data->pwm_freq[nr - 1]); + data->pwm_freq[nr] = pwm_freq_to_reg(val); + w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr], + data->pwm_freq[nr]); } mutex_unlock(&data->update_lock); return count; } -#define sysfs_pwm_freq(offset) \ -static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return show_pwm_freq_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_pwm_freq_##offset(struct device *dev, \ - struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_pwm_freq_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \ - show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset); - -sysfs_pwm_freq(1); -sysfs_pwm_freq(2); -sysfs_pwm_freq(3); +static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 0); +static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 1); +static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO|S_IWUSR, + show_pwm_freq, store_pwm_freq, 2); static ssize_t -show_sensor_reg(struct device *dev, char *buf, int nr) +show_temp_type(struct device *dev, struct device_attribute *devattr, + char *buf) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = w83627hf_update_device(dev); - return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); + return sprintf(buf, "%ld\n", (long) data->sens[nr]); } static ssize_t -store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +store_temp_type(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { + int nr = to_sensor_dev_attr(devattr)->index; struct w83627hf_data *data = dev_get_drvdata(dev); u32 val, tmp; @@ -986,31 +972,35 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) case 1: /* PII/Celeron diode */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); + tmp | BIT_SCFG1[nr]); tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); w83627hf_write_value(data, W83781D_REG_SCFG2, - tmp | BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp | BIT_SCFG2[nr]); + data->sens[nr] = val; break; case 2: /* 3904 */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp | BIT_SCFG1[nr - 1]); + tmp | BIT_SCFG1[nr]); tmp = w83627hf_read_value(data, W83781D_REG_SCFG2); w83627hf_write_value(data, W83781D_REG_SCFG2, - tmp & ~BIT_SCFG2[nr - 1]); - data->sens[nr - 1] = val; + tmp & ~BIT_SCFG2[nr]); + data->sens[nr] = val; break; - case W83781D_DEFAULT_BETA: /* thermistor */ + case W83781D_DEFAULT_BETA: + dev_warn(dev, "Sensor type %d is deprecated, please use 4 " + "instead\n", W83781D_DEFAULT_BETA); + /* fall through */ + case 4: /* thermistor */ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); w83627hf_write_value(data, W83781D_REG_SCFG1, - tmp & ~BIT_SCFG1[nr - 1]); - data->sens[nr - 1] = val; + tmp & ~BIT_SCFG1[nr]); + data->sens[nr] = val; break; default: dev_err(dev, - "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); + "Invalid sensor type %ld; must be 1, 2, or 4\n", + (long) val); break; } @@ -1018,25 +1008,16 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) return count; } -#define sysfs_sensor(offset) \ -static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - return show_sensor_reg(dev, buf, offset); \ -} \ -static ssize_t \ -store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - return store_sensor_reg(dev, buf, count, offset); \ -} \ -static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_regs_sensor_##offset, store_regs_sensor_##offset); +#define sysfs_temp_type(offset) \ +static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ + show_temp_type, store_temp_type, offset - 1); -sysfs_sensor(1); -sysfs_sensor(2); -sysfs_sensor(3); +sysfs_temp_type(1); +sysfs_temp_type(2); +sysfs_temp_type(3); -static ssize_t show_name(struct device *dev, struct device_attribute - *devattr, char *buf) +static ssize_t +show_name(struct device *dev, struct device_attribute *devattr, char *buf) { struct w83627hf_data *data = dev_get_drvdata(dev); @@ -1118,49 +1099,44 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr, return err; } +#define VIN_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_in##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_min.dev_attr.attr, \ + &sensor_dev_attr_in##_X_##_max.dev_attr.attr + +#define FAN_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_fan##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_min.dev_attr.attr, \ + &sensor_dev_attr_fan##_X_##_div.dev_attr.attr + +#define TEMP_UNIT_ATTRS(_X_) \ + &sensor_dev_attr_temp##_X_##_input.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_max.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_max_hyst.dev_attr.attr, \ + &sensor_dev_attr_temp##_X_##_type.dev_attr.attr + static struct attribute *w83627hf_attributes[] = { &dev_attr_in0_input.attr, &dev_attr_in0_min.attr, &dev_attr_in0_max.attr, - &dev_attr_in2_input.attr, - &dev_attr_in2_min.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_input.attr, - &dev_attr_in3_min.attr, - &dev_attr_in3_max.attr, - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - &dev_attr_in7_input.attr, - &dev_attr_in7_min.attr, - &dev_attr_in7_max.attr, - &dev_attr_in8_input.attr, - &dev_attr_in8_min.attr, - &dev_attr_in8_max.attr, - - &dev_attr_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan2_div.attr, - - &dev_attr_temp1_input.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp1_max_hyst.attr, - &dev_attr_temp1_type.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_max_hyst.attr, - &dev_attr_temp2_type.attr, + VIN_UNIT_ATTRS(2), + VIN_UNIT_ATTRS(3), + VIN_UNIT_ATTRS(4), + VIN_UNIT_ATTRS(7), + VIN_UNIT_ATTRS(8), + + FAN_UNIT_ATTRS(1), + FAN_UNIT_ATTRS(2), + + TEMP_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(2), &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, &dev_attr_beep_mask.attr, - &dev_attr_pwm1.attr, - &dev_attr_pwm2.attr, - + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm2.dev_attr.attr, &dev_attr_name.attr, NULL }; @@ -1170,30 +1146,17 @@ static const struct attribute_group w83627hf_group = { }; static struct attribute *w83627hf_attributes_opt[] = { - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_max.attr, - &dev_attr_in5_input.attr, - &dev_attr_in5_min.attr, - &dev_attr_in5_max.attr, - &dev_attr_in6_input.attr, - &dev_attr_in6_min.attr, - &dev_attr_in6_max.attr, - - &dev_attr_fan3_input.attr, - &dev_attr_fan3_min.attr, - &dev_attr_fan3_div.attr, - - &dev_attr_temp3_input.attr, - &dev_attr_temp3_max.attr, - &dev_attr_temp3_max_hyst.attr, - &dev_attr_temp3_type.attr, - - &dev_attr_pwm3.attr, - - &dev_attr_pwm1_freq.attr, - &dev_attr_pwm2_freq.attr, - &dev_attr_pwm3_freq.attr, + VIN_UNIT_ATTRS(1), + VIN_UNIT_ATTRS(5), + VIN_UNIT_ATTRS(6), + + FAN_UNIT_ATTRS(3), + TEMP_UNIT_ATTRS(3), + &sensor_dev_attr_pwm3.dev_attr.attr, + + &sensor_dev_attr_pwm1_freq.dev_attr.attr, + &sensor_dev_attr_pwm2_freq.dev_attr.attr, + &sensor_dev_attr_pwm3_freq.dev_attr.attr, NULL }; @@ -1244,6 +1207,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1)); data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2)); data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3)); + w83627hf_update_fan_div(data); /* Register common device attributes */ if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group))) @@ -1251,27 +1215,45 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) /* Register chip-specific device attributes */ if (data->type == w83627hf || data->type == w83697hf) - if ((err = device_create_file(dev, &dev_attr_in5_input)) - || (err = device_create_file(dev, &dev_attr_in5_min)) - || (err = device_create_file(dev, &dev_attr_in5_max)) - || (err = device_create_file(dev, &dev_attr_in6_input)) - || (err = device_create_file(dev, &dev_attr_in6_min)) - || (err = device_create_file(dev, &dev_attr_in6_max)) - || (err = device_create_file(dev, &dev_attr_pwm1_freq)) - || (err = device_create_file(dev, &dev_attr_pwm2_freq))) + if ((err = device_create_file(dev, + &sensor_dev_attr_in5_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in5_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in5_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in6_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm1_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2_freq.dev_attr))) goto ERROR4; if (data->type != w83697hf) - if ((err = device_create_file(dev, &dev_attr_in1_input)) - || (err = device_create_file(dev, &dev_attr_in1_min)) - || (err = device_create_file(dev, &dev_attr_in1_max)) - || (err = device_create_file(dev, &dev_attr_fan3_input)) - || (err = device_create_file(dev, &dev_attr_fan3_min)) - || (err = device_create_file(dev, &dev_attr_fan3_div)) - || (err = device_create_file(dev, &dev_attr_temp3_input)) - || (err = device_create_file(dev, &dev_attr_temp3_max)) - || (err = device_create_file(dev, &dev_attr_temp3_max_hyst)) - || (err = device_create_file(dev, &dev_attr_temp3_type))) + if ((err = device_create_file(dev, + &sensor_dev_attr_in1_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_min.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_fan3_div.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_input.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_max_hyst.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_type.dev_attr))) goto ERROR4; if (data->type != w83697hf && data->vid != 0xff) { @@ -1285,18 +1267,22 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) if (data->type == w83627thf || data->type == w83637hf || data->type == w83687thf) - if ((err = device_create_file(dev, &dev_attr_pwm3))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm3.dev_attr))) goto ERROR4; if (data->type == w83637hf || data->type == w83687thf) - if ((err = device_create_file(dev, &dev_attr_pwm1_freq)) - || (err = device_create_file(dev, &dev_attr_pwm2_freq)) - || (err = device_create_file(dev, &dev_attr_pwm3_freq))) + if ((err = device_create_file(dev, + &sensor_dev_attr_pwm1_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm2_freq.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_pwm3_freq.dev_attr))) goto ERROR4; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1319,7 +1305,7 @@ static int __devexit w83627hf_remove(struct platform_device *pdev) struct w83627hf_data *data = platform_get_drvdata(pdev); struct resource *res; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); @@ -1333,6 +1319,24 @@ static int __devexit w83627hf_remove(struct platform_device *pdev) } +/* Registers 0x50-0x5f are banked */ +static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg) +{ + if ((reg & 0x00f0) == 0x50) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET); + } +} + +/* Not strictly necessary, but play it safe for now */ +static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg) +{ + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); + } +} + static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) { int res, word_sized; @@ -1343,12 +1347,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) && (((reg & 0x00ff) == 0x50) || ((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); res = inb_p(data->addr + W83781D_DATA_REG_OFFSET); if (word_sized) { @@ -1358,11 +1357,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) (res << 8) + inb_p(data->addr + W83781D_DATA_REG_OFFSET); } - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return res; } @@ -1433,12 +1428,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) || ((reg & 0xff00) == 0x200)) && (((reg & 0x00ff) == 0x53) || ((reg & 0x00ff) == 0x55)); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(reg >> 8, - data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_set_bank(data, reg); outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET); if (word_sized) { outb_p(value >> 8, @@ -1448,11 +1438,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) } outb_p(value & 0xff, data->addr + W83781D_DATA_REG_OFFSET); - if (reg & 0xff00) { - outb_p(W83781D_REG_BANK, - data->addr + W83781D_ADDR_REG_OFFSET); - outb_p(0, data->addr + W83781D_DATA_REG_OFFSET); - } + w83627hf_reset_bank(data, reg); mutex_unlock(&data->lock); return 0; } @@ -1513,7 +1499,7 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) tmp = w83627hf_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; + data->sens[i - 1] = 4; } else { if (w83627hf_read_value (data, @@ -1556,6 +1542,24 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev) | 0x01); } +static void w83627hf_update_fan_div(struct w83627hf_data *data) +{ + int reg; + + reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); + data->fan_div[0] = (reg >> 4) & 0x03; + data->fan_div[1] = (reg >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83627hf_read_value(data, + W83781D_REG_PIN) >> 6) & 0x03; + } + reg = w83627hf_read_value(data, W83781D_REG_VBAT); + data->fan_div[0] |= (reg >> 3) & 0x04; + data->fan_div[1] |= (reg >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (reg >> 5) & 0x04; +} + static struct w83627hf_data *w83627hf_update_device(struct device *dev) { struct w83627hf_data *data = dev_get_drvdata(dev); @@ -1587,15 +1591,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) w83627hf_read_value(data, W83781D_REG_FAN_MIN(i)); } - for (i = 1; i <= 3; i++) { + for (i = 0; i <= 2; i++) { u8 tmp = w83627hf_read_value(data, W836X7HF_REG_PWM(data->type, i)); /* bits 0-3 are reserved in 627THF */ if (data->type == w83627thf) tmp &= 0xf0; - data->pwm[i - 1] = tmp; - if(i == 2 && - (data->type == w83627hf || data->type == w83697hf)) + data->pwm[i] = tmp; + if (i == 1 && + (data->type == w83627hf || data->type == w83697hf)) break; } if (data->type == w83627hf) { @@ -1633,18 +1637,8 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev) w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3)); } - i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV); - data->fan_div[0] = (i >> 4) & 0x03; - data->fan_div[1] = (i >> 6) & 0x03; - if (data->type != w83697hf) { - data->fan_div[2] = (w83627hf_read_value(data, - W83781D_REG_PIN) >> 6) & 0x03; - } - i = w83627hf_read_value(data, W83781D_REG_VBAT); - data->fan_div[0] |= (i >> 3) & 0x04; - data->fan_div[1] |= (i >> 4) & 0x04; - if (data->type != w83697hf) - data->fan_div[2] |= (i >> 5) & 0x04; + w83627hf_update_fan_div(data); + data->alarms = w83627hf_read_value(data, W83781D_REG_ALARM1) | (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) | diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index dcc941a5aaf..a6a1edfe761 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -220,7 +220,7 @@ DIV_TO_REG(long val, enum chips type) the driver field to differentiate between I2C and ISA chips. */ struct w83781d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex lock; enum chips type; @@ -251,9 +251,7 @@ struct w83781d_data { u8 pwm2_enable; /* Boolean */ u16 sens[3]; /* 782D/783S only. 1 = pentium diode; 2 = 3904 diode; - 3000-5000 = thermistor beta. - Default = 3435. - Other Betas unimplemented */ + 4 = thermistor */ u8 vrm; }; @@ -410,7 +408,7 @@ static ssize_t store_temp_##reg (struct device *dev, \ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \ struct w83781d_data *data = dev_get_drvdata(dev); \ int nr = attr->index; \ - s32 val; \ + long val; \ \ val = simple_strtol(buf, NULL, 10); \ \ @@ -456,7 +454,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83781d_data *data = w83781d_update_device(dev); + struct w83781d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } @@ -483,6 +481,39 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +/* The W83781D has a single alarm bit for temp2 and temp3 */ +static ssize_t show_temp3_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = (data->type == w83781d) ? 5 : 13; + return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0); + static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); @@ -546,6 +577,100 @@ static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, show_beep_enable, store_beep_enable); +static ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t +store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct w83781d_data *data = dev_get_drvdata(dev); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + u8 reg; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + + if (bitnr < 8) { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS1); + if (bit) + reg |= (1 << bitnr); + else + reg &= ~(1 << bitnr); + w83781d_write_value(data, W83781D_REG_BEEP_INTS1, reg); + } else if (bitnr < 16) { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS2); + if (bit) + reg |= (1 << (bitnr - 8)); + else + reg &= ~(1 << (bitnr - 8)); + w83781d_write_value(data, W83781D_REG_BEEP_INTS2, reg); + } else { + reg = w83781d_read_value(data, W83781D_REG_BEEP_INTS3); + if (bit) + reg |= (1 << (bitnr - 16)); + else + reg &= ~(1 << (bitnr - 16)); + w83781d_write_value(data, W83781D_REG_BEEP_INTS3, reg); + } + mutex_unlock(&data->update_lock); + + return count; +} + +/* The W83781D has a single beep bit for temp2 and temp3 */ +static ssize_t show_temp3_beep(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct w83781d_data *data = w83781d_update_device(dev); + int bitnr = (data->type == w83781d) ? 5 : 13; + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 3); +static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 8); +static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 9); +static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 10); +static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 16); +static SENSOR_DEVICE_ATTR(in8_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 17); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 6); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 7); +static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 11); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 4); +static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, + show_beep, store_beep, 5); +static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, + show_temp3_beep, store_beep, 13); + static ssize_t show_fan_div(struct device *dev, struct device_attribute *da, char *buf) { @@ -721,15 +846,19 @@ store_sensor(struct device *dev, struct device_attribute *da, tmp & ~BIT_SCFG2[nr]); data->sens[nr] = val; break; - case W83781D_DEFAULT_BETA: /* thermistor */ + case W83781D_DEFAULT_BETA: + dev_warn(dev, "Sensor type %d is deprecated, please use 4 " + "instead\n", W83781D_DEFAULT_BETA); + /* fall through */ + case 4: /* thermistor */ tmp = w83781d_read_value(data, W83781D_REG_SCFG1); w83781d_write_value(data, W83781D_REG_SCFG1, tmp & ~BIT_SCFG1[nr]); data->sens[nr] = val; break; default: - dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n", - (long) val, W83781D_DEFAULT_BETA); + dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or 4\n", + (long) val); break; } @@ -875,17 +1004,23 @@ ERROR_SC_0: #define IN_UNIT_ATTRS(X) \ &sensor_dev_attr_in##X##_input.dev_attr.attr, \ &sensor_dev_attr_in##X##_min.dev_attr.attr, \ - &sensor_dev_attr_in##X##_max.dev_attr.attr + &sensor_dev_attr_in##X##_max.dev_attr.attr, \ + &sensor_dev_attr_in##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_in##X##_beep.dev_attr.attr #define FAN_UNIT_ATTRS(X) \ &sensor_dev_attr_fan##X##_input.dev_attr.attr, \ &sensor_dev_attr_fan##X##_min.dev_attr.attr, \ - &sensor_dev_attr_fan##X##_div.dev_attr.attr + &sensor_dev_attr_fan##X##_div.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_fan##X##_beep.dev_attr.attr #define TEMP_UNIT_ATTRS(X) \ &sensor_dev_attr_temp##X##_input.dev_attr.attr, \ &sensor_dev_attr_temp##X##_max.dev_attr.attr, \ - &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr + &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_alarm.dev_attr.attr, \ + &sensor_dev_attr_temp##X##_beep.dev_attr.attr static struct attribute* w83781d_attributes[] = { IN_UNIT_ATTRS(0), @@ -944,7 +1079,11 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_in1_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_in1_max.dev_attr))) + &sensor_dev_attr_in1_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in1_beep.dev_attr))) return err; } if (kind != as99127f && kind != w83781d && kind != w83783s) { @@ -955,11 +1094,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_in7_max.dev_attr)) || (err = device_create_file(dev, + &sensor_dev_attr_in7_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in7_beep.dev_attr)) + || (err = device_create_file(dev, &sensor_dev_attr_in8_input.dev_attr)) || (err = device_create_file(dev, &sensor_dev_attr_in8_min.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_in8_max.dev_attr))) + &sensor_dev_attr_in8_max.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_in8_beep.dev_attr))) return err; } if (kind != w83783s) { @@ -968,8 +1115,19 @@ w83781d_create_files(struct device *dev, int kind, int is_isa) || (err = device_create_file(dev, &sensor_dev_attr_temp3_max.dev_attr)) || (err = device_create_file(dev, - &sensor_dev_attr_temp3_max_hyst.dev_attr))) + &sensor_dev_attr_temp3_max_hyst.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_alarm.dev_attr)) + || (err = device_create_file(dev, + &sensor_dev_attr_temp3_beep.dev_attr))) return err; + + if (kind != w83781d) + err = sysfs_chmod_file(&dev->kobj, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, + S_IRUGO | S_IWUSR); + if (err) + return err; } if (kind != w83781d && kind != as99127f) { @@ -1156,9 +1314,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) if (err) goto ERROR4; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto ERROR4; } @@ -1192,7 +1350,7 @@ w83781d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83781d_group); sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt); } @@ -1259,9 +1417,9 @@ w83781d_isa_probe(struct platform_device *pdev) if (err) goto exit_remove_files; - data->class_dev = hwmon_device_register(&pdev->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&pdev->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -1283,7 +1441,7 @@ w83781d_isa_remove(struct platform_device *pdev) { struct w83781d_data *data = platform_get_drvdata(pdev); - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&pdev->dev.kobj, &w83781d_group); sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt); device_remove_file(&pdev->dev, &dev_attr_name); @@ -1485,7 +1643,7 @@ w83781d_init_device(struct device *dev) tmp = w83781d_read_value(data, W83781D_REG_SCFG1); for (i = 1; i <= 3; i++) { if (!(tmp & BIT_SCFG1[i - 1])) { - data->sens[i - 1] = W83781D_DEFAULT_BETA; + data->sens[i - 1] = 4; } else { if (w83781d_read_value (data, diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 9e5f885368b..b6f2ebf9f9c 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -2,7 +2,7 @@ w83791d.c - Part of lm_sensors, Linux kernel modules for hardware monitoring - Copyright (C) 2006 Charles Spirakis <bezaur@gmail.com> + Copyright (C) 2006-2007 Charles Spirakis <bezaur@gmail.com> 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 @@ -247,7 +247,7 @@ static u8 div_to_reg(int nr, long val) struct w83791d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ @@ -384,6 +384,85 @@ static struct sensor_device_attribute sda_in_max[] = { SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9), }; + +static ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct w83791d_data *data = w83791d_update_device(dev); + int bitnr = sensor_attr->index; + + return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t store_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct i2c_client *client = to_i2c_client(dev); + struct w83791d_data *data = i2c_get_clientdata(client); + int bitnr = sensor_attr->index; + int bytenr = bitnr / 8; + long val = simple_strtol(buf, NULL, 10) ? 1 : 0; + + mutex_lock(&data->update_lock); + + data->beep_mask &= ~(0xff << (bytenr * 8)); + data->beep_mask |= w83791d_read(client, W83791D_REG_BEEP_CTRL[bytenr]) + << (bytenr * 8); + + data->beep_mask &= ~(1 << bitnr); + data->beep_mask |= val << bitnr; + + w83791d_write(client, W83791D_REG_BEEP_CTRL[bytenr], + (data->beep_mask >> (bytenr * 8)) & 0xff); + + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct sensor_device_attribute *sensor_attr = + to_sensor_dev_attr(attr); + struct w83791d_data *data = w83791d_update_device(dev); + int bitnr = sensor_attr->index; + + return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1); +} + +/* Note: The bitmask for the beep enable/disable is different than + the bitmask for the alarm. */ +static struct sensor_device_attribute sda_in_beep[] = { + SENSOR_ATTR(in0_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 0), + SENSOR_ATTR(in1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 13), + SENSOR_ATTR(in2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 2), + SENSOR_ATTR(in3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 3), + SENSOR_ATTR(in4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 8), + SENSOR_ATTR(in5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 9), + SENSOR_ATTR(in6_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 10), + SENSOR_ATTR(in7_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 16), + SENSOR_ATTR(in8_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 17), + SENSOR_ATTR(in9_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 14), +}; + +static struct sensor_device_attribute sda_in_alarm[] = { + SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0), + SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1), + SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2), + SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3), + SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8), + SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9), + SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10), + SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19), + SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20), + SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 14), +}; + #define show_fan_reg(reg) \ static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ char *buf) \ @@ -536,6 +615,22 @@ static struct sensor_device_attribute sda_fan_div[] = { show_fan_div, store_fan_div, 4), }; +static struct sensor_device_attribute sda_fan_beep[] = { + SENSOR_ATTR(fan1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 6), + SENSOR_ATTR(fan2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 7), + SENSOR_ATTR(fan3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 11), + SENSOR_ATTR(fan4_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 21), + SENSOR_ATTR(fan5_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 22), +}; + +static struct sensor_device_attribute sda_fan_alarm[] = { + SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6), + SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7), + SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11), + SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21), + SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22), +}; + /* read/write the temperature1, includes measured value and limits */ static ssize_t show_temp1(struct device *dev, struct device_attribute *devattr, char *buf) @@ -618,6 +713,19 @@ static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { show_temp23, store_temp23, 1, 2), }; +/* Note: The bitmask for the beep enable/disable is different than + the bitmask for the alarm. */ +static struct sensor_device_attribute sda_temp_beep[] = { + SENSOR_ATTR(temp1_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 4), + SENSOR_ATTR(temp2_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 5), + SENSOR_ATTR(temp3_beep, S_IWUSR | S_IRUGO, show_beep, store_beep, 1), +}; + +static struct sensor_device_attribute sda_temp_alarm[] = { + SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), + SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), + SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), +}; /* get reatime status of all sensors items: voltage, temp, fan */ static ssize_t show_alarms_reg(struct device *dev, @@ -724,7 +832,7 @@ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) { - struct w83791d_data *data = w83791d_update_device(dev); + struct w83791d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } @@ -749,17 +857,23 @@ static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); #define IN_UNIT_ATTRS(X) \ &sda_in_input[X].dev_attr.attr, \ &sda_in_min[X].dev_attr.attr, \ - &sda_in_max[X].dev_attr.attr + &sda_in_max[X].dev_attr.attr, \ + &sda_in_beep[X].dev_attr.attr, \ + &sda_in_alarm[X].dev_attr.attr #define FAN_UNIT_ATTRS(X) \ &sda_fan_input[X].dev_attr.attr, \ &sda_fan_min[X].dev_attr.attr, \ - &sda_fan_div[X].dev_attr.attr + &sda_fan_div[X].dev_attr.attr, \ + &sda_fan_beep[X].dev_attr.attr, \ + &sda_fan_alarm[X].dev_attr.attr #define TEMP_UNIT_ATTRS(X) \ &sda_temp_input[X].dev_attr.attr, \ &sda_temp_max[X].dev_attr.attr, \ - &sda_temp_max_hyst[X].dev_attr.attr + &sda_temp_max_hyst[X].dev_attr.attr, \ + &sda_temp_beep[X].dev_attr.attr, \ + &sda_temp_alarm[X].dev_attr.attr static struct attribute *w83791d_attributes[] = { IN_UNIT_ATTRS(0), @@ -1017,9 +1131,9 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind) goto error3; /* Everything is ready, now register the working device */ - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto error4; } @@ -1051,7 +1165,7 @@ static int w83791d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83791d_group); } diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index b0fa296740d..f836198b705 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -267,7 +267,7 @@ DIV_TO_REG(long val) struct w83792d_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; enum chips type; struct mutex update_lock; @@ -540,6 +540,15 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%d\n", data->alarms); } +static ssize_t show_alarm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + int nr = sensor_attr->index; + struct w83792d_data *data = w83792d_update_device(dev); + return sprintf(buf, "%d\n", (data->alarms >> nr) & 1); +} + static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) @@ -1015,6 +1024,25 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4); static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 8); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 9); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 10); +static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 11); +static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 12); +static SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_alarm, NULL, 15); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 19); +static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20); +static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21); +static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22); +static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23); static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL); static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR, show_chassis_clear, store_chassis_clear); @@ -1123,26 +1151,30 @@ static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7); -static struct attribute *w83792d_attributes_fan[4][4] = { +static struct attribute *w83792d_attributes_fan[4][5] = { { &sensor_dev_attr_fan4_input.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_div.dev_attr.attr, + &sensor_dev_attr_fan4_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan5_input.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_div.dev_attr.attr, + &sensor_dev_attr_fan5_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan6_input.dev_attr.attr, &sensor_dev_attr_fan6_min.dev_attr.attr, &sensor_dev_attr_fan6_div.dev_attr.attr, + &sensor_dev_attr_fan6_alarm.dev_attr.attr, NULL }, { &sensor_dev_attr_fan7_input.dev_attr.attr, &sensor_dev_attr_fan7_min.dev_attr.attr, &sensor_dev_attr_fan7_div.dev_attr.attr, + &sensor_dev_attr_fan7_alarm.dev_attr.attr, NULL } }; @@ -1182,6 +1214,15 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_in8_input.dev_attr.attr, &sensor_dev_attr_in8_max.dev_attr.attr, &sensor_dev_attr_in8_min.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + &sensor_dev_attr_in8_alarm.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, @@ -1191,6 +1232,9 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1_mode.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr, @@ -1233,12 +1277,15 @@ static struct attribute *w83792d_attributes[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, + &sensor_dev_attr_fan3_alarm.dev_attr.attr, NULL }; @@ -1396,9 +1443,9 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) &w83792d_group_fan[3]))) goto exit_remove_files; - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove_files; } @@ -1433,7 +1480,7 @@ w83792d_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &w83792d_group); for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++) sysfs_remove_group(&client->dev.kobj, diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 253ffaf1568..48599e1cc55 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -179,7 +179,7 @@ static inline s8 TEMP_TO_REG(long val, s8 min, s8 max) struct w83793_data { struct i2c_client client; struct i2c_client *lm75[2]; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ @@ -1075,7 +1075,7 @@ static int w83793_detach_client(struct i2c_client *client) /* main client */ if (data) { - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) device_remove_file(dev, @@ -1434,9 +1434,9 @@ static int w83793_detect(struct i2c_adapter *adapter, int address, int kind) } } - data->class_dev = hwmon_device_register(dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c index a3fcace412f..b5db354e2f1 100644 --- a/drivers/hwmon/w83l785ts.c +++ b/drivers/hwmon/w83l785ts.c @@ -107,7 +107,7 @@ static struct i2c_driver w83l785ts_driver = { struct w83l785ts_data { struct i2c_client client; - struct class_device *class_dev; + struct device *hwmon_dev; struct mutex update_lock; char valid; /* zero until following fields are valid */ unsigned long last_updated; /* in jiffies */ @@ -247,9 +247,9 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind) goto exit_remove; /* Register sysfs hooks */ - data->class_dev = hwmon_device_register(&new_client->dev); - if (IS_ERR(data->class_dev)) { - err = PTR_ERR(data->class_dev); + data->hwmon_dev = hwmon_device_register(&new_client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); goto exit_remove; } @@ -272,7 +272,7 @@ static int w83l785ts_detach_client(struct i2c_client *client) struct w83l785ts_data *data = i2c_get_clientdata(client); int err; - hwmon_device_unregister(data->class_dev); + hwmon_device_unregister(data->hwmon_dev); device_remove_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr); device_remove_file(&client->dev, |