GIT 4774975e7cdc8ba47f0e76f3d25fbba983e88edf git://lm-sensors.org/kernel/mhoffman/hwmon-2.6.git#testing commit Author: Jean Delvare Date: Sun Nov 4 23:45:41 2007 +0100 hwmon: (gl520sm) Add individual alarm and beep files libsensors 3.0 needs these. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit cdc5578d2493739945751fd955a41293aaa42cf5 Author: Jean Delvare Date: Sun Nov 4 23:45:14 2007 +0100 hwmon: (gl520sm) De-macro the sysfs callbacks Use standard dynamic sysfs callbacks instead of macro-generated wrappers. This makes the code more readable, and the binary smaller (by about 11%). Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 48de67f157b0c1180cd7fbd21b1daca5914b9711 Author: Jean Delvare Date: Sun Nov 4 23:44:52 2007 +0100 hwmon: (gl520sm) Put register addresses in arrays This allows for some code refactoring, making the binary slightly smaller. This is also required to use dynamic sysfs callbacks for voltage and temperature files. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 313b20d1a0d9ea4e75a224947629d432d301d656 Author: Jean Delvare Date: Sun Nov 4 23:44:23 2007 +0100 hwmon: (gl520sm) Various cleanups * Drop trailing spaces * Drop unused driver ID * Drop stray backslashes in macros * Rename new_client to client * Drop redundant initializations to 0 Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit d4cc7d2a95d288a7eefbceeb71f60c05f27c0e12 Author: Jean Delvare Date: Sun Nov 25 21:58:21 2007 +0100 hwmon: (lm90) Use generic i2c reads during detection As indirectly reported by Olof Johansson, the lm90 driver uses a custom i2c read function even during detection, at which point we don't know yet what device we're talking with. It would make more sense to only use the generic i2c read function at this point, so that we don't log irrelevant errors on misdetection. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit f33a00b56c12ada61d7e2b98b4d1d7247349893f Author: Jean Delvare Date: Tue Oct 23 14:02:24 2007 +0200 hwmon: (gl518sm) Fix the reported fan speed The fan speeds reported by the gl518sm driver are twice as much as they should. It's currently reporting the number of pulses per minute, not rotations per minute, while typical fans emit two pulses per rotation. This explains why all reports with this driver had very high speed values (between 9000 to 12000 RPM). Odd that nobody ever actually complained about this bug. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 57e593147aa889998f0d99027874911ab33efbd4 Author: Jean Delvare Date: Mon Oct 22 17:47:58 2007 +0200 hwmon: (gl518sm) Report error on invalid fan div value If the user attempts to write a fan clock divider not supported by the chip, an error should be returned. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 741fa584d2d68b2f30e9f0625ecd32721d8421f2 Author: Jean Delvare Date: Mon Oct 22 17:47:16 2007 +0200 hwmon: (gl518sm) Add individual alarm and beep files The new libsensors needs these. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 01271f5d62368e8232038391cda3e503f95645a0 Author: Jean Delvare Date: Mon Oct 22 17:46:42 2007 +0200 hwmon: (gl518sm) Refactor fan functions This makes the code more readable and the binary smaller (by 5% or so). Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 0db1fa21ac89048a828455956324aa20c5eaa63b Author: Jean Delvare Date: Mon Oct 22 17:46:17 2007 +0200 hwmon: (gl518sm) Don't create sysfs files for missing features The early revisions of the GL518SM do not report voltage values for the first 3 voltage channels. We should not create sysfs attributes for these missing features. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 161e4532931e642fcaa8b6b9ddb61d38d850e24e Author: Jean Delvare Date: Mon Oct 22 17:45:08 2007 +0200 hwmon: (gl518sm) Various cleanups * Drop history, it doesn't belong there * Drop unused struct member * Drop bogus struct member comment * Drop unused driver ID * Rename new_client to client * Drop redundant initializations to 0 * Drop useless cast * Drop trailing space * Fix comment * Drop duplicate comment Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 832584888d63f7eec3ac120d806a513157cc5950 Author: Jean Delvare Date: Sat Nov 24 17:45:09 2007 -0500 hwmon: (fschmd) Discard non-ASCII characters Somehow non-ASCII characters managed to sneak into the fschmd driver. Kick them out. Signed-off-by: Jean Delvare Cc: Hans de Goede Signed-off-by: Mark M. Hoffman commit c67afce77614cf33242e8c6bf34649de4bda5ffb Author: Jean Delvare Date: Wed Oct 10 21:14:11 2007 +0200 hwmon: (adm1025) Various cleanups * Whitespace cleanups * Constify scaling constants * Fold long lines * Drop redundant initializations to 0 * Rename new_client to just client * Use sysfs_create_group() * Drop a useless comment Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 2b92aa72169f0792cc45cfdaf8daa10be73d5d6a Author: Jean Delvare Date: Wed Oct 10 21:11:52 2007 +0200 hwmon: (adm1025) Add individual alarm files The future libsensors needs these individual alarm and fault files. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 8b6742681f5c10ea45d6bbbdd7fcf32129bf8234 Author: Jean Delvare Date: Wed Oct 10 21:11:01 2007 +0200 hwmon: (adm1025) Use dynamic sysfs callbacks This lets us get rid of macro-generated functions and shrinks the driver size by about 30%. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 97e0c3cdc7714c465aa5bbaa26bc53646da01d34 Author: Jean Delvare Date: Tue Oct 9 15:22:22 2007 +0200 hwmon: (lm87) Add support for the Analog Devices ADM1024 It happens that the Analog Devices ADM1024 is fully compatible with the National Semiconductor LM87, so support for the former can easily be added to the lm87 driver. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit d9707eb3e8a69bcd9d5a64fd0b49c09708c9b18c Author: Kevin Lo Date: Fri Nov 23 09:31:52 2007 +0800 hwmon: Add support for Winbond W83L786NG/NR Signed-off-by: Kevin Lo Signed-off-by: Mark M. Hoffman commit 8b9daa5d6f914913ec17fd454cf7030727760ea1 Author: Robert P. J. Day Date: Tue Nov 6 03:21:42 2007 -0500 hwmon: (adt7470) Replace power-of-two test Since already supplies a power-of-two test, there's no point in having this source file redefine it again. Signed-off-by: Robert P. J. Day Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 92890eb0d383794fd5b87cd6459f7b17a5c61c30 Author: Nicolas Kaiser Date: Wed Nov 7 13:28:59 2007 +0100 hwmon: (w83793) remove duplicated defines Remove duplicated defines. Signed-off-by: Nicolas Kaiser Acked-by: Jean Delvare Signed-off-by: Mark M. Hoffman commit 578c7184257af1c2eb923de06059f482932038fc Author: Jean Delvare Date: Sun Oct 7 12:25:46 2007 +0200 hwmon: (lm78/w83781d) Probe fewer I2C addresses We've never seen any device supported by the lm78 or w83781d driver at addresses 0x20-0x27, so let's stop probing these addresses. Extra probes cost time, and have potential for confusing or misdetecting other I2C devices. Signed-off-by: Jean Delvare Signed-off-by: Mark M. Hoffman Documentation/hwmon/lm78 | 4 +- Documentation/hwmon/lm87 | 11 +- Documentation/hwmon/w83781d | 6 +- Documentation/hwmon/w83l786ng | 54 +++ drivers/hwmon/Kconfig | 14 +- drivers/hwmon/Makefile | 1 + drivers/hwmon/adm1025.c | 389 +++++++++++--------- drivers/hwmon/adt7470.c | 4 +- drivers/hwmon/fschmd.c | 4 +- drivers/hwmon/gl518sm.c | 269 +++++++++----- drivers/hwmon/gl520sm.c | 648 +++++++++++++++++++------------- drivers/hwmon/lm78.c | 6 +- drivers/hwmon/lm87.c | 25 +- drivers/hwmon/lm90.c | 26 +- drivers/hwmon/w83781d.c | 7 +- drivers/hwmon/w83793.c | 5 +- drivers/hwmon/w83l786ng.c | 821 +++++++++++++++++++++++++++++++++++++++++ include/linux/i2c-id.h | 2 - 18 files changed, 1725 insertions(+), 571 deletions(-) diff --git a/Documentation/hwmon/lm78 b/Documentation/hwmon/lm78 index dfc318a..60932e2 100644 --- a/Documentation/hwmon/lm78 +++ b/Documentation/hwmon/lm78 @@ -4,12 +4,12 @@ Kernel driver lm78 Supported chips: * National Semiconductor LM78 / LM78-J Prefix: 'lm78' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ * National Semiconductor LM79 Prefix: 'lm79' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: Publicly available at the National Semiconductor website http://www.national.com/ diff --git a/Documentation/hwmon/lm87 b/Documentation/hwmon/lm87 index c952c57..ec27aa1 100644 --- a/Documentation/hwmon/lm87 +++ b/Documentation/hwmon/lm87 @@ -4,8 +4,12 @@ Kernel driver lm87 Supported chips: * National Semiconductor LM87 Prefix: 'lm87' - Addresses scanned: I2C 0x2c - 0x2f + Addresses scanned: I2C 0x2c - 0x2e Datasheet: http://www.national.com/pf/LM/LM87.html + * Analog Devices ADM1024 + Prefix: 'adm1024' + Addresses scanned: I2C 0x2c - 0x2e + Datasheet: http://www.analog.com/en/prod/0,2877,ADM1024,00.html Authors: Frodo Looijaard , @@ -19,11 +23,12 @@ Authors: Description ----------- -This driver implements support for the National Semiconductor LM87. +This driver implements support for the National Semiconductor LM87 +and the Analog Devices ADM1024. The LM87 implements up to three temperature sensors, up to two fan rotation speed sensors, up to seven voltage sensors, alarms, and some -miscellaneous stuff. +miscellaneous stuff. The ADM1024 is fully compatible. Temperatures are measured in degrees Celsius. Each input has a high and low alarm settings. A high limit produces an alarm when the value diff --git a/Documentation/hwmon/w83781d b/Documentation/hwmon/w83781d index b1e9f80..dbeadb2 100644 --- a/Documentation/hwmon/w83781d +++ b/Documentation/hwmon/w83781d @@ -4,11 +4,11 @@ Kernel driver w83781d Supported chips: * Winbond W83781D Prefix: 'w83781d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83781d.pdf * Winbond W83782D Prefix: 'w83782d' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond.com/PDF/sheet/w83782d.pdf * Winbond W83783S Prefix: 'w83783s' @@ -16,7 +16,7 @@ Supported chips: Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/w83783s.pdf * Winbond W83627HF Prefix: 'w83627hf' - Addresses scanned: I2C 0x20 - 0x2f, ISA 0x290 (8 I/O ports) + Addresses scanned: I2C 0x28 - 0x2f, ISA 0x290 (8 I/O ports) Datasheet: http://www.winbond.com/PDF/sheet/w83627hf.pdf * Asus AS99127F Prefix: 'as99127f' diff --git a/Documentation/hwmon/w83l786ng b/Documentation/hwmon/w83l786ng new file mode 100644 index 0000000..d8f55d7 --- /dev/null +++ b/Documentation/hwmon/w83l786ng @@ -0,0 +1,54 @@ +Kernel driver w83l786ng +===================== + +Supported chips: + * Winbond W83L786NG/W83L786NR + Prefix: 'w83l786ng' + Addresses scanned: I2C 0x2e - 0x2f + Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L786NRNG09.pdf + +Author: Kevin Lo + + +Module Parameters +----------------- + +* reset boolean + (default 0) + Use 'reset=1' to reset the chip (via index 0x40, bit 7). The default + behavior is no chip reset to preserve BIOS settings + + +Description +----------- + +This driver implements support for Winbond W83L786NG/W83L786NR chips. + +The driver implements two temperature sensors, two fan rotation speed +sensors, and three voltage sensors. + +Temperatures are measured in degrees Celsius and measurement resolution is 1 +degC for temp1 and temp2. + +Fan rotation speeds are reported in RPM (rotations per minute). Fan readings +readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 +or 128 for fan 1/2) to give the readings more range or accuracy. + +Voltage sensors (also known as IN sensors) report their values in millivolts. +An alarm is triggered if the voltage has crossed a programmable minimum +or maximum limit. + +/sys files +---------- + +pwm[1-2] - this file stores PWM duty cycle or DC value (fan speed) in range: + 0 (stop) to 255 (full) +pwm[1-2]_enable - this file controls mode of fan/temperature control: + * 0 Manual Mode + * 1 Thermal Cruise + * 2 Smart Fan II + * 4 FAN_SET +pwm[1-2]_mode - Select PWM of DC mode + * 0 DC + * 1 PWM +tolerance[1-2] - Value in degrees of Celsius (degC) for +- T diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index a0445be..af43d56 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -433,12 +433,12 @@ config SENSORS_LM85 will be called lm85. config SENSORS_LM87 - tristate "National Semiconductor LM87" + tristate "National Semiconductor LM87 and compatibles" depends on I2C select HWMON_VID help If you say yes here you get support for National Semiconductor LM87 - sensor chips. + and Analog Devices ADM1024 sensor chips. This driver can also be built as a module. If so, the module will be called lm87. @@ -683,6 +683,16 @@ config SENSORS_W83L785TS This driver can also be built as a module. If so, the module will be called w83l785ts. +config SENSORS_W83L786NG + tristate "Winbond W83L786NG, W83L786NR" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Winbond W83L786NG + and W83L786NR sensor chips. + + This driver can also be built as a module. If so, the module + will be called w83l786ng. + config SENSORS_W83627HF tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" select HWMON_VID diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 55595f6..77a3e09 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_SENSORS_VT1211) += vt1211.o obj-$(CONFIG_SENSORS_VT8231) += vt8231.o obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o +obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 041ecb0..c7a365a 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619); */ #define ADM1025_REG_MAN_ID 0x3E -#define ADM1025_REG_CHIP_ID 0x3F +#define ADM1025_REG_CHIP_ID 0x3F #define ADM1025_REG_CONFIG 0x40 #define ADM1025_REG_STATUS1 0x41 #define ADM1025_REG_STATUS2 0x42 @@ -92,7 +93,7 @@ I2C_CLIENT_INSMOD_2(adm1025, ne1619); * The ADM1025 uses signed 8-bit values for temperatures. */ -static int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; +static const int in_scale[6] = { 2500, 2250, 3300, 5000, 12000, 3300 }; #define IN_FROM_REG(reg,scale) (((reg) * (scale) + 96) / 192) #define IN_TO_REG(val,scale) ((val) <= 0 ? 0 : \ @@ -153,86 +154,96 @@ struct adm1025_data { * Sysfs stuff */ -#define show_in(offset) \ -static ssize_t show_in##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[offset], \ - in_scale[offset])); \ -} \ -static ssize_t show_in##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[offset], \ - in_scale[offset])); \ -} \ -static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL); -show_in(0); -show_in(1); -show_in(2); -show_in(3); -show_in(4); -show_in(5); - -#define show_temp(offset) \ -static ssize_t show_temp##offset(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[offset-1])); \ -} \ -static ssize_t show_temp##offset##_min(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[offset-1])); \ -} \ -static ssize_t show_temp##offset##_max(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct adm1025_data *data = adm1025_update_device(dev); \ - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[offset-1])); \ -}\ -static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp##offset, NULL); -show_temp(1); -show_temp(2); +static ssize_t +show_in(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in[index], + in_scale[index])); +} + +static ssize_t +show_in_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[index], + in_scale[index])); +} + +static ssize_t +show_in_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[index], + in_scale[index])); +} + +static ssize_t +show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[index])); +} + +static ssize_t +show_temp_min(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[index])); +} + +static ssize_t +show_temp_max(struct device *dev, struct device_attribute *attr, char *buf) +{ + int index = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index])); +} + +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->in_min[index] = IN_TO_REG(val, in_scale[index]); + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(index), + data->in_min[index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->in_max[index] = IN_TO_REG(val, in_scale[index]); + i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(index), + data->in_max[index]); + mutex_unlock(&data->update_lock); + return count; +} #define set_in(offset) \ -static ssize_t set_in##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_min[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MIN(offset), \ - data->in_min[offset]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_in##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->in_max[offset] = IN_TO_REG(val, in_scale[offset]); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_IN_MAX(offset), \ - data->in_max[offset]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(in##offset##_min, S_IWUSR | S_IRUGO, \ - show_in##offset##_min, set_in##offset##_min); \ -static DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ - 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_IWUSR | S_IRUGO, \ + show_in_min, set_in_min, offset); \ +static SENSOR_DEVICE_ATTR(in##offset##_max, S_IWUSR | S_IRUGO, \ + show_in_max, set_in_max, offset) set_in(0); set_in(1); set_in(2); @@ -240,62 +251,89 @@ set_in(3); set_in(4); set_in(5); +static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->temp_min[index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(index), + data->temp_min[index]); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int index = to_sensor_dev_attr(attr)->index; + struct i2c_client *client = to_i2c_client(dev); + struct adm1025_data *data = i2c_get_clientdata(client); + long val = simple_strtol(buf, NULL, 10); + + mutex_lock(&data->update_lock); + data->temp_max[index] = TEMP_TO_REG(val); + i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(index), + data->temp_max[index]); + mutex_unlock(&data->update_lock); + return count; +} + #define set_temp(offset) \ -static ssize_t set_temp##offset##_min(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->temp_min[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_LOW(offset-1), \ - data->temp_min[offset-1]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static ssize_t set_temp##offset##_max(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct adm1025_data *data = i2c_get_clientdata(client); \ - long val = simple_strtol(buf, NULL, 10); \ - \ - mutex_lock(&data->update_lock); \ - data->temp_max[offset-1] = TEMP_TO_REG(val); \ - i2c_smbus_write_byte_data(client, ADM1025_REG_TEMP_HIGH(offset-1), \ - data->temp_max[offset-1]); \ - mutex_unlock(&data->update_lock); \ - return count; \ -} \ -static DEVICE_ATTR(temp##offset##_min, S_IWUSR | S_IRUGO, \ - show_temp##offset##_min, set_temp##offset##_min); \ -static DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ - 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_IWUSR | S_IRUGO, \ + show_temp_min, set_temp_min, offset - 1); \ +static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IWUSR | S_IRUGO, \ + show_temp_max, set_temp_max, offset - 1) set_temp(1); set_temp(2); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_alarms(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_alarm(struct device *dev, struct device_attribute *attr, char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct adm1025_data *data = adm1025_update_device(dev); + 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(temp1_alarm, S_IRUGO, show_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); + +static ssize_t +show_vid(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_vrm(struct device *dev, struct device_attribute *attr, char *buf) { 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) +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 adm1025_data *data = i2c_get_clientdata(client); @@ -316,27 +354,35 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter) } static struct attribute *adm1025_attributes[] = { - &dev_attr_in0_input.attr, - &dev_attr_in1_input.attr, - &dev_attr_in2_input.attr, - &dev_attr_in3_input.attr, - &dev_attr_in5_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in1_min.attr, - &dev_attr_in2_min.attr, - &dev_attr_in3_min.attr, - &dev_attr_in5_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_max.attr, - &dev_attr_in2_max.attr, - &dev_attr_in3_max.attr, - &dev_attr_in5_max.attr, - &dev_attr_temp1_input.attr, - &dev_attr_temp2_input.attr, - &dev_attr_temp1_min.attr, - &dev_attr_temp2_min.attr, - &dev_attr_temp1_max.attr, - &dev_attr_temp2_max.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_in5_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_in5_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_in5_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_in5_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_cpu0_vid.attr, &dev_attr_vrm.attr, @@ -347,15 +393,16 @@ static const struct attribute_group adm1025_group = { .attrs = adm1025_attributes, }; -static struct attribute *adm1025_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, +static struct attribute *adm1025_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 adm1025_group_opt = { - .attrs = adm1025_attributes_opt, +static const struct attribute_group adm1025_group_in4 = { + .attrs = adm1025_attributes_in4, }; /* @@ -364,7 +411,7 @@ static const struct attribute_group adm1025_group_opt = { */ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct adm1025_data *data; int err = 0; const char *name = ""; @@ -378,14 +425,11 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - /* The common I2C client data is placed right before the - ADM1025-specific data. */ - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &adm1025_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &adm1025_driver; /* * Now we do the remaining detection. A negative kind means that @@ -397,12 +441,12 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) * requested, so both the detection and the identification steps * are skipped. */ - config = i2c_smbus_read_byte_data(new_client, ADM1025_REG_CONFIG); + config = i2c_smbus_read_byte_data(client, ADM1025_REG_CONFIG); if (kind < 0) { /* detection */ if ((config & 0x80) != 0x00 - || (i2c_smbus_read_byte_data(new_client, + || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS1) & 0xC0) != 0x00 - || (i2c_smbus_read_byte_data(new_client, + || (i2c_smbus_read_byte_data(client, ADM1025_REG_STATUS2) & 0xBC) != 0x00) { dev_dbg(&adapter->dev, "ADM1025 detection failed at 0x%02x.\n", @@ -414,11 +458,9 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) if (kind <= 0) { /* identification */ u8 man_id, chip_id; - man_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_MAN_ID); - chip_id = i2c_smbus_read_byte_data(new_client, - ADM1025_REG_CHIP_ID); - + man_id = i2c_smbus_read_byte_data(client, ADM1025_REG_MAN_ID); + chip_id = i2c_smbus_read_byte_data(client, ADM1025_REG_CHIP_ID); + if (man_id == 0x41) { /* Analog Devices */ if ((chip_id & 0xF0) == 0x20) { /* ADM1025/ADM1025A */ kind = adm1025; @@ -446,33 +488,28 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) } /* We can fill in the remaining client fields */ - strlcpy(new_client->name, name, I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, name, I2C_NAME_SIZE); 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 exit_free; /* Initialize the ADM1025 chip */ - adm1025_init_client(new_client); + adm1025_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &adm1025_group))) goto exit_detach; /* Pin 11 is either in4 (+12V) or VID4 */ if (!(config & 0x20)) { - 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(&client->dev.kobj, + &adm1025_group_in4))) goto exit_remove; } - data->hwmon_dev = hwmon_device_register(&new_client->dev); + data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; @@ -481,10 +518,10 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove: - sysfs_remove_group(&new_client->dev.kobj, &adm1025_group); - sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt); + sysfs_remove_group(&client->dev.kobj, &adm1025_group); + sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -540,7 +577,7 @@ static int adm1025_detach_client(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &adm1025_group); - sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt); + sysfs_remove_group(&client->dev.kobj, &adm1025_group_in4); if ((err = i2c_detach_client(client))) return err; diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 9810aaa..a215560 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -114,8 +114,6 @@ I2C_CLIENT_INSMOD_1(adt7470); /* 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 @@ -677,7 +675,7 @@ static int cvt_auto_temp(int input) { if (input == ADT7470_PWM_ALL_TEMPS) return 0; - if (input < 1 || !power_of_2(input)) + if (input < 1 || !is_power_of_2(input)) return -EINVAL; return ilog2(input) + 1; } diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index 63a4df0..d427ea5 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -133,7 +133,7 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { { 0x71, 0x81, 0x91 }, /* her */ { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ { 0x71, 0x81, 0x91 }, /* hrc */ - { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ + { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ }; /* temperature high limit registers, FSC does not document these. Proven to be @@ -146,7 +146,7 @@ static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { { 0x76, 0x86, 0x96 }, /* her */ { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ { 0x76, 0x86, 0x96 }, /* hrc */ - { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ + { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ }; /* These were found through experimenting with an fscher, currently they are diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index bb58d98..3b1ac48 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -30,10 +30,6 @@ * We did not keep that part of the original driver in the Linux 2.6 * version, since it was making the driver significantly more complex * with no real benefit. - * - * History: - * 2004-01-28 Original port. (Hong-Gunn Chew) - * 2004-01-31 Code review and approval. (Jean Delvare) */ #include @@ -42,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -99,10 +96,10 @@ static inline u8 FAN_TO_REG(long rpm, int div) long rpmdiv; if (rpm == 0) return 0; - rpmdiv = SENSORS_LIMIT(rpm, 1, 1920000) * div; - return SENSORS_LIMIT((960000 + rpmdiv / 2) / rpmdiv, 1, 255); + rpmdiv = SENSORS_LIMIT(rpm, 1, 960000) * div; + return SENSORS_LIMIT((480000 + rpmdiv / 2) / rpmdiv, 1, 255); } -#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (960000/((val)*(div)))) +#define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val)*(div)))) #define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) #define IN_FROM_REG(val) ((val)*19) @@ -110,7 +107,6 @@ static inline u8 FAN_TO_REG(long rpm, int div) #define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) #define VDD_FROM_REG(val) (((val)*95+2)/4) -#define DIV_TO_REG(val) ((val)==4?2:(val)==2?1:(val)==1?0:3) #define DIV_FROM_REG(val) (1 << (val)) #define BEEP_MASK_TO_REG(val) ((val) & 0x7f & data->alarm_mask) @@ -129,7 +125,6 @@ struct gl518_data { u8 voltage_in[4]; /* Register values; [0] = VDD */ u8 voltage_min[4]; /* Register values; [0] = VDD */ u8 voltage_max[4]; /* Register values; [0] = VDD */ - u8 iter_voltage_in[4]; /* Register values; [0] = VDD */ u8 fan_in[2]; u8 fan_min[2]; u8 fan_div[2]; /* Register encoding, shifted right */ @@ -138,7 +133,7 @@ struct gl518_data { u8 temp_max; /* Register values */ u8 temp_hyst; /* Register values */ u8 alarms; /* Register value */ - u8 alarm_mask; /* Register value */ + u8 alarm_mask; u8 beep_mask; /* Register value */ u8 beep_enable; /* Boolean */ }; @@ -156,7 +151,6 @@ static struct i2c_driver gl518_driver = { .driver = { .name = "gl518sm", }, - .id = I2C_DRIVERID_GL518, .attach_adapter = gl518_attach_adapter, .detach_client = gl518_detach_client, }; @@ -172,24 +166,10 @@ static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", type##_FROM_REG(data->value)); \ } -#define show_fan(suffix, value, index) \ -static ssize_t show_##suffix(struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl518_data *data = gl518_update_device(dev); \ - return sprintf(buf, "%d\n", FAN_FROM_REG(data->value[index], \ - DIV_FROM_REG(data->fan_div[index]))); \ -} - show(TEMP, temp_input1, temp_in); show(TEMP, temp_max1, temp_max); show(TEMP, temp_hyst1, temp_hyst); show(BOOL, fan_auto1, fan_auto1); -show_fan(fan_input1, fan_in, 0); -show_fan(fan_input2, fan_in, 1); -show_fan(fan_min1, fan_min, 0); -show_fan(fan_min2, fan_min, 1); -show(DIV, fan_div1, fan_div[0]); -show(DIV, fan_div2, fan_div[1]); show(VDD, in_input0, voltage_in[0]); show(IN, in_input1, voltage_in[1]); show(IN, in_input2, voltage_in[2]); @@ -206,6 +186,32 @@ show(RAW, alarms, alarms); show(BOOL, beep_enable, beep_enable); show(BEEP_MASK, beep_mask, beep_mask); +static ssize_t show_fan_input(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_in[nr], + DIV_FROM_REG(data->fan_div[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 gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], + DIV_FROM_REG(data->fan_div[nr]))); +} + +static ssize_t show_fan_div(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr])); +} + #define set(type, suffix, value, reg) \ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \ size_t count) \ @@ -247,8 +253,6 @@ static ssize_t set_##suffix(struct device *dev, struct device_attribute *attr, c set(TEMP, temp_max1, temp_max, GL518_REG_TEMP_MAX); set(TEMP, temp_hyst1, temp_hyst, GL518_REG_TEMP_HYST); set_bits(BOOL, fan_auto1, fan_auto1, GL518_REG_MISC, 0x08, 3); -set_bits(DIV, fan_div1, fan_div[0], GL518_REG_MISC, 0xc0, 6); -set_bits(DIV, fan_div2, fan_div[1], GL518_REG_MISC, 0x30, 4); set_low(VDD, in_min0, voltage_min[0], GL518_REG_VDD_LIMIT); set_low(IN, in_min1, voltage_min[1], GL518_REG_VIN1_LIMIT); set_low(IN, in_min2, voltage_min[2], GL518_REG_VIN2_LIMIT); @@ -260,25 +264,27 @@ set_high(IN, in_max3, voltage_max[3], GL518_REG_VIN3_LIMIT); set_bits(BOOL, beep_enable, beep_enable, GL518_REG_CONF, 0x04, 2); set(BEEP_MASK, beep_mask, beep_mask, GL518_REG_ALARM); -static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val = simple_strtoul(buf, NULL, 10); mutex_lock(&data->update_lock); regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[0] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[0])); - regvalue = (regvalue & 0x00ff) | (data->fan_min[0] << 8); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + regvalue = (regvalue & (0xff << (8 * nr))) + | (data->fan_min[nr] << (8 * (1 - nr))); gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[0] == 0) - data->alarm_mask &= ~0x20; + if (data->fan_min[nr] == 0) + data->alarm_mask &= ~(0x20 << nr); else - data->alarm_mask |= 0x20; + data->alarm_mask |= (0x20 << nr); data->beep_mask &= data->alarm_mask; gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); @@ -286,28 +292,32 @@ static ssize_t set_fan_min1(struct device *dev, struct device_attribute *attr, c return count; } -static ssize_t set_fan_min2(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct gl518_data *data = i2c_get_clientdata(client); + int nr = to_sensor_dev_attr(attr)->index; int regvalue; unsigned long val = simple_strtoul(buf, NULL, 10); - mutex_lock(&data->update_lock); - regvalue = gl518_read_value(client, GL518_REG_FAN_LIMIT); - data->fan_min[1] = FAN_TO_REG(val, - DIV_FROM_REG(data->fan_div[1])); - regvalue = (regvalue & 0xff00) | data->fan_min[1]; - gl518_write_value(client, GL518_REG_FAN_LIMIT, regvalue); - - data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); - if (data->fan_min[1] == 0) - data->alarm_mask &= ~0x40; - else - data->alarm_mask |= 0x40; - data->beep_mask &= data->alarm_mask; - gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + switch (val) { + case 1: val = 0; break; + case 2: val = 1; break; + case 4: val = 2; break; + case 8: val = 3; break; + default: + dev_err(dev, "Invalid fan clock divider %lu, choose one " + "of 1, 2, 4 or 8\n", val); + return -EINVAL; + } + mutex_lock(&data->update_lock); + regvalue = gl518_read_value(client, GL518_REG_MISC); + data->fan_div[nr] = val; + regvalue = (regvalue & ~(0xc0 >> (2 * nr))) + | (data->fan_div[nr] << (6 - 2 * nr)); + gl518_write_value(client, GL518_REG_MISC, regvalue); mutex_unlock(&data->update_lock); return count; } @@ -317,12 +327,16 @@ static DEVICE_ATTR(temp1_max, S_IWUSR|S_IRUGO, show_temp_max1, set_temp_max1); static DEVICE_ATTR(temp1_max_hyst, S_IWUSR|S_IRUGO, show_temp_hyst1, set_temp_hyst1); static DEVICE_ATTR(fan1_auto, S_IWUSR|S_IRUGO, show_fan_auto1, set_fan_auto1); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input1, NULL); -static DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input2, NULL); -static DEVICE_ATTR(fan1_min, S_IWUSR|S_IRUGO, show_fan_min1, set_fan_min1); -static DEVICE_ATTR(fan2_min, S_IWUSR|S_IRUGO, show_fan_min2, set_fan_min2); -static DEVICE_ATTR(fan1_div, S_IWUSR|S_IRUGO, show_fan_div1, set_fan_div1); -static DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, show_fan_div2, set_fan_div2); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); +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(fan1_div, S_IWUSR|S_IRUGO, + show_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR|S_IRUGO, + show_fan_div, set_fan_div, 1); static DEVICE_ATTR(in0_input, S_IRUGO, show_in_input0, NULL); static DEVICE_ATTR(in1_input, S_IRUGO, show_in_input1, NULL); static DEVICE_ATTR(in2_input, S_IRUGO, show_in_input2, NULL); @@ -341,10 +355,62 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO, static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO, show_beep_mask, set_beep_mask); +static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + 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(temp1_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 ssize_t show_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl518_data *data = gl518_update_device(dev); + return sprintf(buf, "%u\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t set_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl518_data *data = i2c_get_clientdata(client); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beep_mask = gl518_read_value(client, GL518_REG_ALARM); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + gl518_write_value(client, GL518_REG_ALARM, data->beep_mask); + mutex_unlock(&data->update_lock); + return count; +} + +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 3); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 4); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 5); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_beep, set_beep, 6); + static struct attribute *gl518_attributes[] = { - &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, @@ -354,18 +420,32 @@ static struct attribute *gl518_attributes[] = { &dev_attr_in1_max.attr, &dev_attr_in2_max.attr, &dev_attr_in3_max.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_in0_beep.dev_attr.attr, + &sensor_dev_attr_in1_beep.dev_attr.attr, + &sensor_dev_attr_in2_beep.dev_attr.attr, + &sensor_dev_attr_in3_beep.dev_attr.attr, &dev_attr_fan1_auto.attr, - &dev_attr_fan1_input.attr, - &dev_attr_fan2_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan2_min.attr, - &dev_attr_fan1_div.attr, - &dev_attr_fan2_div.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, + &sensor_dev_attr_fan1_div.dev_attr.attr, + &sensor_dev_attr_fan2_div.dev_attr.attr, + &sensor_dev_attr_fan1_alarm.dev_attr.attr, + &sensor_dev_attr_fan2_alarm.dev_attr.attr, + &sensor_dev_attr_fan1_beep.dev_attr.attr, + &sensor_dev_attr_fan2_beep.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_temp1_beep.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, @@ -377,6 +457,17 @@ static const struct attribute_group gl518_group = { .attrs = gl518_attributes, }; +static struct attribute *gl518_attributes_r80[] = { + &dev_attr_in0_input.attr, + &dev_attr_in1_input.attr, + &dev_attr_in2_input.attr, + NULL +}; + +static const struct attribute_group gl518_group_r80 = { + .attrs = gl518_attributes_r80, +}; + /* * Real code */ @@ -391,7 +482,7 @@ static int gl518_attach_adapter(struct i2c_adapter *adapter) static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) { int i; - struct i2c_client *new_client; + struct i2c_client *client; struct gl518_data *data; int err = 0; @@ -408,25 +499,24 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); + client = &data->client; + i2c_set_clientdata(client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl518_driver; - new_client->flags = 0; + client->addr = address; + client->adapter = adapter; + client->driver = &gl518_driver; /* Now, we do the remaining detection. */ if (kind < 0) { - if ((gl518_read_value(new_client, GL518_REG_CHIP_ID) != 0x80) - || (gl518_read_value(new_client, GL518_REG_CONF) & 0x80)) + if ((gl518_read_value(client, GL518_REG_CHIP_ID) != 0x80) + || (gl518_read_value(client, GL518_REG_CONF) & 0x80)) goto exit_free; } /* Determine the chip type. */ if (kind <= 0) { - i = gl518_read_value(new_client, GL518_REG_REVISION); + i = gl518_read_value(client, GL518_REG_REVISION); if (i == 0x00) { kind = gl518sm_r00; } else if (i == 0x80) { @@ -442,25 +532,27 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) } /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl518sm", I2C_NAME_SIZE); + strlcpy(client->name, "gl518sm", 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 exit_free; /* Initialize the GL518SM chip */ data->alarm_mask = 0xff; - data->voltage_in[0]=data->voltage_in[1]=data->voltage_in[2]=0; - gl518_init_client((struct i2c_client *) new_client); + gl518_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &gl518_group))) goto exit_detach; + if (data->type == gl518sm_r80) + if ((err = sysfs_create_group(&client->dev.kobj, + &gl518_group_r80))) + goto exit_remove_files; - data->hwmon_dev = hwmon_device_register(&new_client->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; @@ -469,9 +561,11 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &gl518_group); + sysfs_remove_group(&client->dev.kobj, &gl518_group); + if (data->type == gl518sm_r80) + sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -504,6 +598,8 @@ static int gl518_detach_client(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &gl518_group); + if (data->type == gl518sm_r80) + sysfs_remove_group(&client->dev.kobj, &gl518_group_r80); if ((err = i2c_detach_client(client))) return err; @@ -512,9 +608,9 @@ static int gl518_detach_client(struct i2c_client *client) return 0; } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ + the SMBus standard. */ static int gl518_read_value(struct i2c_client *client, u8 reg) { if ((reg >= 0x07) && (reg <= 0x0c)) @@ -523,9 +619,6 @@ static int gl518_read_value(struct i2c_client *client, u8 reg) return i2c_smbus_read_byte_data(client, reg); } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized - GL518 uses a high-byte first convention, which is exactly opposite to - the usual practice. */ static int gl518_write_value(struct i2c_client *client, u8 reg, u16 value) { if ((reg >= 0x07) && (reg <= 0x0c)) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index 2d39d8f..03ecdc3 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -43,9 +44,9 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(gl520sm); -/* Many GL520 constants specified below +/* Many GL520 constants specified below One of the inputs can be configured as either temp or voltage. -That's why _TEMP2 and _IN4 access the same register +That's why _TEMP2 and _IN4 access the same register */ /* The GL520 registers */ @@ -56,37 +57,14 @@ That's why _TEMP2 and _IN4 access the same register #define GL520_REG_VID_INPUT 0x02 -#define GL520_REG_IN0_INPUT 0x15 -#define GL520_REG_IN0_LIMIT 0x0c -#define GL520_REG_IN0_MIN GL520_REG_IN0_LIMIT -#define GL520_REG_IN0_MAX GL520_REG_IN0_LIMIT +static const u8 GL520_REG_IN_INPUT[] = { 0x15, 0x14, 0x13, 0x0d, 0x0e }; +static const u8 GL520_REG_IN_LIMIT[] = { 0x0c, 0x09, 0x0a, 0x0b }; +static const u8 GL520_REG_IN_MIN[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x18 }; +static const u8 GL520_REG_IN_MAX[] = { 0x0c, 0x09, 0x0a, 0x0b, 0x17 }; -#define GL520_REG_IN1_INPUT 0x14 -#define GL520_REG_IN1_LIMIT 0x09 -#define GL520_REG_IN1_MIN GL520_REG_IN1_LIMIT -#define GL520_REG_IN1_MAX GL520_REG_IN1_LIMIT - -#define GL520_REG_IN2_INPUT 0x13 -#define GL520_REG_IN2_LIMIT 0x0a -#define GL520_REG_IN2_MIN GL520_REG_IN2_LIMIT -#define GL520_REG_IN2_MAX GL520_REG_IN2_LIMIT - -#define GL520_REG_IN3_INPUT 0x0d -#define GL520_REG_IN3_LIMIT 0x0b -#define GL520_REG_IN3_MIN GL520_REG_IN3_LIMIT -#define GL520_REG_IN3_MAX GL520_REG_IN3_LIMIT - -#define GL520_REG_IN4_INPUT 0x0e -#define GL520_REG_IN4_MAX 0x17 -#define GL520_REG_IN4_MIN 0x18 - -#define GL520_REG_TEMP1_INPUT 0x04 -#define GL520_REG_TEMP1_MAX 0x05 -#define GL520_REG_TEMP1_MAX_HYST 0x06 - -#define GL520_REG_TEMP2_INPUT 0x0e -#define GL520_REG_TEMP2_MAX 0x17 -#define GL520_REG_TEMP2_MAX_HYST 0x18 +static const u8 GL520_REG_TEMP_INPUT[] = { 0x04, 0x0e }; +static const u8 GL520_REG_TEMP_MAX[] = { 0x05, 0x17 }; +static const u8 GL520_REG_TEMP_MAX_HYST[] = { 0x06, 0x18 }; #define GL520_REG_FAN_INPUT 0x07 #define GL520_REG_FAN_MIN 0x08 @@ -114,7 +92,6 @@ static struct i2c_driver gl520_driver = { .driver = { .name = "gl520sm", }, - .id = I2C_DRIVERID_GL520, .attach_adapter = gl520_attach_adapter, .detach_client = gl520_detach_client, }; @@ -150,93 +127,13 @@ struct gl520_data { * Sysfs stuff */ -#define sysfs_r(type, n, item, reg) \ -static ssize_t get_##type##item (struct gl520_data *, char *, int); \ -static ssize_t get_##type##n##item (struct device *, struct device_attribute *attr, char *); \ -static ssize_t get_##type##n##item (struct device *dev, struct device_attribute *attr, char *buf) \ -{ \ - struct gl520_data *data = gl520_update_device(dev); \ - return get_##type##item(data, buf, (n)); \ -} - -#define sysfs_w(type, n, item, reg) \ -static ssize_t set_##type##item (struct i2c_client *, struct gl520_data *, const char *, size_t, int, int); \ -static ssize_t set_##type##n##item (struct device *, struct device_attribute *attr, const char *, size_t); \ -static ssize_t set_##type##n##item (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct i2c_client *client = to_i2c_client(dev); \ - struct gl520_data *data = i2c_get_clientdata(client); \ - return set_##type##item(client, data, buf, count, (n), reg); \ -} - -#define sysfs_rw_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -sysfs_w(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO | S_IWUSR, get_##type##n##item, set_##type##n##item); - -#define sysfs_ro_n(type, n, item, reg) \ -sysfs_r(type, n, item, reg) \ -static DEVICE_ATTR(type##n##item, S_IRUGO, get_##type##n##item, NULL); - -#define sysfs_rw(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -sysfs_w(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO | S_IWUSR, get_##type##0##item, set_##type##0##item); - -#define sysfs_ro(type, item, reg) \ -sysfs_r(type, 0, item, reg) \ -static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL); - - -#define sysfs_vid(n) \ -sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT) - -#define sysfs_in(n) \ -sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \ -sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \ -sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \ - -#define sysfs_fan(n) \ -sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \ -sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \ -sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV) - -#define sysfs_fan_off(n) \ -sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \ - -#define sysfs_temp(n) \ -sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \ -sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \ -sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST) - -#define sysfs_alarms() \ -sysfs_ro(alarms, , GL520_REG_ALARMS) \ -sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \ -sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK) - - -sysfs_vid(0) - -sysfs_in(0) -sysfs_in(1) -sysfs_in(2) -sysfs_in(3) -sysfs_in(4) - -sysfs_fan(1) -sysfs_fan(2) -sysfs_fan_off(1) - -sysfs_temp(1) -sysfs_temp(2) - -sysfs_alarms() - - -static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) +static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } +static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); #define VDD_FROM_REG(val) (((val)*95+2)/4) #define VDD_TO_REG(val) (SENSORS_LIMIT((((val)*4+47)/95),0,255)) @@ -244,8 +141,11 @@ static ssize_t get_cpu_vid(struct gl520_data *data, char *buf, int n) #define IN_FROM_REG(val) ((val)*19) #define IN_TO_REG(val) (SENSORS_LIMIT((((val)+9)/19),0,255)) -static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_input[n]; if (n == 0) @@ -254,8 +154,11 @@ static ssize_t get_in_input(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_min(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_min[n]; if (n == 0) @@ -264,8 +167,11 @@ static ssize_t get_in_min(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) +static ssize_t get_in_max(struct device *dev, struct device_attribute *attr, + char *buf) { + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); u8 r = data->in_max[n]; if (n == 0) @@ -274,8 +180,12 @@ static ssize_t get_in_max(struct gl520_data *data, char *buf, int n) return sprintf(buf, "%d\n", IN_FROM_REG(r)); } -static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); u8 r; @@ -289,16 +199,22 @@ static ssize_t set_in_min(struct i2c_client *client, struct gl520_data *data, co data->in_min[n] = r; if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + gl520_write_value(client, GL520_REG_IN_MIN[n], + (gl520_read_value(client, GL520_REG_IN_MIN[n]) + & ~0xff) | r); else - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_IN_MIN[n], r); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); u8 r; @@ -312,57 +228,109 @@ static ssize_t set_in_max(struct i2c_client *client, struct gl520_data *data, co data->in_max[n] = r; if (n < 4) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + gl520_write_value(client, GL520_REG_IN_MAX[n], + (gl520_read_value(client, GL520_REG_IN_MAX[n]) + & ~0xff00) | (r << 8)); else - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_IN_MAX[n], r); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, get_in_input, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, get_in_input, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, get_in_input, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, get_in_input, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, get_in_input, NULL, 4); +static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 0); +static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 1); +static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 2); +static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 3); +static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR, + get_in_min, set_in_min, 4); +static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 0); +static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 1); +static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 2); +static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 3); +static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, + get_in_max, set_in_max, 4); + #define DIV_FROM_REG(val) (1 << (val)) #define FAN_FROM_REG(val,div) ((val)==0 ? 0 : (480000/((val) << (div)))) #define FAN_TO_REG(val,div) ((val)<=0?0:SENSORS_LIMIT((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)); -static ssize_t get_fan_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n - 1], data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_input[n], + data->fan_div[n])); } -static ssize_t get_fan_min(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_min(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n - 1], data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[n], + data->fan_div[n])); } -static ssize_t get_fan_div(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n])); } -static ssize_t get_fan_off(struct gl520_data *data, char *buf, int n) +static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->fan_off); } -static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; mutex_lock(&data->update_lock); - r = FAN_TO_REG(v, data->fan_div[n - 1]); - data->fan_min[n - 1] = r; + r = FAN_TO_REG(v, data->fan_div[n]); + data->fan_min[n] = r; - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff00) | (r << 8)); + if (n == 0) + gl520_write_value(client, GL520_REG_FAN_MIN, + (gl520_read_value(client, GL520_REG_FAN_MIN) + & ~0xff00) | (r << 8)); else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xff) | r); + gl520_write_value(client, GL520_REG_FAN_MIN, + (gl520_read_value(client, GL520_REG_FAN_MIN) + & ~0xff) | r); data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); - if (data->fan_min[n - 1] == 0) - data->alarm_mask &= (n == 1) ? ~0x20 : ~0x40; + if (data->fan_min[n] == 0) + data->alarm_mask &= (n == 0) ? ~0x20 : ~0x40; else - data->alarm_mask |= (n == 1) ? 0x20 : 0x40; + data->alarm_mask |= (n == 0) ? 0x20 : 0x40; data->beep_mask &= data->alarm_mask; gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); @@ -370,8 +338,12 @@ static ssize_t set_fan_min(struct i2c_client *client, struct gl520_data *data, c return count; } -static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; unsigned long v = simple_strtoul(buf, NULL, 10); u8 r; @@ -386,133 +358,282 @@ static ssize_t set_fan_div(struct i2c_client *client, struct gl520_data *data, c } mutex_lock(&data->update_lock); - data->fan_div[n - 1] = r; + data->fan_div[n] = r; - if (n == 1) - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0xc0) | (r << 6)); + if (n == 0) + gl520_write_value(client, GL520_REG_FAN_DIV, + (gl520_read_value(client, GL520_REG_FAN_DIV) + & ~0xc0) | (r << 6)); else - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x30) | (r << 4)); + gl520_write_value(client, GL520_REG_FAN_DIV, + (gl520_read_value(client, GL520_REG_FAN_DIV) + & ~0x30) | (r << 4)); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_fan_off(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10)?1:0; mutex_lock(&data->update_lock); data->fan_off = r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x0c) | (r << 2)); + gl520_write_value(client, GL520_REG_FAN_OFF, + (gl520_read_value(client, GL520_REG_FAN_OFF) + & ~0x0c) | (r << 2)); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_input, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan_input, NULL, 1); +static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, + get_fan_min, set_fan_min, 0); +static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR, + get_fan_min, set_fan_min, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, + get_fan_div, set_fan_div, 0); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, + get_fan_div, set_fan_div, 1); +static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, + get_fan_off, set_fan_off); + #define TEMP_FROM_REG(val) (((val) - 130) * 1000) #define TEMP_TO_REG(val) (SENSORS_LIMIT(((((val)<0?(val)-500:(val)+500) / 1000)+130),0,255)) -static ssize_t get_temp_input(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_input[n])); } -static ssize_t get_temp_max(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_max(struct device *dev, struct device_attribute *attr, + char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[n])); } -static ssize_t get_temp_max_hyst(struct gl520_data *data, char *buf, int n) +static ssize_t get_temp_max_hyst(struct device *dev, struct device_attribute + *attr, char *buf) { - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n - 1])); + int n = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max_hyst[n])); } -static ssize_t set_temp_max(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); - data->temp_max[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max[n - 1]); + data->temp_max[n] = TEMP_TO_REG(v); + gl520_write_value(client, GL520_REG_TEMP_MAX[n], data->temp_max[n]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp_max_hyst(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_temp_max_hyst(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int n = to_sensor_dev_attr(attr)->index; long v = simple_strtol(buf, NULL, 10); mutex_lock(&data->update_lock); - data->temp_max_hyst[n - 1] = TEMP_TO_REG(v); - gl520_write_value(client, reg, data->temp_max_hyst[n - 1]); + data->temp_max_hyst[n] = TEMP_TO_REG(v); + gl520_write_value(client, GL520_REG_TEMP_MAX_HYST[n], + data->temp_max_hyst[n]); mutex_unlock(&data->update_lock); return count; } -static ssize_t get_alarms(struct gl520_data *data, char *buf, int n) +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, get_temp_input, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, get_temp_input, NULL, 1); +static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, + get_temp_max, set_temp_max, 0); +static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, + get_temp_max, set_temp_max, 1); +static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, + get_temp_max_hyst, set_temp_max_hyst, 0); +static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, + get_temp_max_hyst, set_temp_max_hyst, 1); + +static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static ssize_t get_beep_enable(struct gl520_data *data, char *buf, int n) +static ssize_t get_beep_enable(struct device *dev, struct device_attribute + *attr, char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_enable); } -static ssize_t get_beep_mask(struct gl520_data *data, char *buf, int n) +static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr, + char *buf) { + struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_mask); } -static ssize_t set_beep_enable(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_beep_enable(struct device *dev, struct device_attribute + *attr, const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10)?0:1; mutex_lock(&data->update_lock); data->beep_enable = !r; - gl520_write_value(client, reg, (gl520_read_value(client, reg) & ~0x04) | (r << 2)); + gl520_write_value(client, GL520_REG_BEEP_ENABLE, + (gl520_read_value(client, GL520_REG_BEEP_ENABLE) + & ~0x04) | (r << 2)); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data, const char *buf, size_t count, int n, int reg) +static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); u8 r = simple_strtoul(buf, NULL, 10); - + mutex_lock(&data->update_lock); r &= data->alarm_mask; data->beep_mask = r; - gl520_write_value(client, reg, r); + gl520_write_value(client, GL520_REG_BEEP_MASK, r); + mutex_unlock(&data->update_lock); + return count; +} + +static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); +static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, + get_beep_enable, set_beep_enable); +static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, + get_beep_mask, set_beep_mask); + +static ssize_t get_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bit_nr = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", (data->alarms >> bit_nr) & 1); +} + +static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, get_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, get_alarm, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, get_alarm, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, get_alarm, NULL, 3); +static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, get_alarm, NULL, 4); +static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, get_alarm, NULL, 5); +static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, get_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, get_alarm, NULL, 7); +static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, get_alarm, NULL, 7); + +static ssize_t get_beep(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int bitnr = to_sensor_dev_attr(attr)->index; + struct gl520_data *data = gl520_update_device(dev); + + return sprintf(buf, "%d\n", (data->beep_mask >> bitnr) & 1); +} + +static ssize_t set_beep(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct gl520_data *data = i2c_get_clientdata(client); + int bitnr = to_sensor_dev_attr(attr)->index; + unsigned long bit; + + bit = simple_strtoul(buf, NULL, 10); + if (bit & ~1) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); + if (bit) + data->beep_mask |= (1 << bitnr); + else + data->beep_mask &= ~(1 << bitnr); + gl520_write_value(client, GL520_REG_BEEP_MASK, data->beep_mask); mutex_unlock(&data->update_lock); return count; } +static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 0); +static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 1); +static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 2); +static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 3); +static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 4); +static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 5); +static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 6); +static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7); +static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO | S_IWUSR, get_beep, set_beep, 7); + static struct attribute *gl520_attributes[] = { &dev_attr_cpu0_vid.attr, - &dev_attr_in0_input.attr, - &dev_attr_in0_min.attr, - &dev_attr_in0_max.attr, - &dev_attr_in1_input.attr, - &dev_attr_in1_min.attr, - &dev_attr_in1_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_fan1_input.attr, - &dev_attr_fan1_min.attr, - &dev_attr_fan1_div.attr, + &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_in0_beep.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_in1_beep.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_in2_beep.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_in3_beep.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_fan1_beep.dev_attr.attr, &dev_attr_fan1_off.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, + &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_fan2_beep.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, + &sensor_dev_attr_temp1_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_beep.dev_attr.attr, &dev_attr_alarms.attr, &dev_attr_beep_enable.attr, @@ -525,13 +646,17 @@ static const struct attribute_group gl520_group = { }; static struct attribute *gl520_attributes_opt[] = { - &dev_attr_in4_input.attr, - &dev_attr_in4_min.attr, - &dev_attr_in4_max.attr, - - &dev_attr_temp2_input.attr, - &dev_attr_temp2_max.attr, - &dev_attr_temp2_max_hyst.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_in4_beep.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_temp2_alarm.dev_attr.attr, + &sensor_dev_attr_temp2_beep.dev_attr.attr, NULL }; @@ -553,7 +678,7 @@ static int gl520_attach_adapter(struct i2c_adapter *adapter) static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) { - struct i2c_client *new_client; + struct i2c_client *client; struct gl520_data *data; int err = 0; @@ -570,59 +695,65 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) goto exit; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &gl520_driver; - new_client->flags = 0; + client = &data->client; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &gl520_driver; /* Determine the chip type. */ if (kind < 0) { - if ((gl520_read_value(new_client, GL520_REG_CHIP_ID) != 0x20) || - ((gl520_read_value(new_client, GL520_REG_REVISION) & 0x7f) != 0x00) || - ((gl520_read_value(new_client, GL520_REG_CONF) & 0x80) != 0x00)) { - dev_dbg(&new_client->dev, "Unknown chip type, skipping\n"); + if ((gl520_read_value(client, GL520_REG_CHIP_ID) != 0x20) || + ((gl520_read_value(client, GL520_REG_REVISION) & 0x7f) != 0x00) || + ((gl520_read_value(client, GL520_REG_CONF) & 0x80) != 0x00)) { + dev_dbg(&client->dev, "Unknown chip type, skipping\n"); goto exit_free; } } /* Fill in the remaining client fields */ - strlcpy(new_client->name, "gl520sm", I2C_NAME_SIZE); - data->valid = 0; + strlcpy(client->name, "gl520sm", I2C_NAME_SIZE); 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 exit_free; /* Initialize the GL520SM chip */ - gl520_init_client(new_client); + gl520_init_client(client); /* Register sysfs hooks */ - if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group))) + if ((err = sysfs_create_group(&client->dev.kobj, &gl520_group))) goto exit_detach; if (data->two_temps) { - if ((err = device_create_file(&new_client->dev, - &dev_attr_temp2_input)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp2_max)) - || (err = device_create_file(&new_client->dev, - &dev_attr_temp2_max_hyst))) + if ((err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_input.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_max.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_max_hyst.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_alarm.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_temp2_beep.dev_attr))) goto exit_remove_files; } else { - 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 = device_create_file(&client->dev, + &sensor_dev_attr_in4_input.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_min.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_max.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_alarm.dev_attr)) + || (err = device_create_file(&client->dev, + &sensor_dev_attr_in4_beep.dev_attr))) goto exit_remove_files; } - data->hwmon_dev = hwmon_device_register(&new_client->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; @@ -631,10 +762,10 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind) return 0; exit_remove_files: - sysfs_remove_group(&new_client->dev.kobj, &gl520_group); - sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt); + sysfs_remove_group(&client->dev.kobj, &gl520_group); + sysfs_remove_group(&client->dev.kobj, &gl520_group_opt); exit_detach: - i2c_detach_client(new_client); + i2c_detach_client(client); exit_free: kfree(data); exit: @@ -697,7 +828,7 @@ static int gl520_detach_client(struct i2c_client *client) } -/* Registers 0x07 to 0x0c are word-sized, others are byte-sized +/* Registers 0x07 to 0x0c are word-sized, others are byte-sized GL520 uses a high-byte first convention */ static int gl520_read_value(struct i2c_client *client, u8 reg) { @@ -720,7 +851,7 @@ static struct gl520_data *gl520_update_device(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gl520_data *data = i2c_get_clientdata(client); - int val; + int val, i; mutex_lock(&data->update_lock); @@ -732,18 +863,13 @@ static struct gl520_data *gl520_update_device(struct device *dev) data->beep_mask = gl520_read_value(client, GL520_REG_BEEP_MASK); data->vid = gl520_read_value(client, GL520_REG_VID_INPUT) & 0x1f; - val = gl520_read_value(client, GL520_REG_IN0_LIMIT); - data->in_min[0] = val & 0xff; - data->in_max[0] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN1_LIMIT); - data->in_min[1] = val & 0xff; - data->in_max[1] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN2_LIMIT); - data->in_min[2] = val & 0xff; - data->in_max[2] = (val >> 8) & 0xff; - val = gl520_read_value(client, GL520_REG_IN3_LIMIT); - data->in_min[3] = val & 0xff; - data->in_max[3] = (val >> 8) & 0xff; + for (i = 0; i < 4; i++) { + data->in_input[i] = gl520_read_value(client, + GL520_REG_IN_INPUT[i]); + val = gl520_read_value(client, GL520_REG_IN_LIMIT[i]); + data->in_min[i] = val & 0xff; + data->in_max[i] = (val >> 8) & 0xff; + } val = gl520_read_value(client, GL520_REG_FAN_INPUT); data->fan_input[0] = (val >> 8) & 0xff; @@ -753,9 +879,12 @@ static struct gl520_data *gl520_update_device(struct device *dev) data->fan_min[0] = (val >> 8) & 0xff; data->fan_min[1] = val & 0xff; - data->temp_input[0] = gl520_read_value(client, GL520_REG_TEMP1_INPUT); - data->temp_max[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX); - data->temp_max_hyst[0] = gl520_read_value(client, GL520_REG_TEMP1_MAX_HYST); + data->temp_input[0] = gl520_read_value(client, + GL520_REG_TEMP_INPUT[0]); + data->temp_max[0] = gl520_read_value(client, + GL520_REG_TEMP_MAX[0]); + data->temp_max_hyst[0] = gl520_read_value(client, + GL520_REG_TEMP_MAX_HYST[0]); val = gl520_read_value(client, GL520_REG_FAN_DIV); data->fan_div[0] = (val >> 6) & 0x03; @@ -767,20 +896,21 @@ static struct gl520_data *gl520_update_device(struct device *dev) val = gl520_read_value(client, GL520_REG_CONF); data->beep_enable = !((val >> 2) & 1); - data->in_input[0] = gl520_read_value(client, GL520_REG_IN0_INPUT); - data->in_input[1] = gl520_read_value(client, GL520_REG_IN1_INPUT); - data->in_input[2] = gl520_read_value(client, GL520_REG_IN2_INPUT); - data->in_input[3] = gl520_read_value(client, GL520_REG_IN3_INPUT); - /* Temp1 and Vin4 are the same input */ if (data->two_temps) { - data->temp_input[1] = gl520_read_value(client, GL520_REG_TEMP2_INPUT); - data->temp_max[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX); - data->temp_max_hyst[1] = gl520_read_value(client, GL520_REG_TEMP2_MAX_HYST); + data->temp_input[1] = gl520_read_value(client, + GL520_REG_TEMP_INPUT[1]); + data->temp_max[1] = gl520_read_value(client, + GL520_REG_TEMP_MAX[1]); + data->temp_max_hyst[1] = gl520_read_value(client, + GL520_REG_TEMP_MAX_HYST[1]); } else { - data->in_input[4] = gl520_read_value(client, GL520_REG_IN4_INPUT); - data->in_min[4] = gl520_read_value(client, GL520_REG_IN4_MIN); - data->in_max[4] = gl520_read_value(client, GL520_REG_IN4_MAX); + data->in_input[4] = gl520_read_value(client, + GL520_REG_IN_INPUT[4]); + data->in_min[4] = gl520_read_value(client, + GL520_REG_IN_MIN[4]); + data->in_max[4] = gl520_read_value(client, + GL520_REG_IN_MAX[4]); } data->last_updated = jiffies; diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 3f7055e..934378e 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -37,10 +37,8 @@ static struct platform_device *pdev; /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, - 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; static unsigned short isa_address = 0x290; /* Insmod parameters */ diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 28cdff0..3ab4c3f 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -5,7 +5,7 @@ * Philip Edelbrock * Stephen Rousset * Dan Eaton - * Copyright (C) 2004 Jean Delvare + * Copyright (C) 2004,2007 Jean Delvare * * Original port to Linux 2.6 by Jeff Oliver. * @@ -37,6 +37,11 @@ * instead. The LM87 is the only hardware monitoring chipset I know of * which uses amplitude modulation. Be careful when using this feature. * + * This driver also supports the ADM1024, a sensor chip made by Analog + * Devices. That chip is fully compatible with the LM87. Complete + * datasheet can be obtained from Analog's website at: + * http://www.analog.com/en/prod/0,2877,ADM1024,00.html + * * 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 @@ -74,7 +79,7 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; * Insmod parameters */ -I2C_CLIENT_INSMOD_1(lm87); +I2C_CLIENT_INSMOD_2(lm87, adm1024); /* * The LM87 registers @@ -662,6 +667,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) struct i2c_client *new_client; struct lm87_data *data; int err = 0; + static const char *names[] = { "lm87", "adm1024" }; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) goto exit; @@ -686,11 +692,18 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) /* Now, we do the remaining detection. */ if (kind < 0) { + u8 cid = lm87_read_value(new_client, LM87_REG_COMPANY_ID); u8 rev = lm87_read_value(new_client, LM87_REG_REVISION); - if (rev < 0x01 || rev > 0x08 - || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80) - || lm87_read_value(new_client, LM87_REG_COMPANY_ID) != 0x02) { + if (cid == 0x02 /* National Semiconductor */ + && (rev >= 0x01 && rev <= 0x08)) + kind = lm87; + else if (cid == 0x41 /* Analog Devices */ + && (rev & 0xf0) == 0x10) + kind = adm1024; + + if (kind < 0 + || (lm87_read_value(new_client, LM87_REG_CONFIG) & 0x80)) { dev_dbg(&adapter->dev, "LM87 detection failed at 0x%02x.\n", address); @@ -699,7 +712,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind) } /* We can fill in the remaining client fields */ - strlcpy(new_client->name, "lm87", I2C_NAME_SIZE); + strlcpy(new_client->name, names[kind - 1], I2C_NAME_SIZE); data->valid = 0; mutex_init(&data->update_lock); diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 960df9f..116093d 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -531,24 +531,24 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind) kind = lm90; if (kind < 0) { /* detection and identification */ - u8 man_id, chip_id, reg_config1, reg_convrate; - - if (lm90_read_reg(new_client, LM90_REG_R_MAN_ID, - &man_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CHIP_ID, - &chip_id) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONFIG1, - ®_config1) < 0 - || lm90_read_reg(new_client, LM90_REG_R_CONVRATE, - ®_convrate) < 0) + int man_id, chip_id, reg_config1, reg_convrate; + + if ((man_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_MAN_ID)) < 0 + || (chip_id = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CHIP_ID)) < 0 + || (reg_config1 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG1)) < 0 + || (reg_convrate = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONVRATE)) < 0) goto exit_free; if ((address == 0x4C || address == 0x4D) && man_id == 0x01) { /* National Semiconductor */ - u8 reg_config2; + int reg_config2; - if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2, - ®_config2) < 0) + if ((reg_config2 = i2c_smbus_read_byte_data(new_client, + LM90_REG_R_CONFIG2)) < 0) goto exit_free; if ((reg_config1 & 0x2A) == 0x00 diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index e0fa752..d38b9ed 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -54,9 +54,8 @@ static struct platform_device *pdev; /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; static unsigned short isa_address = 0x290; /* Insmod parameters */ @@ -1270,7 +1269,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind) kind = w83783s; else if (val1 == 0x21 && vendid == winbond) kind = w83627hf; - else if (val1 == 0x31 && address >= 0x28) + else if (val1 == 0x31) kind = as99127f; else { if (kind == 0) diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 48599e1..6b5c99c 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -131,6 +131,7 @@ static u8 scale_in_add[] = { 0, 0, 0, 0, 0, 0, 0, 150, 150, 0 }; #define PWM_DUTY 0 #define PWM_START 1 #define PWM_NONSTOP 2 +#define PWM_STOP_TIME 3 #define W83793_REG_PWM(index, nr) (((nr) == 0 ? 0xb3 : \ (nr) == 1 ? 0x220 : 0x218) + (index)) @@ -407,10 +408,6 @@ store_fan_min(struct device *dev, struct device_attribute *attr, return count; } -#define PWM_DUTY 0 -#define PWM_START 1 -#define PWM_NONSTOP 2 -#define PWM_STOP_TIME 3 static ssize_t show_pwm(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/hwmon/w83l786ng.c b/drivers/hwmon/w83l786ng.c new file mode 100644 index 0000000..1dbee4f --- /dev/null +++ b/drivers/hwmon/w83l786ng.c @@ -0,0 +1,821 @@ +/* + w83l786ng.c - Linux kernel driver for hardware monitoring + Copyright (c) 2007 Kevin Lo + + 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 - version 2. + + 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., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + w83l786ng 3 2 2 2 0x7b 0x5ca3 yes no +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { 0x2e, 0x2f, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(w83l786ng); + +static int reset; +module_param(reset, bool, 0); +MODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); + +#define W83L786NG_REG_IN_MIN(nr) (0x2C + (nr) * 2) +#define W83L786NG_REG_IN_MAX(nr) (0x2B + (nr) * 2) +#define W83L786NG_REG_IN(nr) ((nr) + 0x20) + +#define W83L786NG_REG_FAN(nr) ((nr) + 0x28) +#define W83L786NG_REG_FAN_MIN(nr) ((nr) + 0x3B) + +#define W83L786NG_REG_CONFIG 0x40 +#define W83L786NG_REG_ALARM1 0x41 +#define W83L786NG_REG_ALARM2 0x42 +#define W83L786NG_REG_GPIO_EN 0x47 +#define W83L786NG_REG_MAN_ID2 0x4C +#define W83L786NG_REG_MAN_ID1 0x4D +#define W83L786NG_REG_CHIP_ID 0x4E + +#define W83L786NG_REG_DIODE 0x53 +#define W83L786NG_REG_FAN_DIV 0x54 +#define W83L786NG_REG_FAN_CFG 0x80 + +#define W83L786NG_REG_TOLERANCE 0x8D + +static const u8 W83L786NG_REG_TEMP[2][3] = { + { 0x25, /* TEMP 0 in DataSheet */ + 0x35, /* TEMP 0 Over in DataSheet */ + 0x36 }, /* TEMP 0 Hyst in DataSheet */ + { 0x26, /* TEMP 1 in DataSheet */ + 0x37, /* TEMP 1 Over in DataSheet */ + 0x38 } /* TEMP 1 Hyst in DataSheet */ +}; + +static const u8 W83L786NG_PWM_MODE_SHIFT[] = {6, 7}; +static const u8 W83L786NG_PWM_ENABLE_SHIFT[] = {2, 4}; + +/* FAN Duty Cycle, be used to control */ +static const u8 W83L786NG_REG_PWM[] = {0x81, 0x87}; + + +static inline u8 +FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ + ((val) == 255 ? 0 : \ + 1350000 / ((val) * (div)))) + +/* for temp */ +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \ + : (val)) / 1000, 0, 0xff)) +#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000) + +/* The analog voltage inputs have 8mV LSB. Since the sysfs output is + in mV as would be measured on the chip input pin, need to just + multiply/divide by 8 to translate from/to register values. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 4) / 8), 0, 255)) +#define IN_FROM_REG(val) ((val) * 8) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 +DIV_TO_REG(long val) +{ + int i; + val = SENSORS_LIMIT(val, 1, 128) >> 1; + for (i = 0; i < 7; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +struct w83l786ng_data { + struct i2c_client client; + 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_nonvolatile; /* In jiffies, last time we update the + nonvolatile registers */ + + u8 in[3]; + u8 in_max[3]; + u8 in_min[3]; + u8 fan[2]; + u8 fan_div[2]; + u8 fan_min[2]; + u8 temp_type[2]; + u8 temp[2][3]; + u8 pwm[2]; + u8 pwm_mode[2]; /* 0->DC variable voltage + 1->PWM variable duty cycle */ + + u8 pwm_enable[2]; /* 1->manual + 2->thermal cruise (also called SmartFan I) */ + u8 tolerance[2]; +}; + +static int w83l786ng_attach_adapter(struct i2c_adapter *adapter); +static int w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind); +static int w83l786ng_detach_client(struct i2c_client *client); +static void w83l786ng_init_client(struct i2c_client *client); +static struct w83l786ng_data *w83l786ng_update_device(struct device *dev); + +static struct i2c_driver w83l786ng_driver = { + .driver = { + .name = "w83l786ng", + }, + .attach_adapter = w83l786ng_attach_adapter, + .detach_client = w83l786ng_detach_client, +}; + +static u8 +w83l786ng_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int +w83l786ng_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t \ +show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + int nr = to_sensor_dev_attr(attr)->index; \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + return sprintf(buf,"%d\n", IN_FROM_REG(data->reg[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, 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 w83l786ng_data *data = i2c_get_clientdata(client); \ + unsigned long val = simple_strtoul(buf, NULL, 10); \ + mutex_lock(&data->update_lock); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83l786ng_write_value(client, W83L786NG_REG_IN_##REG(nr), \ + data->in_##reg[nr]); \ + mutex_unlock(&data->update_lock); \ + return count; \ +} + +store_in_reg(MIN, min) +store_in_reg(MAX, max) + +static struct sensor_device_attribute sda_in_input[] = { + SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), +}; + +static struct sensor_device_attribute sda_in_min[] = { + SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0), + SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1), + SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2), +}; + +static struct sensor_device_attribute sda_in_max[] = { + SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0), + SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1), + SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2), +}; + +#define show_fan_reg(reg) \ +static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + int nr = to_sensor_dev_attr(attr)->index; \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + return sprintf(buf,"%d\n", \ + FAN_FROM_REG(data->fan[nr], 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, 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 w83l786ng_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + mutex_lock(&data->update_lock); + data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), + data->fan_min[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t +show_fan_div(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%u\n", 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(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 w83l786ng_data *data = i2c_get_clientdata(client); + + unsigned long min; + u8 tmp_fan_div; + u8 fan_div_reg; + u8 keep_mask = 0; + u8 new_shift = 0; + + /* Save fan_min */ + mutex_lock(&data->update_lock); + min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + + data->fan_div[nr] = DIV_TO_REG(simple_strtoul(buf, NULL, 10)); + + switch (nr) { + case 0: + keep_mask = 0xf8; + new_shift = 0; + break; + case 1: + keep_mask = 0x8f; + new_shift = 4; + break; + } + + fan_div_reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV) + & keep_mask; + + tmp_fan_div = (data->fan_div[nr] << new_shift) & ~keep_mask; + + w83l786ng_write_value(client, W83L786NG_REG_FAN_DIV, + fan_div_reg | tmp_fan_div); + + /* Restore fan_min */ + data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + w83l786ng_write_value(client, W83L786NG_REG_FAN_MIN(nr), + data->fan_min[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute sda_fan_input[] = { + SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0), + SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1), +}; + +static struct sensor_device_attribute sda_fan_min[] = { + SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, + store_fan_min, 0), + SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, + store_fan_min, 1), +}; + +static struct sensor_device_attribute sda_fan_div[] = { + SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, + store_fan_div, 0), + SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, + store_fan_div, 1), +}; + + +/* read/write the temperature, includes measured value and limits */ + +static ssize_t +show_temp(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); +} + +static ssize_t +store_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct sensor_device_attribute_2 *sensor_attr = + to_sensor_dev_attr_2(attr); + int nr = sensor_attr->nr; + int index = sensor_attr->index; + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + s32 val; + + val = simple_strtol(buf, NULL, 10); + mutex_lock(&data->update_lock); + data->temp[nr][index] = TEMP_TO_REG(val); + w83l786ng_write_value(client, W83L786NG_REG_TEMP[nr][index], + data->temp[nr][index]); + mutex_unlock(&data->update_lock); + + return count; +} + +static struct sensor_device_attribute_2 sda_temp_input[] = { + SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), + SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0), +}; + +static struct sensor_device_attribute_2 sda_temp_max[] = { + SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0, 1), + SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, + show_temp, store_temp, 1, 1), +}; + +static struct sensor_device_attribute_2 sda_temp_max_hyst[] = { + SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, + show_temp, store_temp, 0, 2), + SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, + show_temp, store_temp, 1, 2), +}; + +#define show_pwm_reg(reg) \ +static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct w83l786ng_data *data = w83l786ng_update_device(dev); \ + int nr = to_sensor_dev_attr(attr)->index; \ + return sprintf(buf, "%d\n", data->reg[nr]); \ +} + +show_pwm_reg(pwm_mode) +show_pwm_reg(pwm_enable) +show_pwm_reg(pwm) + +static ssize_t +store_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 w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + u8 reg; + + if (val > 1) + return -EINVAL; + mutex_lock(&data->update_lock); + data->pwm_mode[nr] = val; + reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + reg &= ~(1 << W83L786NG_PWM_MODE_SHIFT[nr]); + if (!val) + reg |= 1 << W83L786NG_PWM_MODE_SHIFT[nr]; + w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_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 w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255); + + mutex_lock(&data->update_lock); + data->pwm[nr] = val; + w83l786ng_write_value(client, W83L786NG_REG_PWM[nr], val); + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t +store_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 w83l786ng_data *data = i2c_get_clientdata(client); + u32 val = simple_strtoul(buf, NULL, 10); + + u8 reg; + + if (!val || (val > 2)) /* only modes 1 and 2 are supported */ + return -EINVAL; + + mutex_lock(&data->update_lock); + reg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + data->pwm_enable[nr] = val; + reg &= ~(0x02 << W83L786NG_PWM_ENABLE_SHIFT[nr]); + reg |= (val - 1) << W83L786NG_PWM_ENABLE_SHIFT[nr]; + w83l786ng_write_value(client, W83L786NG_REG_FAN_CFG, reg); + mutex_unlock(&data->update_lock); + return count; +} + +static struct sensor_device_attribute sda_pwm[] = { + SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0), + SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1), +}; + +static struct sensor_device_attribute sda_pwm_mode[] = { + SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 0), + SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode, + store_pwm_mode, 1), +}; + +static struct sensor_device_attribute sda_pwm_enable[] = { + SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 0), + SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable, + store_pwm_enable, 1), +}; + +/* For Smart Fan I/Thermal Cruise and Smart Fan II */ +static ssize_t +show_tolerance(struct device *dev, struct device_attribute *attr, char *buf) +{ + int nr = to_sensor_dev_attr(attr)->index; + struct w83l786ng_data *data = w83l786ng_update_device(dev); + return sprintf(buf, "%ld\n", (long)data->tolerance[nr]); +} + +static ssize_t +store_tolerance(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 w83l786ng_data *data = i2c_get_clientdata(client); + u32 val; + u8 tol_tmp, tol_mask; + + val = simple_strtoul(buf, NULL, 10); + + mutex_lock(&data->update_lock); + tol_mask = w83l786ng_read_value(client, + W83L786NG_REG_TOLERANCE) & ((nr == 1) ? 0x0f : 0xf0); + tol_tmp = SENSORS_LIMIT(val, 0, 15); + tol_tmp &= 0x0f; + data->tolerance[nr] = tol_tmp; + if (nr == 1) { + tol_tmp <<= 4; + } + + w83l786ng_write_value(client, W83L786NG_REG_TOLERANCE, + tol_mask | tol_tmp); + mutex_unlock(&data->update_lock); + return count; +} + +static struct sensor_device_attribute sda_tolerance[] = { + SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 0), + SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, + show_tolerance, store_tolerance, 1), +}; + + +#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 + +#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 + +#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 + +#define PWM_UNIT_ATTRS(X) \ + &sda_pwm[X].dev_attr.attr, \ + &sda_pwm_mode[X].dev_attr.attr, \ + &sda_pwm_enable[X].dev_attr.attr + +#define TOLERANCE_UNIT_ATTRS(X) \ + &sda_tolerance[X].dev_attr.attr + +static struct attribute *w83l786ng_attributes[] = { + IN_UNIT_ATTRS(0), + IN_UNIT_ATTRS(1), + IN_UNIT_ATTRS(2), + FAN_UNIT_ATTRS(0), + FAN_UNIT_ATTRS(1), + TEMP_UNIT_ATTRS(0), + TEMP_UNIT_ATTRS(1), + PWM_UNIT_ATTRS(0), + PWM_UNIT_ATTRS(1), + TOLERANCE_UNIT_ATTRS(0), + TOLERANCE_UNIT_ATTRS(1), + NULL +}; + +static const struct attribute_group w83l786ng_group = { + .attrs = w83l786ng_attributes, +}; + +static int +w83l786ng_attach_adapter(struct i2c_adapter *adapter) +{ + if (!(adapter->class & I2C_CLASS_HWMON)) + return 0; + return i2c_probe(adapter, &addr_data, w83l786ng_detect); +} + +static int +w83l786ng_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *client; + struct device *dev; + struct w83l786ng_data *data; + int i, err = 0; + u8 reg_tmp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + goto exit; + } + + /* 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 w83l786ng_{read,write}_value. */ + + if (!(data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL))) { + err = -ENOMEM; + goto exit; + } + + client = &data->client; + dev = &client->dev; + i2c_set_clientdata(client, data); + client->addr = address; + client->adapter = adapter; + client->driver = &w83l786ng_driver; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip (actually there is only + * one possible kind of chip for now, W83L786NG). A zero kind means + * that the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + if (kind < 0) { /* detection */ + if (((w83l786ng_read_value(client, + W83L786NG_REG_CONFIG) & 0x80) != 0x00)) { + dev_dbg(&adapter->dev, + "W83L786NG detection failed at 0x%02x.\n", + address); + goto exit_free; + } + } + + if (kind <= 0) { /* identification */ + u16 man_id; + u8 chip_id; + + man_id = (w83l786ng_read_value(client, + W83L786NG_REG_MAN_ID1) << 8) + + w83l786ng_read_value(client, W83L786NG_REG_MAN_ID2); + chip_id = w83l786ng_read_value(client, W83L786NG_REG_CHIP_ID); + + if (man_id == 0x5CA3) { /* Winbond */ + if (chip_id == 0x80) { /* W83L786NG */ + kind = w83l786ng; + } + } + + if (kind <= 0) { /* identification failed */ + dev_info(&adapter->dev, + "Unsupported chip (man_id=0x%04X, " + "chip_id=0x%02X).\n", man_id, chip_id); + goto exit_free; + } + } + + /* Fill in the remaining client fields and put into the global list */ + strlcpy(client->name, "w83l786ng", I2C_NAME_SIZE); + mutex_init(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto exit_free; + + /* Initialize the chip */ + w83l786ng_init_client(client); + + /* A few vars need to be filled upon startup */ + for (i = 0; i < 2; i++) { + data->fan_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN_MIN(i)); + } + + /* Update the fan divisor */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); + data->fan_div[0] = reg_tmp & 0x07; + data->fan_div[1] = (reg_tmp >> 4) & 0x07; + + /* Register sysfs hooks */ + if ((err = sysfs_create_group(&client->dev.kobj, &w83l786ng_group))) + goto exit_remove; + + data->hwmon_dev = hwmon_device_register(dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + return 0; + + /* Unregister sysfs hooks */ + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); + i2c_detach_client(client); +exit_free: + kfree(data); +exit: + return err; +} + +static int +w83l786ng_detach_client(struct i2c_client *client) +{ + struct w83l786ng_data *data = i2c_get_clientdata(client); + int err; + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &w83l786ng_group); + + if ((err = i2c_detach_client(client))) + return err; + + kfree(data); + + return 0; +} + +static void +w83l786ng_init_client(struct i2c_client *client) +{ + u8 tmp; + + if (reset) + w83l786ng_write_value(client, W83L786NG_REG_CONFIG, 0x80); + + /* Start monitoring */ + tmp = w83l786ng_read_value(client, W83L786NG_REG_CONFIG); + if (!(tmp & 0x01)) + w83l786ng_write_value(client, W83L786NG_REG_CONFIG, tmp | 0x01); +} + +static struct w83l786ng_data *w83l786ng_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83l786ng_data *data = i2c_get_clientdata(client); + int i, j; + u8 reg_tmp, pwmcfg; + + mutex_lock(&data->update_lock); + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + dev_dbg(&client->dev, "Updating w83l786ng data.\n"); + + /* Update the voltages measured value and limits */ + for (i = 0; i < 3; i++) { + data->in[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN(i)); + data->in_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN_MIN(i)); + data->in_max[i] = w83l786ng_read_value(client, + W83L786NG_REG_IN_MAX(i)); + } + + /* Update the fan counts and limits */ + for (i = 0; i < 2; i++) { + data->fan[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN(i)); + data->fan_min[i] = w83l786ng_read_value(client, + W83L786NG_REG_FAN_MIN(i)); + } + + /* Update the fan divisor */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_FAN_DIV); + data->fan_div[0] = reg_tmp & 0x07; + data->fan_div[1] = (reg_tmp >> 4) & 0x07; + + pwmcfg = w83l786ng_read_value(client, W83L786NG_REG_FAN_CFG); + for (i = 0; i < 2; i++) { + data->pwm_mode[i] = + ((pwmcfg >> W83L786NG_PWM_MODE_SHIFT[i]) & 1) + ? 0 : 1; + data->pwm_enable[i] = + ((pwmcfg >> W83L786NG_PWM_ENABLE_SHIFT[i]) & 2) + 1; + data->pwm[i] = w83l786ng_read_value(client, + W83L786NG_REG_PWM[i]); + } + + + /* Update the temperature sensors */ + for (i = 0; i < 2; i++) { + for (j = 0; j < 3; j++) { + data->temp[i][j] = w83l786ng_read_value(client, + W83L786NG_REG_TEMP[i][j]); + } + } + + /* Update Smart Fan I/II tolerance */ + reg_tmp = w83l786ng_read_value(client, W83L786NG_REG_TOLERANCE); + data->tolerance[0] = reg_tmp & 0x0f; + data->tolerance[1] = (reg_tmp >> 4) & 0x0f; + + data->last_updated = jiffies; + data->valid = 1; + + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init +sensors_w83l786ng_init(void) +{ + return i2c_add_driver(&w83l786ng_driver); +} + +static void __exit +sensors_w83l786ng_exit(void) +{ + i2c_del_driver(&w83l786ng_driver); +} + +MODULE_AUTHOR("Kevin Lo"); +MODULE_DESCRIPTION("w83l786ng driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83l786ng_init); +module_exit(sensors_w83l786ng_exit); diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 88c8140..68f109b 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -130,7 +130,6 @@ These were originally in sensors.h in the lm_sensors package */ #define I2C_DRIVERID_LM78 1002 #define I2C_DRIVERID_LM75 1003 -#define I2C_DRIVERID_GL518 1004 #define I2C_DRIVERID_EEPROM 1005 #define I2C_DRIVERID_W83781D 1006 #define I2C_DRIVERID_LM80 1007 @@ -140,7 +139,6 @@ #define I2C_DRIVERID_BT869 1013 #define I2C_DRIVERID_MAXILIFE 1014 #define I2C_DRIVERID_MATORB 1015 -#define I2C_DRIVERID_GL520 1016 #define I2C_DRIVERID_THMC50 1017 #define I2C_DRIVERID_ADM1025 1020 #define I2C_DRIVERID_LM87 1021