diff options
-rw-r--r-- | Documentation/hwmon/f71805f | 14 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 5 | ||||
-rw-r--r-- | drivers/hwmon/f71805f.c | 230 |
3 files changed, 203 insertions, 46 deletions
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f index bc571f99d0ee..bfd0f154959c 100644 --- a/Documentation/hwmon/f71805f +++ b/Documentation/hwmon/f71805f | |||
@@ -6,6 +6,10 @@ Supported chips: | |||
6 | Prefix: 'f71805f' | 6 | Prefix: 'f71805f' |
7 | Addresses scanned: none, address read from Super I/O config space | 7 | Addresses scanned: none, address read from Super I/O config space |
8 | Datasheet: Provided by Fintek on request | 8 | Datasheet: Provided by Fintek on request |
9 | * Fintek F71872F/FG | ||
10 | Prefix: 'f71872f' | ||
11 | Addresses scanned: none, address read from Super I/O config space | ||
12 | Datasheet: Provided by Fintek on request | ||
9 | 13 | ||
10 | Author: Jean Delvare <khali@linux-fr.org> | 14 | Author: Jean Delvare <khali@linux-fr.org> |
11 | 15 | ||
@@ -30,6 +34,10 @@ source), 3 fans and 3 temperature sensors. | |||
30 | This chip also has fan controlling features, using either DC or PWM, in | 34 | This chip also has fan controlling features, using either DC or PWM, in |
31 | three different modes (one manual, two automatic). | 35 | three different modes (one manual, two automatic). |
32 | 36 | ||
37 | The Fintek F71872F/FG Super I/O chip is almost the same, with two | ||
38 | additional internal voltages monitored (VSB and battery). It also features | ||
39 | 6 VID inputs. The VID inputs are not yet supported by this driver. | ||
40 | |||
33 | The driver assumes that no more than one chip is present, which seems | 41 | The driver assumes that no more than one chip is present, which seems |
34 | reasonable. | 42 | reasonable. |
35 | 43 | ||
@@ -41,7 +49,8 @@ Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported | |||
41 | range is thus from 0 to 2.040 V. Voltage values outside of this range | 49 | range is thus from 0 to 2.040 V. Voltage values outside of this range |
42 | need external resistors. An exception is in0, which is used to monitor | 50 | need external resistors. An exception is in0, which is used to monitor |
43 | the chip's own power source (+3.3V), and is divided internally by a | 51 | the chip's own power source (+3.3V), and is divided internally by a |
44 | factor 2. | 52 | factor 2. For the F71872F/FG, in9 (VSB) and in10 (battery) are also |
53 | divided internally by a factor 2. | ||
45 | 54 | ||
46 | The two LSB of the voltage limit registers are not used (always 0), so | 55 | The two LSB of the voltage limit registers are not used (always 0), so |
47 | you can only set the limits in steps of 32 mV (before scaling). | 56 | you can only set the limits in steps of 32 mV (before scaling). |
@@ -60,9 +69,12 @@ in5 VIN5 +12V 200K 20K 11.00 1.05 V | |||
60 | in6 VIN6 VCC1.5V 10K - 1.00 1.50 V | 69 | in6 VIN6 VCC1.5V 10K - 1.00 1.50 V |
61 | in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) | 70 | in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) |
62 | in8 VIN8 VSB5V 200K 47K 1.00 0.95 V | 71 | in8 VIN8 VSB5V 200K 47K 1.00 0.95 V |
72 | in10 VSB VSB3.3V int. int. 2.00 1.65 V (3) | ||
73 | in9 VBAT VBATTERY int. int. 2.00 1.50 V (3) | ||
63 | 74 | ||
64 | (1) Depends on your hardware setup. | 75 | (1) Depends on your hardware setup. |
65 | (2) Obviously not correct, swapping R1 and R2 would make more sense. | 76 | (2) Obviously not correct, swapping R1 and R2 would make more sense. |
77 | (3) F71872F/FG only. | ||
66 | 78 | ||
67 | These values can be used as hints at best, as motherboard manufacturers | 79 | These values can be used as hints at best, as motherboard manufacturers |
68 | are free to use a completely different setup. As a matter of fact, the | 80 | are free to use a completely different setup. As a matter of fact, the |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e379ac41c09c..5a0763197e21 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -142,11 +142,12 @@ config SENSORS_DS1621 | |||
142 | will be called ds1621. | 142 | will be called ds1621. |
143 | 143 | ||
144 | config SENSORS_F71805F | 144 | config SENSORS_F71805F |
145 | tristate "Fintek F71805F/FG" | 145 | tristate "Fintek F71805F/FG and F71872F/FG" |
146 | depends on HWMON && EXPERIMENTAL | 146 | depends on HWMON && EXPERIMENTAL |
147 | help | 147 | help |
148 | If you say yes here you get support for hardware monitoring | 148 | If you say yes here you get support for hardware monitoring |
149 | features of the Fintek F71805F/FG chips. | 149 | features of the Fintek F71805F/FG and F71872F/FG Super-I/O |
150 | chips. | ||
150 | 151 | ||
151 | This driver can also be built as a module. If so, the module | 152 | This driver can also be built as a module. If so, the module |
152 | will be called f71805f. | 153 | will be called f71805f. |
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 975c1cc2acf1..ba5e7b70f8cc 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c | |||
@@ -1,12 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated | 2 | * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O |
3 | * hardware monitoring features | 3 | * chips integrated hardware monitoring features |
4 | * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> | 4 | * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | * |
6 | * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates | 6 | * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates |
7 | * complete hardware monitoring features: voltage, fan and temperature | 7 | * complete hardware monitoring features: voltage, fan and temperature |
8 | * sensors, and manual and automatic fan speed control. | 8 | * sensors, and manual and automatic fan speed control. |
9 | * | 9 | * |
10 | * The F71872F/FG is almost the same, with two more voltages monitored, | ||
11 | * and 6 VID inputs. | ||
12 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 15 | * the Free Software Foundation; either version 2 of the License, or |
@@ -37,6 +40,7 @@ | |||
37 | static struct platform_device *pdev; | 40 | static struct platform_device *pdev; |
38 | 41 | ||
39 | #define DRVNAME "f71805f" | 42 | #define DRVNAME "f71805f" |
43 | enum kinds { f71805f, f71872f }; | ||
40 | 44 | ||
41 | /* | 45 | /* |
42 | * Super-I/O constants and functions | 46 | * Super-I/O constants and functions |
@@ -48,11 +52,13 @@ static struct platform_device *pdev; | |||
48 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | 52 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ |
49 | #define SIO_REG_DEVREV 0x22 /* Device revision */ | 53 | #define SIO_REG_DEVREV 0x22 /* Device revision */ |
50 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ | 54 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ |
55 | #define SIO_REG_FNSEL1 0x29 /* Multi Function Select 1 (F71872F) */ | ||
51 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ | 56 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ |
52 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | 57 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ |
53 | 58 | ||
54 | #define SIO_FINTEK_ID 0x1934 | 59 | #define SIO_FINTEK_ID 0x1934 |
55 | #define SIO_F71805F_ID 0x0406 | 60 | #define SIO_F71805F_ID 0x0406 |
61 | #define SIO_F71872F_ID 0x0341 | ||
56 | 62 | ||
57 | static inline int | 63 | static inline int |
58 | superio_inb(int base, int reg) | 64 | superio_inb(int base, int reg) |
@@ -104,10 +110,10 @@ superio_exit(int base) | |||
104 | * Registers | 110 | * Registers |
105 | */ | 111 | */ |
106 | 112 | ||
107 | /* in nr from 0 to 8 (8-bit values) */ | 113 | /* in nr from 0 to 10 (8-bit values) */ |
108 | #define F71805F_REG_IN(nr) (0x10 + (nr)) | 114 | #define F71805F_REG_IN(nr) (0x10 + (nr)) |
109 | #define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) | 115 | #define F71805F_REG_IN_HIGH(nr) ((nr) < 10 ? 0x40 + 2 * (nr) : 0x2E) |
110 | #define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) | 116 | #define F71805F_REG_IN_LOW(nr) ((nr) < 10 ? 0x41 + 2 * (nr) : 0x2F) |
111 | /* fan nr from 0 to 2 (12-bit values, two registers) */ | 117 | /* fan nr from 0 to 2 (12-bit values, two registers) */ |
112 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) | 118 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) |
113 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) | 119 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) |
@@ -150,9 +156,10 @@ struct f71805f_data { | |||
150 | unsigned long last_limits; /* In jiffies */ | 156 | unsigned long last_limits; /* In jiffies */ |
151 | 157 | ||
152 | /* Register values */ | 158 | /* Register values */ |
153 | u8 in[9]; | 159 | u8 in[11]; |
154 | u8 in_high[9]; | 160 | u8 in_high[11]; |
155 | u8 in_low[9]; | 161 | u8 in_low[11]; |
162 | u16 has_in; | ||
156 | u16 fan[3]; | 163 | u16 fan[3]; |
157 | u16 fan_low[3]; | 164 | u16 fan_low[3]; |
158 | u16 fan_target[3]; | 165 | u16 fan_target[3]; |
@@ -166,6 +173,11 @@ struct f71805f_data { | |||
166 | unsigned long alarms; | 173 | unsigned long alarms; |
167 | }; | 174 | }; |
168 | 175 | ||
176 | struct f71805f_sio_data { | ||
177 | enum kinds kind; | ||
178 | u8 fnsel1; | ||
179 | }; | ||
180 | |||
169 | static inline long in_from_reg(u8 reg) | 181 | static inline long in_from_reg(u8 reg) |
170 | { | 182 | { |
171 | return (reg * 8); | 183 | return (reg * 8); |
@@ -316,7 +328,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
316 | /* Limit registers cache is refreshed after 60 seconds */ | 328 | /* Limit registers cache is refreshed after 60 seconds */ |
317 | if (time_after(jiffies, data->last_updated + 60 * HZ) | 329 | if (time_after(jiffies, data->last_updated + 60 * HZ) |
318 | || !data->valid) { | 330 | || !data->valid) { |
319 | for (nr = 0; nr < 9; nr++) { | 331 | for (nr = 0; nr < 11; nr++) { |
332 | if (!(data->has_in & (1 << nr))) | ||
333 | continue; | ||
320 | data->in_high[nr] = f71805f_read8(data, | 334 | data->in_high[nr] = f71805f_read8(data, |
321 | F71805F_REG_IN_HIGH(nr)); | 335 | F71805F_REG_IN_HIGH(nr)); |
322 | data->in_low[nr] = f71805f_read8(data, | 336 | data->in_low[nr] = f71805f_read8(data, |
@@ -346,7 +360,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev) | |||
346 | /* Measurement registers cache is refreshed after 1 second */ | 360 | /* Measurement registers cache is refreshed after 1 second */ |
347 | if (time_after(jiffies, data->last_updated + HZ) | 361 | if (time_after(jiffies, data->last_updated + HZ) |
348 | || !data->valid) { | 362 | || !data->valid) { |
349 | for (nr = 0; nr < 9; nr++) { | 363 | for (nr = 0; nr < 11; nr++) { |
364 | if (!(data->has_in & (1 << nr))) | ||
365 | continue; | ||
350 | data->in[nr] = f71805f_read8(data, | 366 | data->in[nr] = f71805f_read8(data, |
351 | F71805F_REG_IN(nr)); | 367 | F71805F_REG_IN(nr)); |
352 | } | 368 | } |
@@ -385,35 +401,43 @@ static ssize_t show_in0(struct device *dev, struct device_attribute *devattr, | |||
385 | char *buf) | 401 | char *buf) |
386 | { | 402 | { |
387 | struct f71805f_data *data = f71805f_update_device(dev); | 403 | struct f71805f_data *data = f71805f_update_device(dev); |
404 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
405 | int nr = attr->index; | ||
388 | 406 | ||
389 | return sprintf(buf, "%ld\n", in0_from_reg(data->in[0])); | 407 | return sprintf(buf, "%ld\n", in0_from_reg(data->in[nr])); |
390 | } | 408 | } |
391 | 409 | ||
392 | static ssize_t show_in0_max(struct device *dev, struct device_attribute | 410 | static ssize_t show_in0_max(struct device *dev, struct device_attribute |
393 | *devattr, char *buf) | 411 | *devattr, char *buf) |
394 | { | 412 | { |
395 | struct f71805f_data *data = f71805f_update_device(dev); | 413 | struct f71805f_data *data = f71805f_update_device(dev); |
414 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
415 | int nr = attr->index; | ||
396 | 416 | ||
397 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[0])); | 417 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[nr])); |
398 | } | 418 | } |
399 | 419 | ||
400 | static ssize_t show_in0_min(struct device *dev, struct device_attribute | 420 | static ssize_t show_in0_min(struct device *dev, struct device_attribute |
401 | *devattr, char *buf) | 421 | *devattr, char *buf) |
402 | { | 422 | { |
403 | struct f71805f_data *data = f71805f_update_device(dev); | 423 | struct f71805f_data *data = f71805f_update_device(dev); |
424 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
425 | int nr = attr->index; | ||
404 | 426 | ||
405 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[0])); | 427 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[nr])); |
406 | } | 428 | } |
407 | 429 | ||
408 | static ssize_t set_in0_max(struct device *dev, struct device_attribute | 430 | static ssize_t set_in0_max(struct device *dev, struct device_attribute |
409 | *devattr, const char *buf, size_t count) | 431 | *devattr, const char *buf, size_t count) |
410 | { | 432 | { |
411 | struct f71805f_data *data = dev_get_drvdata(dev); | 433 | struct f71805f_data *data = dev_get_drvdata(dev); |
434 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
435 | int nr = attr->index; | ||
412 | long val = simple_strtol(buf, NULL, 10); | 436 | long val = simple_strtol(buf, NULL, 10); |
413 | 437 | ||
414 | mutex_lock(&data->update_lock); | 438 | mutex_lock(&data->update_lock); |
415 | data->in_high[0] = in0_to_reg(val); | 439 | data->in_high[nr] = in0_to_reg(val); |
416 | f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]); | 440 | f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]); |
417 | mutex_unlock(&data->update_lock); | 441 | mutex_unlock(&data->update_lock); |
418 | 442 | ||
419 | return count; | 443 | return count; |
@@ -423,11 +447,13 @@ static ssize_t set_in0_min(struct device *dev, struct device_attribute | |||
423 | *devattr, const char *buf, size_t count) | 447 | *devattr, const char *buf, size_t count) |
424 | { | 448 | { |
425 | struct f71805f_data *data = dev_get_drvdata(dev); | 449 | struct f71805f_data *data = dev_get_drvdata(dev); |
450 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
451 | int nr = attr->index; | ||
426 | long val = simple_strtol(buf, NULL, 10); | 452 | long val = simple_strtol(buf, NULL, 10); |
427 | 453 | ||
428 | mutex_lock(&data->update_lock); | 454 | mutex_lock(&data->update_lock); |
429 | data->in_low[0] = in0_to_reg(val); | 455 | data->in_low[nr] = in0_to_reg(val); |
430 | f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]); | 456 | f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]); |
431 | mutex_unlock(&data->update_lock); | 457 | mutex_unlock(&data->update_lock); |
432 | 458 | ||
433 | return count; | 459 | return count; |
@@ -770,7 +796,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute | |||
770 | { | 796 | { |
771 | struct f71805f_data *data = f71805f_update_device(dev); | 797 | struct f71805f_data *data = f71805f_update_device(dev); |
772 | 798 | ||
773 | return sprintf(buf, "%lu\n", data->alarms & 0x1ff); | 799 | return sprintf(buf, "%lu\n", data->alarms & 0x7ff); |
774 | } | 800 | } |
775 | 801 | ||
776 | static ssize_t show_alarms_fan(struct device *dev, struct device_attribute | 802 | static ssize_t show_alarms_fan(struct device *dev, struct device_attribute |
@@ -807,9 +833,11 @@ static ssize_t show_name(struct device *dev, struct device_attribute | |||
807 | return sprintf(buf, "%s\n", data->name); | 833 | return sprintf(buf, "%s\n", data->name); |
808 | } | 834 | } |
809 | 835 | ||
810 | static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); | 836 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL, 0); |
811 | static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); | 837 | static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, |
812 | static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); | 838 | show_in0_max, set_in0_max, 0); |
839 | static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, | ||
840 | show_in0_min, set_in0_min, 0); | ||
813 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); | 841 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1); |
814 | static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, | 842 | static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, |
815 | show_in_max, set_in_max, 1); | 843 | show_in_max, set_in_max, 1); |
@@ -850,6 +878,16 @@ static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR, | |||
850 | show_in_max, set_in_max, 8); | 878 | show_in_max, set_in_max, 8); |
851 | static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, | 879 | static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR, |
852 | show_in_min, set_in_min, 8); | 880 | show_in_min, set_in_min, 8); |
881 | static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in0, NULL, 9); | ||
882 | static SENSOR_DEVICE_ATTR(in9_max, S_IRUGO | S_IWUSR, | ||
883 | show_in0_max, set_in0_max, 9); | ||
884 | static SENSOR_DEVICE_ATTR(in9_min, S_IRUGO | S_IWUSR, | ||
885 | show_in0_min, set_in0_min, 9); | ||
886 | static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in0, NULL, 10); | ||
887 | static SENSOR_DEVICE_ATTR(in10_max, S_IRUGO | S_IWUSR, | ||
888 | show_in0_max, set_in0_max, 10); | ||
889 | static SENSOR_DEVICE_ATTR(in10_min, S_IRUGO | S_IWUSR, | ||
890 | show_in0_min, set_in0_min, 10); | ||
853 | 891 | ||
854 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | 892 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); |
855 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, | 893 | static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, |
@@ -916,6 +954,8 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); | |||
916 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); | 954 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); |
917 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); | 955 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); |
918 | static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); | 956 | static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); |
957 | static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9); | ||
958 | static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10); | ||
919 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); | 959 | static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11); |
920 | static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); | 960 | static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12); |
921 | static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); | 961 | static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); |
@@ -929,9 +969,9 @@ static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); | |||
929 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 969 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
930 | 970 | ||
931 | static struct attribute *f71805f_attributes[] = { | 971 | static struct attribute *f71805f_attributes[] = { |
932 | &dev_attr_in0_input.attr, | 972 | &sensor_dev_attr_in0_input.dev_attr.attr, |
933 | &dev_attr_in0_max.attr, | 973 | &sensor_dev_attr_in0_max.dev_attr.attr, |
934 | &dev_attr_in0_min.attr, | 974 | &sensor_dev_attr_in0_min.dev_attr.attr, |
935 | &sensor_dev_attr_in1_input.dev_attr.attr, | 975 | &sensor_dev_attr_in1_input.dev_attr.attr, |
936 | &sensor_dev_attr_in1_max.dev_attr.attr, | 976 | &sensor_dev_attr_in1_max.dev_attr.attr, |
937 | &sensor_dev_attr_in1_min.dev_attr.attr, | 977 | &sensor_dev_attr_in1_min.dev_attr.attr, |
@@ -941,9 +981,6 @@ static struct attribute *f71805f_attributes[] = { | |||
941 | &sensor_dev_attr_in3_input.dev_attr.attr, | 981 | &sensor_dev_attr_in3_input.dev_attr.attr, |
942 | &sensor_dev_attr_in3_max.dev_attr.attr, | 982 | &sensor_dev_attr_in3_max.dev_attr.attr, |
943 | &sensor_dev_attr_in3_min.dev_attr.attr, | 983 | &sensor_dev_attr_in3_min.dev_attr.attr, |
944 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
945 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
946 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
947 | &sensor_dev_attr_in5_input.dev_attr.attr, | 984 | &sensor_dev_attr_in5_input.dev_attr.attr, |
948 | &sensor_dev_attr_in5_max.dev_attr.attr, | 985 | &sensor_dev_attr_in5_max.dev_attr.attr, |
949 | &sensor_dev_attr_in5_min.dev_attr.attr, | 986 | &sensor_dev_attr_in5_min.dev_attr.attr, |
@@ -953,9 +990,6 @@ static struct attribute *f71805f_attributes[] = { | |||
953 | &sensor_dev_attr_in7_input.dev_attr.attr, | 990 | &sensor_dev_attr_in7_input.dev_attr.attr, |
954 | &sensor_dev_attr_in7_max.dev_attr.attr, | 991 | &sensor_dev_attr_in7_max.dev_attr.attr, |
955 | &sensor_dev_attr_in7_min.dev_attr.attr, | 992 | &sensor_dev_attr_in7_min.dev_attr.attr, |
956 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
957 | &sensor_dev_attr_in8_max.dev_attr.attr, | ||
958 | &sensor_dev_attr_in8_min.dev_attr.attr, | ||
959 | 993 | ||
960 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 994 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
961 | &sensor_dev_attr_temp1_max.dev_attr.attr, | 995 | &sensor_dev_attr_temp1_max.dev_attr.attr, |
@@ -974,11 +1008,9 @@ static struct attribute *f71805f_attributes[] = { | |||
974 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | 1008 | &sensor_dev_attr_in1_alarm.dev_attr.attr, |
975 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | 1009 | &sensor_dev_attr_in2_alarm.dev_attr.attr, |
976 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | 1010 | &sensor_dev_attr_in3_alarm.dev_attr.attr, |
977 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | ||
978 | &sensor_dev_attr_in5_alarm.dev_attr.attr, | 1011 | &sensor_dev_attr_in5_alarm.dev_attr.attr, |
979 | &sensor_dev_attr_in6_alarm.dev_attr.attr, | 1012 | &sensor_dev_attr_in6_alarm.dev_attr.attr, |
980 | &sensor_dev_attr_in7_alarm.dev_attr.attr, | 1013 | &sensor_dev_attr_in7_alarm.dev_attr.attr, |
981 | &sensor_dev_attr_in8_alarm.dev_attr.attr, | ||
982 | &dev_attr_alarms_in.attr, | 1014 | &dev_attr_alarms_in.attr, |
983 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, | 1015 | &sensor_dev_attr_temp1_alarm.dev_attr.attr, |
984 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, | 1016 | &sensor_dev_attr_temp2_alarm.dev_attr.attr, |
@@ -994,6 +1026,41 @@ static const struct attribute_group f71805f_group = { | |||
994 | .attrs = f71805f_attributes, | 1026 | .attrs = f71805f_attributes, |
995 | }; | 1027 | }; |
996 | 1028 | ||
1029 | static struct attribute *f71805f_attributes_optin[4][5] = { | ||
1030 | { | ||
1031 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
1032 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
1033 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
1034 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | ||
1035 | NULL | ||
1036 | }, { | ||
1037 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
1038 | &sensor_dev_attr_in8_max.dev_attr.attr, | ||
1039 | &sensor_dev_attr_in8_min.dev_attr.attr, | ||
1040 | &sensor_dev_attr_in8_alarm.dev_attr.attr, | ||
1041 | NULL | ||
1042 | }, { | ||
1043 | &sensor_dev_attr_in9_input.dev_attr.attr, | ||
1044 | &sensor_dev_attr_in9_max.dev_attr.attr, | ||
1045 | &sensor_dev_attr_in9_min.dev_attr.attr, | ||
1046 | &sensor_dev_attr_in9_alarm.dev_attr.attr, | ||
1047 | NULL | ||
1048 | }, { | ||
1049 | &sensor_dev_attr_in10_input.dev_attr.attr, | ||
1050 | &sensor_dev_attr_in10_max.dev_attr.attr, | ||
1051 | &sensor_dev_attr_in10_min.dev_attr.attr, | ||
1052 | &sensor_dev_attr_in10_alarm.dev_attr.attr, | ||
1053 | NULL | ||
1054 | } | ||
1055 | }; | ||
1056 | |||
1057 | static const struct attribute_group f71805f_group_optin[4] = { | ||
1058 | { .attrs = f71805f_attributes_optin[0] }, | ||
1059 | { .attrs = f71805f_attributes_optin[1] }, | ||
1060 | { .attrs = f71805f_attributes_optin[2] }, | ||
1061 | { .attrs = f71805f_attributes_optin[3] }, | ||
1062 | }; | ||
1063 | |||
997 | static struct attribute *f71805f_attributes_fan[3][8] = { | 1064 | static struct attribute *f71805f_attributes_fan[3][8] = { |
998 | { | 1065 | { |
999 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 1066 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
@@ -1084,10 +1151,16 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) | |||
1084 | 1151 | ||
1085 | static int __devinit f71805f_probe(struct platform_device *pdev) | 1152 | static int __devinit f71805f_probe(struct platform_device *pdev) |
1086 | { | 1153 | { |
1154 | struct f71805f_sio_data *sio_data = pdev->dev.platform_data; | ||
1087 | struct f71805f_data *data; | 1155 | struct f71805f_data *data; |
1088 | struct resource *res; | 1156 | struct resource *res; |
1089 | int i, err; | 1157 | int i, err; |
1090 | 1158 | ||
1159 | static const char *names[] = { | ||
1160 | "f71805f", | ||
1161 | "f71872f", | ||
1162 | }; | ||
1163 | |||
1091 | if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { | 1164 | if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { |
1092 | err = -ENOMEM; | 1165 | err = -ENOMEM; |
1093 | printk(KERN_ERR DRVNAME ": Out of memory\n"); | 1166 | printk(KERN_ERR DRVNAME ": Out of memory\n"); |
@@ -1097,17 +1170,51 @@ static int __devinit f71805f_probe(struct platform_device *pdev) | |||
1097 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1170 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
1098 | data->addr = res->start; | 1171 | data->addr = res->start; |
1099 | mutex_init(&data->lock); | 1172 | mutex_init(&data->lock); |
1100 | data->name = "f71805f"; | 1173 | data->name = names[sio_data->kind]; |
1101 | mutex_init(&data->update_lock); | 1174 | mutex_init(&data->update_lock); |
1102 | 1175 | ||
1103 | platform_set_drvdata(pdev, data); | 1176 | platform_set_drvdata(pdev, data); |
1104 | 1177 | ||
1178 | /* Some voltage inputs depend on chip model and configuration */ | ||
1179 | switch (sio_data->kind) { | ||
1180 | case f71805f: | ||
1181 | data->has_in = 0x1ff; | ||
1182 | break; | ||
1183 | case f71872f: | ||
1184 | data->has_in = 0x6ef; | ||
1185 | if (sio_data->fnsel1 & 0x01) | ||
1186 | data->has_in |= (1 << 4); /* in4 */ | ||
1187 | if (sio_data->fnsel1 & 0x02) | ||
1188 | data->has_in |= (1 << 8); /* in8 */ | ||
1189 | break; | ||
1190 | } | ||
1191 | |||
1105 | /* Initialize the F71805F chip */ | 1192 | /* Initialize the F71805F chip */ |
1106 | f71805f_init_device(data); | 1193 | f71805f_init_device(data); |
1107 | 1194 | ||
1108 | /* Register sysfs interface files */ | 1195 | /* Register sysfs interface files */ |
1109 | if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) | 1196 | if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group))) |
1110 | goto exit_free; | 1197 | goto exit_free; |
1198 | if (data->has_in & (1 << 4)) { /* in4 */ | ||
1199 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1200 | &f71805f_group_optin[0]))) | ||
1201 | goto exit_remove_files; | ||
1202 | } | ||
1203 | if (data->has_in & (1 << 8)) { /* in8 */ | ||
1204 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1205 | &f71805f_group_optin[1]))) | ||
1206 | goto exit_remove_files; | ||
1207 | } | ||
1208 | if (data->has_in & (1 << 9)) { /* in9 (F71872F/FG only) */ | ||
1209 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1210 | &f71805f_group_optin[2]))) | ||
1211 | goto exit_remove_files; | ||
1212 | } | ||
1213 | if (data->has_in & (1 << 10)) { /* in9 (F71872F/FG only) */ | ||
1214 | if ((err = sysfs_create_group(&pdev->dev.kobj, | ||
1215 | &f71805f_group_optin[3]))) | ||
1216 | goto exit_remove_files; | ||
1217 | } | ||
1111 | for (i = 0; i < 3; i++) { | 1218 | for (i = 0; i < 3; i++) { |
1112 | if (data->fan_ctrl[i] & FAN_CTRL_SKIP) | 1219 | if (data->fan_ctrl[i] & FAN_CTRL_SKIP) |
1113 | continue; | 1220 | continue; |
@@ -1143,6 +1250,8 @@ static int __devinit f71805f_probe(struct platform_device *pdev) | |||
1143 | 1250 | ||
1144 | exit_remove_files: | 1251 | exit_remove_files: |
1145 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); | 1252 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); |
1253 | for (i = 0; i < 4; i++) | ||
1254 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); | ||
1146 | for (i = 0; i < 3; i++) | 1255 | for (i = 0; i < 3; i++) |
1147 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); | 1256 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); |
1148 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); | 1257 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); |
@@ -1161,6 +1270,8 @@ static int __devexit f71805f_remove(struct platform_device *pdev) | |||
1161 | platform_set_drvdata(pdev, NULL); | 1270 | platform_set_drvdata(pdev, NULL); |
1162 | hwmon_device_unregister(data->class_dev); | 1271 | hwmon_device_unregister(data->class_dev); |
1163 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); | 1272 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); |
1273 | for (i = 0; i < 4; i++) | ||
1274 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); | ||
1164 | for (i = 0; i < 3; i++) | 1275 | for (i = 0; i < 3; i++) |
1165 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); | 1276 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]); |
1166 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); | 1277 | sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); |
@@ -1178,7 +1289,8 @@ static struct platform_driver f71805f_driver = { | |||
1178 | .remove = __devexit_p(f71805f_remove), | 1289 | .remove = __devexit_p(f71805f_remove), |
1179 | }; | 1290 | }; |
1180 | 1291 | ||
1181 | static int __init f71805f_device_add(unsigned short address) | 1292 | static int __init f71805f_device_add(unsigned short address, |
1293 | const struct f71805f_sio_data *sio_data) | ||
1182 | { | 1294 | { |
1183 | struct resource res = { | 1295 | struct resource res = { |
1184 | .start = address, | 1296 | .start = address, |
@@ -1202,26 +1314,45 @@ static int __init f71805f_device_add(unsigned short address) | |||
1202 | goto exit_device_put; | 1314 | goto exit_device_put; |
1203 | } | 1315 | } |
1204 | 1316 | ||
1317 | pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data), | ||
1318 | GFP_KERNEL); | ||
1319 | if (!pdev->dev.platform_data) { | ||
1320 | err = -ENOMEM; | ||
1321 | printk(KERN_ERR DRVNAME ": Platform data allocation failed\n"); | ||
1322 | goto exit_device_put; | ||
1323 | } | ||
1324 | memcpy(pdev->dev.platform_data, sio_data, | ||
1325 | sizeof(struct f71805f_sio_data)); | ||
1326 | |||
1205 | err = platform_device_add(pdev); | 1327 | err = platform_device_add(pdev); |
1206 | if (err) { | 1328 | if (err) { |
1207 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", | 1329 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", |
1208 | err); | 1330 | err); |
1209 | goto exit_device_put; | 1331 | goto exit_kfree_data; |
1210 | } | 1332 | } |
1211 | 1333 | ||
1212 | return 0; | 1334 | return 0; |
1213 | 1335 | ||
1336 | exit_kfree_data: | ||
1337 | kfree(pdev->dev.platform_data); | ||
1338 | pdev->dev.platform_data = NULL; | ||
1214 | exit_device_put: | 1339 | exit_device_put: |
1215 | platform_device_put(pdev); | 1340 | platform_device_put(pdev); |
1216 | exit: | 1341 | exit: |
1217 | return err; | 1342 | return err; |
1218 | } | 1343 | } |
1219 | 1344 | ||
1220 | static int __init f71805f_find(int sioaddr, unsigned short *address) | 1345 | static int __init f71805f_find(int sioaddr, unsigned short *address, |
1346 | struct f71805f_sio_data *sio_data) | ||
1221 | { | 1347 | { |
1222 | int err = -ENODEV; | 1348 | int err = -ENODEV; |
1223 | u16 devid; | 1349 | u16 devid; |
1224 | 1350 | ||
1351 | static const char *names[] = { | ||
1352 | "F71805F/FG", | ||
1353 | "F71872F/FG", | ||
1354 | }; | ||
1355 | |||
1225 | superio_enter(sioaddr); | 1356 | superio_enter(sioaddr); |
1226 | 1357 | ||
1227 | devid = superio_inw(sioaddr, SIO_REG_MANID); | 1358 | devid = superio_inw(sioaddr, SIO_REG_MANID); |
@@ -1229,7 +1360,15 @@ static int __init f71805f_find(int sioaddr, unsigned short *address) | |||
1229 | goto exit; | 1360 | goto exit; |
1230 | 1361 | ||
1231 | devid = superio_inw(sioaddr, SIO_REG_DEVID); | 1362 | devid = superio_inw(sioaddr, SIO_REG_DEVID); |
1232 | if (devid != SIO_F71805F_ID) { | 1363 | switch (devid) { |
1364 | case SIO_F71805F_ID: | ||
1365 | sio_data->kind = f71805f; | ||
1366 | break; | ||
1367 | case SIO_F71872F_ID: | ||
1368 | sio_data->kind = f71872f; | ||
1369 | sio_data->fnsel1 = superio_inb(sioaddr, SIO_REG_FNSEL1); | ||
1370 | break; | ||
1371 | default: | ||
1233 | printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " | 1372 | printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " |
1234 | "skipping\n"); | 1373 | "skipping\n"); |
1235 | goto exit; | 1374 | goto exit; |
@@ -1250,8 +1389,9 @@ static int __init f71805f_find(int sioaddr, unsigned short *address) | |||
1250 | } | 1389 | } |
1251 | 1390 | ||
1252 | err = 0; | 1391 | err = 0; |
1253 | printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", | 1392 | printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %u\n", |
1254 | *address, superio_inb(sioaddr, SIO_REG_DEVREV)); | 1393 | names[sio_data->kind], *address, |
1394 | superio_inb(sioaddr, SIO_REG_DEVREV)); | ||
1255 | 1395 | ||
1256 | exit: | 1396 | exit: |
1257 | superio_exit(sioaddr); | 1397 | superio_exit(sioaddr); |
@@ -1262,9 +1402,10 @@ static int __init f71805f_init(void) | |||
1262 | { | 1402 | { |
1263 | int err; | 1403 | int err; |
1264 | unsigned short address; | 1404 | unsigned short address; |
1405 | struct f71805f_sio_data sio_data; | ||
1265 | 1406 | ||
1266 | if (f71805f_find(0x2e, &address) | 1407 | if (f71805f_find(0x2e, &address, &sio_data) |
1267 | && f71805f_find(0x4e, &address)) | 1408 | && f71805f_find(0x4e, &address, &sio_data)) |
1268 | return -ENODEV; | 1409 | return -ENODEV; |
1269 | 1410 | ||
1270 | err = platform_driver_register(&f71805f_driver); | 1411 | err = platform_driver_register(&f71805f_driver); |
@@ -1272,7 +1413,7 @@ static int __init f71805f_init(void) | |||
1272 | goto exit; | 1413 | goto exit; |
1273 | 1414 | ||
1274 | /* Sets global pdev as a side effect */ | 1415 | /* Sets global pdev as a side effect */ |
1275 | err = f71805f_device_add(address); | 1416 | err = f71805f_device_add(address, &sio_data); |
1276 | if (err) | 1417 | if (err) |
1277 | goto exit_driver; | 1418 | goto exit_driver; |
1278 | 1419 | ||
@@ -1286,13 +1427,16 @@ exit: | |||
1286 | 1427 | ||
1287 | static void __exit f71805f_exit(void) | 1428 | static void __exit f71805f_exit(void) |
1288 | { | 1429 | { |
1430 | kfree(pdev->dev.platform_data); | ||
1431 | pdev->dev.platform_data = NULL; | ||
1289 | platform_device_unregister(pdev); | 1432 | platform_device_unregister(pdev); |
1433 | |||
1290 | platform_driver_unregister(&f71805f_driver); | 1434 | platform_driver_unregister(&f71805f_driver); |
1291 | } | 1435 | } |
1292 | 1436 | ||
1293 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); | 1437 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); |
1294 | MODULE_LICENSE("GPL"); | 1438 | MODULE_LICENSE("GPL"); |
1295 | MODULE_DESCRIPTION("F71805F hardware monitoring driver"); | 1439 | MODULE_DESCRIPTION("F71805F/F71872F hardware monitoring driver"); |
1296 | 1440 | ||
1297 | module_init(f71805f_init); | 1441 | module_init(f71805f_init); |
1298 | module_exit(f71805f_exit); | 1442 | module_exit(f71805f_exit); |