diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-30 20:54:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-30 20:54:32 -0400 |
commit | 3c6fae67d026d57f64eb3da9c0d0e76983e39ae3 (patch) | |
tree | a11f2ff6d99b382fff02a643f6b6b204efb9c40e | |
parent | c4e1aa67ed9e4e542a064bc271ddbf152b677e91 (diff) | |
parent | de15f093e666ccd542f6f7a0e3e917166a07ab44 (diff) |
Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6:
hwmon: (fschmd) Add support for the FSC Hades IC
hwmon: (fschmd) Add support for the FSC Syleus IC
i2c-i801: Instantiate FSC hardware montioring chips
dmi: Let dmi_walk() users pass private data
hwmon: Define a standard interface for chassis intrusion detection
Move the pcf8591 driver to hwmon
hwmon: (w83627ehf) Only expose in6 or temp3 on the W83667HG
hwmon: (w83627ehf) Add support for W83667HG
hwmon: (w83627ehf) Invert fan pin variables logic
hwmon: (hdaps) Fix Thinkpad X41 axis inversion
hwmon: (hdaps) Allow inversion of separate axis
hwmon: (ds1621) Clean up documentation
hwmon: (ds1621) Avoid unneeded register access
hwmon: (ds1621) Clean up register access
hwmon: (ds1621) Reorder code statements
-rw-r--r-- | Documentation/hwmon/ds1621 | 51 | ||||
-rw-r--r-- | Documentation/hwmon/pcf8591 (renamed from Documentation/i2c/chips/pcf8591) | 0 | ||||
-rw-r--r-- | Documentation/hwmon/sysfs-interface | 22 | ||||
-rw-r--r-- | Documentation/hwmon/w83627ehf | 29 | ||||
-rw-r--r-- | drivers/firmware/dmi_scan.c | 18 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 27 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/ds1621.c | 172 | ||||
-rw-r--r-- | drivers/hwmon/fschmd.c | 229 | ||||
-rw-r--r-- | drivers/hwmon/hdaps.c | 66 | ||||
-rw-r--r-- | drivers/hwmon/pcf8591.c (renamed from drivers/i2c/chips/pcf8591.c) | 24 | ||||
-rw-r--r-- | drivers/hwmon/w83627ehf.c | 170 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 77 | ||||
-rw-r--r-- | drivers/i2c/chips/Kconfig | 13 | ||||
-rw-r--r-- | drivers/i2c/chips/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/hpwdt.c | 4 | ||||
-rw-r--r-- | include/linux/dmi.h | 7 |
18 files changed, 588 insertions, 327 deletions
diff --git a/Documentation/hwmon/ds1621 b/Documentation/hwmon/ds1621 index 1fee6f1e6bc5..5e97f333c4df 100644 --- a/Documentation/hwmon/ds1621 +++ b/Documentation/hwmon/ds1621 | |||
@@ -49,12 +49,9 @@ of up to +/- 0.5 degrees even when compared against precise temperature | |||
49 | readings. Be sure to have a high vs. low temperature limit gap of al least | 49 | readings. Be sure to have a high vs. low temperature limit gap of al least |
50 | 1.0 degree Celsius to avoid Tout "bouncing", though! | 50 | 1.0 degree Celsius to avoid Tout "bouncing", though! |
51 | 51 | ||
52 | As for alarms, you can read the alarm status of the DS1621 via the 'alarms' | 52 | The alarm bits are set when the high or low limits are met or exceeded and |
53 | /sys file interface. The result consists mainly of bit 6 and 5 of the | 53 | are reset by the module as soon as the respective temperature ranges are |
54 | configuration register of the chip; bit 6 (0x40 or 64) is the high alarm | 54 | left. |
55 | bit and bit 5 (0x20 or 32) the low one. These bits are set when the high or | ||
56 | low limits are met or exceeded and are reset by the module as soon as the | ||
57 | respective temperature ranges are left. | ||
58 | 55 | ||
59 | The alarm registers are in no way suitable to find out about the actual | 56 | The alarm registers are in no way suitable to find out about the actual |
60 | status of Tout. They will only tell you about its history, whether or not | 57 | status of Tout. They will only tell you about its history, whether or not |
@@ -64,45 +61,3 @@ with neither of the alarms set. | |||
64 | 61 | ||
65 | Temperature conversion of the DS1621 takes up to 1000ms; internal access to | 62 | Temperature conversion of the DS1621 takes up to 1000ms; internal access to |
66 | non-volatile registers may last for 10ms or below. | 63 | non-volatile registers may last for 10ms or below. |
67 | |||
68 | High Accuracy Temperature Reading | ||
69 | --------------------------------- | ||
70 | |||
71 | As said before, the temperature issued via the 9-bit i2c-bus data is | ||
72 | somewhat arbitrary. Internally, the temperature conversion is of a | ||
73 | different kind that is explained (not so...) well in the DS1621 data sheet. | ||
74 | To cut the long story short: Inside the DS1621 there are two oscillators, | ||
75 | both of them biassed by a temperature coefficient. | ||
76 | |||
77 | Higher resolution of the temperature reading can be achieved using the | ||
78 | internal projection, which means taking account of REG_COUNT and REG_SLOPE | ||
79 | (the driver manages them): | ||
80 | |||
81 | Taken from Dallas Semiconductors App Note 068: 'Increasing Temperature | ||
82 | Resolution on the DS1620' and App Note 105: 'High Resolution Temperature | ||
83 | Measurement with Dallas Direct-to-Digital Temperature Sensors' | ||
84 | |||
85 | - Read the 9-bit temperature and strip the LSB (Truncate the .5 degs) | ||
86 | - The resulting value is TEMP_READ. | ||
87 | - Then, read REG_COUNT. | ||
88 | - And then, REG_SLOPE. | ||
89 | |||
90 | TEMP = TEMP_READ - 0.25 + ((REG_SLOPE - REG_COUNT) / REG_SLOPE) | ||
91 | |||
92 | Note that this is what the DONE bit in the DS1621 configuration register is | ||
93 | good for: Internally, one temperature conversion takes up to 1000ms. Before | ||
94 | that conversion is complete you will not be able to read valid things out | ||
95 | of REG_COUNT and REG_SLOPE. The DONE bit, as you may have guessed by now, | ||
96 | tells you whether the conversion is complete ("done", in plain English) and | ||
97 | thus, whether the values you read are good or not. | ||
98 | |||
99 | The DS1621 has two modes of operation: "Continuous" conversion, which can | ||
100 | be understood as the default stand-alone mode where the chip gets the | ||
101 | temperature and controls external devices via its Tout pin or tells other | ||
102 | i2c's about it if they care. The other mode is called "1SHOT", that means | ||
103 | that it only figures out about the temperature when it is explicitly told | ||
104 | to do so; this can be seen as power saving mode. | ||
105 | |||
106 | Now if you want to read REG_COUNT and REG_SLOPE, you have to either stop | ||
107 | the continuous conversions until the contents of these registers are valid, | ||
108 | or, in 1SHOT mode, you have to have one conversion made. | ||
diff --git a/Documentation/i2c/chips/pcf8591 b/Documentation/hwmon/pcf8591 index 5628fcf4207f..5628fcf4207f 100644 --- a/Documentation/i2c/chips/pcf8591 +++ b/Documentation/hwmon/pcf8591 | |||
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 6dbfd5efd991..2f10ce6a879f 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface | |||
@@ -365,6 +365,7 @@ energy[1-*]_input Cumulative energy use | |||
365 | Unit: microJoule | 365 | Unit: microJoule |
366 | RO | 366 | RO |
367 | 367 | ||
368 | |||
368 | ********** | 369 | ********** |
369 | * Alarms * | 370 | * Alarms * |
370 | ********** | 371 | ********** |
@@ -453,6 +454,27 @@ beep_mask Bitmask for beep. | |||
453 | RW | 454 | RW |
454 | 455 | ||
455 | 456 | ||
457 | *********************** | ||
458 | * Intrusion detection * | ||
459 | *********************** | ||
460 | |||
461 | intrusion[0-*]_alarm | ||
462 | Chassis intrusion detection | ||
463 | 0: OK | ||
464 | 1: intrusion detected | ||
465 | RW | ||
466 | Contrary to regular alarm flags which clear themselves | ||
467 | automatically when read, this one sticks until cleared by | ||
468 | the user. This is done by writing 0 to the file. Writing | ||
469 | other values is unsupported. | ||
470 | |||
471 | intrusion[0-*]_beep | ||
472 | Chassis intrusion beep | ||
473 | 0: disable | ||
474 | 1: enable | ||
475 | RW | ||
476 | |||
477 | |||
456 | sysfs attribute writes interpretation | 478 | sysfs attribute writes interpretation |
457 | ------------------------------------- | 479 | ------------------------------------- |
458 | 480 | ||
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf index d6e1ae30fa6e..b6eb59384bb3 100644 --- a/Documentation/hwmon/w83627ehf +++ b/Documentation/hwmon/w83627ehf | |||
@@ -2,30 +2,40 @@ Kernel driver w83627ehf | |||
2 | ======================= | 2 | ======================= |
3 | 3 | ||
4 | Supported chips: | 4 | Supported chips: |
5 | * Winbond W83627EHF/EHG/DHG (ISA access ONLY) | 5 | * Winbond W83627EHF/EHG (ISA access ONLY) |
6 | Prefix: 'w83627ehf' | 6 | Prefix: 'w83627ehf' |
7 | Addresses scanned: ISA address retrieved from Super I/O registers | 7 | Addresses scanned: ISA address retrieved from Super I/O registers |
8 | Datasheet: | 8 | Datasheet: |
9 | http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf | 9 | http://www.nuvoton.com.tw/NR/rdonlyres/A6A258F0-F0C9-4F97-81C0-C4D29E7E943E/0/W83627EHF.pdf |
10 | DHG datasheet confidential. | 10 | * Winbond W83627DHG |
11 | Prefix: 'w83627dhg' | ||
12 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
13 | Datasheet: | ||
14 | http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf | ||
15 | * Winbond W83667HG | ||
16 | Prefix: 'w83667hg' | ||
17 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
18 | Datasheet: not available | ||
11 | 19 | ||
12 | Authors: | 20 | Authors: |
13 | Jean Delvare <khali@linux-fr.org> | 21 | Jean Delvare <khali@linux-fr.org> |
14 | Yuan Mu (Winbond) | 22 | Yuan Mu (Winbond) |
15 | Rudolf Marek <r.marek@assembler.cz> | 23 | Rudolf Marek <r.marek@assembler.cz> |
16 | David Hubbard <david.c.hubbard@gmail.com> | 24 | David Hubbard <david.c.hubbard@gmail.com> |
25 | Gong Jun <JGong@nuvoton.com> | ||
17 | 26 | ||
18 | Description | 27 | Description |
19 | ----------- | 28 | ----------- |
20 | 29 | ||
21 | This driver implements support for the Winbond W83627EHF, W83627EHG, and | 30 | This driver implements support for the Winbond W83627EHF, W83627EHG, |
22 | W83627DHG super I/O chips. We will refer to them collectively as Winbond chips. | 31 | W83627DHG and W83667HG super I/O chips. We will refer to them collectively |
32 | as Winbond chips. | ||
23 | 33 | ||
24 | The chips implement three temperature sensors, five fan rotation | 34 | The chips implement three temperature sensors, five fan rotation |
25 | speed sensors, ten analog voltage sensors (only nine for the 627DHG), one | 35 | speed sensors, ten analog voltage sensors (only nine for the 627DHG), one |
26 | VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG), alarms with beep | 36 | VID (6 pins for the 627EHF/EHG, 8 pins for the 627DHG and 667HG), alarms |
27 | warnings (control unimplemented), and some automatic fan regulation | 37 | with beep warnings (control unimplemented), and some automatic fan |
28 | strategies (plus manual fan control mode). | 38 | regulation strategies (plus manual fan control mode). |
29 | 39 | ||
30 | Temperatures are measured in degrees Celsius and measurement resolution is 1 | 40 | Temperatures are measured in degrees Celsius and measurement resolution is 1 |
31 | degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when | 41 | degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when |
@@ -54,7 +64,8 @@ follows: | |||
54 | temp1 -> pwm1 | 64 | temp1 -> pwm1 |
55 | temp2 -> pwm2 | 65 | temp2 -> pwm2 |
56 | temp3 -> pwm3 | 66 | temp3 -> pwm3 |
57 | prog -> pwm4 (the programmable setting is not supported by the driver) | 67 | prog -> pwm4 (not on 667HG; the programmable setting is not supported by |
68 | the driver) | ||
58 | 69 | ||
59 | /sys files | 70 | /sys files |
60 | ---------- | 71 | ---------- |
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 8f0f7c449305..5f1b5400d96a 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
@@ -68,7 +68,8 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s) | |||
68 | * pointing to completely the wrong place for example | 68 | * pointing to completely the wrong place for example |
69 | */ | 69 | */ |
70 | static void dmi_table(u8 *buf, int len, int num, | 70 | static void dmi_table(u8 *buf, int len, int num, |
71 | void (*decode)(const struct dmi_header *)) | 71 | void (*decode)(const struct dmi_header *, void *), |
72 | void *private_data) | ||
72 | { | 73 | { |
73 | u8 *data = buf; | 74 | u8 *data = buf; |
74 | int i = 0; | 75 | int i = 0; |
@@ -89,7 +90,7 @@ static void dmi_table(u8 *buf, int len, int num, | |||
89 | while ((data - buf < len - 1) && (data[0] || data[1])) | 90 | while ((data - buf < len - 1) && (data[0] || data[1])) |
90 | data++; | 91 | data++; |
91 | if (data - buf < len - 1) | 92 | if (data - buf < len - 1) |
92 | decode(dm); | 93 | decode(dm, private_data); |
93 | data += 2; | 94 | data += 2; |
94 | i++; | 95 | i++; |
95 | } | 96 | } |
@@ -99,7 +100,8 @@ static u32 dmi_base; | |||
99 | static u16 dmi_len; | 100 | static u16 dmi_len; |
100 | static u16 dmi_num; | 101 | static u16 dmi_num; |
101 | 102 | ||
102 | static int __init dmi_walk_early(void (*decode)(const struct dmi_header *)) | 103 | static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, |
104 | void *)) | ||
103 | { | 105 | { |
104 | u8 *buf; | 106 | u8 *buf; |
105 | 107 | ||
@@ -107,7 +109,7 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *)) | |||
107 | if (buf == NULL) | 109 | if (buf == NULL) |
108 | return -1; | 110 | return -1; |
109 | 111 | ||
110 | dmi_table(buf, dmi_len, dmi_num, decode); | 112 | dmi_table(buf, dmi_len, dmi_num, decode, NULL); |
111 | 113 | ||
112 | dmi_iounmap(buf, dmi_len); | 114 | dmi_iounmap(buf, dmi_len); |
113 | return 0; | 115 | return 0; |
@@ -295,7 +297,7 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm) | |||
295 | * and machine entries. For 2.5 we should pull the smbus controller info | 297 | * and machine entries. For 2.5 we should pull the smbus controller info |
296 | * out of here. | 298 | * out of here. |
297 | */ | 299 | */ |
298 | static void __init dmi_decode(const struct dmi_header *dm) | 300 | static void __init dmi_decode(const struct dmi_header *dm, void *dummy) |
299 | { | 301 | { |
300 | switch(dm->type) { | 302 | switch(dm->type) { |
301 | case 0: /* BIOS Information */ | 303 | case 0: /* BIOS Information */ |
@@ -598,10 +600,12 @@ int dmi_get_year(int field) | |||
598 | /** | 600 | /** |
599 | * dmi_walk - Walk the DMI table and get called back for every record | 601 | * dmi_walk - Walk the DMI table and get called back for every record |
600 | * @decode: Callback function | 602 | * @decode: Callback function |
603 | * @private_data: Private data to be passed to the callback function | ||
601 | * | 604 | * |
602 | * Returns -1 when the DMI table can't be reached, 0 on success. | 605 | * Returns -1 when the DMI table can't be reached, 0 on success. |
603 | */ | 606 | */ |
604 | int dmi_walk(void (*decode)(const struct dmi_header *)) | 607 | int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
608 | void *private_data) | ||
605 | { | 609 | { |
606 | u8 *buf; | 610 | u8 *buf; |
607 | 611 | ||
@@ -612,7 +616,7 @@ int dmi_walk(void (*decode)(const struct dmi_header *)) | |||
612 | if (buf == NULL) | 616 | if (buf == NULL) |
613 | return -1; | 617 | return -1; |
614 | 618 | ||
615 | dmi_table(buf, dmi_len, dmi_num, decode); | 619 | dmi_table(buf, dmi_len, dmi_num, decode, private_data); |
616 | 620 | ||
617 | iounmap(buf); | 621 | iounmap(buf); |
618 | return 0; | 622 | return 0; |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index b4eea0292c1a..51ff9b3d7ea2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -343,12 +343,13 @@ config SENSORS_FSCPOS | |||
343 | will be called fscpos. | 343 | will be called fscpos. |
344 | 344 | ||
345 | config SENSORS_FSCHMD | 345 | config SENSORS_FSCHMD |
346 | tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" | 346 | tristate "Fujitsu Siemens Computers sensor chips" |
347 | depends on X86 && I2C | 347 | depends on X86 && I2C |
348 | help | 348 | help |
349 | If you say yes here you get support for various Fujitsu Siemens | 349 | If you say yes here you get support for the following Fujitsu |
350 | Computers sensor chips, including support for the integrated | 350 | Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, |
351 | watchdog. | 351 | Heimdall, Heracles, Hades and Syleus including support for the |
352 | integrated watchdog. | ||
352 | 353 | ||
353 | This is a merged driver for FSC sensor chips replacing the fscpos, | 354 | This is a merged driver for FSC sensor chips replacing the fscpos, |
354 | fscscy and fscher drivers and adding support for several other FSC | 355 | fscscy and fscher drivers and adding support for several other FSC |
@@ -635,6 +636,20 @@ config SENSORS_PC87427 | |||
635 | This driver can also be built as a module. If so, the module | 636 | This driver can also be built as a module. If so, the module |
636 | will be called pc87427. | 637 | will be called pc87427. |
637 | 638 | ||
639 | config SENSORS_PCF8591 | ||
640 | tristate "Philips PCF8591 ADC/DAC" | ||
641 | depends on I2C | ||
642 | default n | ||
643 | help | ||
644 | If you say yes here you get support for Philips PCF8591 4-channel | ||
645 | ADC, 1-channel DAC chips. | ||
646 | |||
647 | This driver can also be built as a module. If so, the module | ||
648 | will be called pcf8591. | ||
649 | |||
650 | These devices are hard to detect and rarely found on mainstream | ||
651 | hardware. If unsure, say N. | ||
652 | |||
638 | config SENSORS_SIS5595 | 653 | config SENSORS_SIS5595 |
639 | tristate "Silicon Integrated Systems Corp. SiS5595" | 654 | tristate "Silicon Integrated Systems Corp. SiS5595" |
640 | depends on PCI | 655 | depends on PCI |
@@ -827,7 +842,7 @@ config SENSORS_W83627HF | |||
827 | will be called w83627hf. | 842 | will be called w83627hf. |
828 | 843 | ||
829 | config SENSORS_W83627EHF | 844 | config SENSORS_W83627EHF |
830 | tristate "Winbond W83627EHF/DHG" | 845 | tristate "Winbond W83627EHF/EHG/DHG, W83667HG" |
831 | select HWMON_VID | 846 | select HWMON_VID |
832 | help | 847 | help |
833 | If you say yes here you get support for the hardware | 848 | If you say yes here you get support for the hardware |
@@ -838,6 +853,8 @@ config SENSORS_W83627EHF | |||
838 | chip suited for specific Intel processors that use PECI such as | 853 | chip suited for specific Intel processors that use PECI such as |
839 | the Core 2 Duo. | 854 | the Core 2 Duo. |
840 | 855 | ||
856 | This driver also supports the W83667HG chip. | ||
857 | |||
841 | This driver can also be built as a module. If so, the module | 858 | This driver can also be built as a module. If so, the module |
842 | will be called w83627ehf. | 859 | will be called w83627ehf. |
843 | 860 | ||
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 2e80f37f39eb..e332d6267920 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -70,6 +70,7 @@ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o | |||
70 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | 70 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o |
71 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 71 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
72 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o | 72 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o |
73 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o | ||
73 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o | 74 | obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o |
74 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | 75 | obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o |
75 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 76 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 7415381601c3..53f88f511816 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c | |||
@@ -81,71 +81,84 @@ struct ds1621_data { | |||
81 | u8 conf; /* Register encoding, combined */ | 81 | u8 conf; /* Register encoding, combined */ |
82 | }; | 82 | }; |
83 | 83 | ||
84 | static int ds1621_probe(struct i2c_client *client, | 84 | /* Temperature registers are word-sized. |
85 | const struct i2c_device_id *id); | ||
86 | static int ds1621_detect(struct i2c_client *client, int kind, | ||
87 | struct i2c_board_info *info); | ||
88 | static void ds1621_init_client(struct i2c_client *client); | ||
89 | static int ds1621_remove(struct i2c_client *client); | ||
90 | static struct ds1621_data *ds1621_update_client(struct device *dev); | ||
91 | |||
92 | static const struct i2c_device_id ds1621_id[] = { | ||
93 | { "ds1621", ds1621 }, | ||
94 | { "ds1625", ds1621 }, | ||
95 | { } | ||
96 | }; | ||
97 | MODULE_DEVICE_TABLE(i2c, ds1621_id); | ||
98 | |||
99 | /* This is the driver that will be inserted */ | ||
100 | static struct i2c_driver ds1621_driver = { | ||
101 | .class = I2C_CLASS_HWMON, | ||
102 | .driver = { | ||
103 | .name = "ds1621", | ||
104 | }, | ||
105 | .probe = ds1621_probe, | ||
106 | .remove = ds1621_remove, | ||
107 | .id_table = ds1621_id, | ||
108 | .detect = ds1621_detect, | ||
109 | .address_data = &addr_data, | ||
110 | }; | ||
111 | |||
112 | /* All registers are word-sized, except for the configuration register. | ||
113 | DS1621 uses a high-byte first convention, which is exactly opposite to | 85 | DS1621 uses a high-byte first convention, which is exactly opposite to |
114 | the SMBus standard. */ | 86 | the SMBus standard. */ |
115 | static int ds1621_read_value(struct i2c_client *client, u8 reg) | 87 | static int ds1621_read_temp(struct i2c_client *client, u8 reg) |
116 | { | 88 | { |
117 | if (reg == DS1621_REG_CONF) | 89 | int ret; |
118 | return i2c_smbus_read_byte_data(client, reg); | 90 | |
119 | else | 91 | ret = i2c_smbus_read_word_data(client, reg); |
120 | return swab16(i2c_smbus_read_word_data(client, reg)); | 92 | if (ret < 0) |
93 | return ret; | ||
94 | return swab16(ret); | ||
121 | } | 95 | } |
122 | 96 | ||
123 | static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value) | 97 | static int ds1621_write_temp(struct i2c_client *client, u8 reg, u16 value) |
124 | { | 98 | { |
125 | if (reg == DS1621_REG_CONF) | 99 | return i2c_smbus_write_word_data(client, reg, swab16(value)); |
126 | return i2c_smbus_write_byte_data(client, reg, value); | ||
127 | else | ||
128 | return i2c_smbus_write_word_data(client, reg, swab16(value)); | ||
129 | } | 100 | } |
130 | 101 | ||
131 | static void ds1621_init_client(struct i2c_client *client) | 102 | static void ds1621_init_client(struct i2c_client *client) |
132 | { | 103 | { |
133 | int reg = ds1621_read_value(client, DS1621_REG_CONF); | 104 | u8 conf, new_conf; |
105 | |||
106 | new_conf = conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | ||
134 | /* switch to continuous conversion mode */ | 107 | /* switch to continuous conversion mode */ |
135 | reg &= ~ DS1621_REG_CONFIG_1SHOT; | 108 | new_conf &= ~DS1621_REG_CONFIG_1SHOT; |
136 | 109 | ||
137 | /* setup output polarity */ | 110 | /* setup output polarity */ |
138 | if (polarity == 0) | 111 | if (polarity == 0) |
139 | reg &= ~DS1621_REG_CONFIG_POLARITY; | 112 | new_conf &= ~DS1621_REG_CONFIG_POLARITY; |
140 | else if (polarity == 1) | 113 | else if (polarity == 1) |
141 | reg |= DS1621_REG_CONFIG_POLARITY; | 114 | new_conf |= DS1621_REG_CONFIG_POLARITY; |
142 | 115 | ||
143 | ds1621_write_value(client, DS1621_REG_CONF, reg); | 116 | if (conf != new_conf) |
117 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, new_conf); | ||
144 | 118 | ||
145 | /* start conversion */ | 119 | /* start conversion */ |
146 | i2c_smbus_write_byte(client, DS1621_COM_START); | 120 | i2c_smbus_write_byte(client, DS1621_COM_START); |
147 | } | 121 | } |
148 | 122 | ||
123 | static struct ds1621_data *ds1621_update_client(struct device *dev) | ||
124 | { | ||
125 | struct i2c_client *client = to_i2c_client(dev); | ||
126 | struct ds1621_data *data = i2c_get_clientdata(client); | ||
127 | u8 new_conf; | ||
128 | |||
129 | mutex_lock(&data->update_lock); | ||
130 | |||
131 | if (time_after(jiffies, data->last_updated + HZ + HZ / 2) | ||
132 | || !data->valid) { | ||
133 | int i; | ||
134 | |||
135 | dev_dbg(&client->dev, "Starting ds1621 update\n"); | ||
136 | |||
137 | data->conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); | ||
138 | |||
139 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) | ||
140 | data->temp[i] = ds1621_read_temp(client, | ||
141 | DS1621_REG_TEMP[i]); | ||
142 | |||
143 | /* reset alarms if necessary */ | ||
144 | new_conf = data->conf; | ||
145 | if (data->temp[0] > data->temp[1]) /* input > min */ | ||
146 | new_conf &= ~DS1621_ALARM_TEMP_LOW; | ||
147 | if (data->temp[0] < data->temp[2]) /* input < max */ | ||
148 | new_conf &= ~DS1621_ALARM_TEMP_HIGH; | ||
149 | if (data->conf != new_conf) | ||
150 | i2c_smbus_write_byte_data(client, DS1621_REG_CONF, | ||
151 | new_conf); | ||
152 | |||
153 | data->last_updated = jiffies; | ||
154 | data->valid = 1; | ||
155 | } | ||
156 | |||
157 | mutex_unlock(&data->update_lock); | ||
158 | |||
159 | return data; | ||
160 | } | ||
161 | |||
149 | static ssize_t show_temp(struct device *dev, struct device_attribute *da, | 162 | static ssize_t show_temp(struct device *dev, struct device_attribute *da, |
150 | char *buf) | 163 | char *buf) |
151 | { | 164 | { |
@@ -160,13 +173,13 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, | |||
160 | { | 173 | { |
161 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | 174 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); |
162 | struct i2c_client *client = to_i2c_client(dev); | 175 | struct i2c_client *client = to_i2c_client(dev); |
163 | struct ds1621_data *data = ds1621_update_client(dev); | 176 | struct ds1621_data *data = i2c_get_clientdata(client); |
164 | u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); | 177 | u16 val = LM75_TEMP_TO_REG(simple_strtol(buf, NULL, 10)); |
165 | 178 | ||
166 | mutex_lock(&data->update_lock); | 179 | mutex_lock(&data->update_lock); |
167 | data->temp[attr->index] = val; | 180 | data->temp[attr->index] = val; |
168 | ds1621_write_value(client, DS1621_REG_TEMP[attr->index], | 181 | ds1621_write_temp(client, DS1621_REG_TEMP[attr->index], |
169 | data->temp[attr->index]); | 182 | data->temp[attr->index]); |
170 | mutex_unlock(&data->update_lock); | 183 | mutex_unlock(&data->update_lock); |
171 | return count; | 184 | return count; |
172 | } | 185 | } |
@@ -228,13 +241,14 @@ static int ds1621_detect(struct i2c_client *client, int kind, | |||
228 | /* The NVB bit should be low if no EEPROM write has been | 241 | /* The NVB bit should be low if no EEPROM write has been |
229 | requested during the latest 10ms, which is highly | 242 | requested during the latest 10ms, which is highly |
230 | improbable in our case. */ | 243 | improbable in our case. */ |
231 | conf = ds1621_read_value(client, DS1621_REG_CONF); | 244 | conf = i2c_smbus_read_byte_data(client, DS1621_REG_CONF); |
232 | if (conf & DS1621_REG_CONFIG_NVB) | 245 | if (conf < 0 || conf & DS1621_REG_CONFIG_NVB) |
233 | return -ENODEV; | 246 | return -ENODEV; |
234 | /* The 7 lowest bits of a temperature should always be 0. */ | 247 | /* The 7 lowest bits of a temperature should always be 0. */ |
235 | for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { | 248 | for (i = 0; i < ARRAY_SIZE(DS1621_REG_TEMP); i++) { |
236 | temp = ds1621_read_value(client, DS1621_REG_TEMP[i]); | 249 | temp = i2c_smbus_read_word_data(client, |
237 | if (temp & 0x007f) | 250 | DS1621_REG_TEMP[i]); |
251 | if (temp < 0 || (temp & 0x7f00)) | ||
238 | return -ENODEV; | 252 | return -ENODEV; |
239 | } | 253 | } |
240 | } | 254 | } |
@@ -294,45 +308,25 @@ static int ds1621_remove(struct i2c_client *client) | |||
294 | return 0; | 308 | return 0; |
295 | } | 309 | } |
296 | 310 | ||
311 | static const struct i2c_device_id ds1621_id[] = { | ||
312 | { "ds1621", ds1621 }, | ||
313 | { "ds1625", ds1621 }, | ||
314 | { } | ||
315 | }; | ||
316 | MODULE_DEVICE_TABLE(i2c, ds1621_id); | ||
297 | 317 | ||
298 | static struct ds1621_data *ds1621_update_client(struct device *dev) | 318 | /* This is the driver that will be inserted */ |
299 | { | 319 | static struct i2c_driver ds1621_driver = { |
300 | struct i2c_client *client = to_i2c_client(dev); | 320 | .class = I2C_CLASS_HWMON, |
301 | struct ds1621_data *data = i2c_get_clientdata(client); | 321 | .driver = { |
302 | u8 new_conf; | 322 | .name = "ds1621", |
303 | 323 | }, | |
304 | mutex_lock(&data->update_lock); | 324 | .probe = ds1621_probe, |
305 | 325 | .remove = ds1621_remove, | |
306 | if (time_after(jiffies, data->last_updated + HZ + HZ / 2) | 326 | .id_table = ds1621_id, |
307 | || !data->valid) { | 327 | .detect = ds1621_detect, |
308 | int i; | 328 | .address_data = &addr_data, |
309 | 329 | }; | |
310 | dev_dbg(&client->dev, "Starting ds1621 update\n"); | ||
311 | |||
312 | data->conf = ds1621_read_value(client, DS1621_REG_CONF); | ||
313 | |||
314 | for (i = 0; i < ARRAY_SIZE(data->temp); i++) | ||
315 | data->temp[i] = ds1621_read_value(client, | ||
316 | DS1621_REG_TEMP[i]); | ||
317 | |||
318 | /* reset alarms if necessary */ | ||
319 | new_conf = data->conf; | ||
320 | if (data->temp[0] > data->temp[1]) /* input > min */ | ||
321 | new_conf &= ~DS1621_ALARM_TEMP_LOW; | ||
322 | if (data->temp[0] < data->temp[2]) /* input < max */ | ||
323 | new_conf &= ~DS1621_ALARM_TEMP_HIGH; | ||
324 | if (data->conf != new_conf) | ||
325 | ds1621_write_value(client, DS1621_REG_CONF, | ||
326 | new_conf); | ||
327 | |||
328 | data->last_updated = jiffies; | ||
329 | data->valid = 1; | ||
330 | } | ||
331 | |||
332 | mutex_unlock(&data->update_lock); | ||
333 | |||
334 | return data; | ||
335 | } | ||
336 | 330 | ||
337 | static int __init ds1621_init(void) | 331 | static int __init ds1621_init(void) |
338 | { | 332 | { |
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d07f4ef75092..ea955edde87e 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fschmd.c | 1 | /* fschmd.c |
2 | * | 2 | * |
3 | * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> | 3 | * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, | 21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, |
22 | * Scylla, Heracles and Heimdall chips | 22 | * Scylla, Heracles, Heimdall, Hades and Syleus chips |
23 | * | 23 | * |
24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 | 24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 |
25 | * (candidate) fschmd drivers: | 25 | * (candidate) fschmd drivers: |
@@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
56 | module_param(nowayout, int, 0); | 56 | module_param(nowayout, int, 0); |
57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
59 | I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | 59 | I2C_CLIENT_INSMOD_7(fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl); |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * The FSCHMD registers and other defines | 62 | * The FSCHMD registers and other defines |
@@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 | 75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 |
76 | 76 | ||
77 | /* watchdog */ | 77 | /* watchdog */ |
78 | #define FSCHMD_REG_WDOG_PRESET 0x28 | 78 | static const u8 FSCHMD_REG_WDOG_CONTROL[7] = |
79 | #define FSCHMD_REG_WDOG_STATE 0x23 | 79 | { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 }; |
80 | #define FSCHMD_REG_WDOG_CONTROL 0x21 | 80 | static const u8 FSCHMD_REG_WDOG_STATE[7] = |
81 | { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 }; | ||
82 | static const u8 FSCHMD_REG_WDOG_PRESET[7] = | ||
83 | { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a }; | ||
81 | 84 | ||
82 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 | 85 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 |
83 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ | 86 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ |
@@ -87,70 +90,95 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
87 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 | 90 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 |
88 | 91 | ||
89 | /* voltages, weird order is to keep the same order as the old drivers */ | 92 | /* voltages, weird order is to keep the same order as the old drivers */ |
90 | static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; | 93 | static const u8 FSCHMD_REG_VOLT[7][6] = { |
94 | { 0x45, 0x42, 0x48 }, /* pos */ | ||
95 | { 0x45, 0x42, 0x48 }, /* her */ | ||
96 | { 0x45, 0x42, 0x48 }, /* scy */ | ||
97 | { 0x45, 0x42, 0x48 }, /* hrc */ | ||
98 | { 0x45, 0x42, 0x48 }, /* hmd */ | ||
99 | { 0x21, 0x20, 0x22 }, /* hds */ | ||
100 | { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ | ||
101 | }; | ||
102 | |||
103 | static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 }; | ||
91 | 104 | ||
92 | /* minimum pwm at which the fan is driven (pwm can by increased depending on | 105 | /* minimum pwm at which the fan is driven (pwm can by increased depending on |
93 | the temp. Notice that for the scy some fans share there minimum speed. | 106 | the temp. Notice that for the scy some fans share there minimum speed. |
94 | Also notice that with the scy the sensor order is different than with the | 107 | Also notice that with the scy the sensor order is different than with the |
95 | other chips, this order was in the 2.4 driver and kept for consistency. */ | 108 | other chips, this order was in the 2.4 driver and kept for consistency. */ |
96 | static const u8 FSCHMD_REG_FAN_MIN[5][6] = { | 109 | static const u8 FSCHMD_REG_FAN_MIN[7][7] = { |
97 | { 0x55, 0x65 }, /* pos */ | 110 | { 0x55, 0x65 }, /* pos */ |
98 | { 0x55, 0x65, 0xb5 }, /* her */ | 111 | { 0x55, 0x65, 0xb5 }, /* her */ |
99 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ | 112 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ |
100 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ | 113 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ |
101 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ | 114 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ |
115 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */ | ||
116 | { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ | ||
102 | }; | 117 | }; |
103 | 118 | ||
104 | /* actual fan speed */ | 119 | /* actual fan speed */ |
105 | static const u8 FSCHMD_REG_FAN_ACT[5][6] = { | 120 | static const u8 FSCHMD_REG_FAN_ACT[7][7] = { |
106 | { 0x0e, 0x6b, 0xab }, /* pos */ | 121 | { 0x0e, 0x6b, 0xab }, /* pos */ |
107 | { 0x0e, 0x6b, 0xbb }, /* her */ | 122 | { 0x0e, 0x6b, 0xbb }, /* her */ |
108 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ | 123 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ |
109 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ | 124 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ |
110 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ | 125 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ |
126 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */ | ||
127 | { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ | ||
111 | }; | 128 | }; |
112 | 129 | ||
113 | /* fan status registers */ | 130 | /* fan status registers */ |
114 | static const u8 FSCHMD_REG_FAN_STATE[5][6] = { | 131 | static const u8 FSCHMD_REG_FAN_STATE[7][7] = { |
115 | { 0x0d, 0x62, 0xa2 }, /* pos */ | 132 | { 0x0d, 0x62, 0xa2 }, /* pos */ |
116 | { 0x0d, 0x62, 0xb2 }, /* her */ | 133 | { 0x0d, 0x62, 0xb2 }, /* her */ |
117 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ | 134 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ |
118 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ | 135 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ |
119 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ | 136 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ |
137 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */ | ||
138 | { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ | ||
120 | }; | 139 | }; |
121 | 140 | ||
122 | /* fan ripple / divider registers */ | 141 | /* fan ripple / divider registers */ |
123 | static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { | 142 | static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = { |
124 | { 0x0f, 0x6f, 0xaf }, /* pos */ | 143 | { 0x0f, 0x6f, 0xaf }, /* pos */ |
125 | { 0x0f, 0x6f, 0xbf }, /* her */ | 144 | { 0x0f, 0x6f, 0xbf }, /* her */ |
126 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ | 145 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ |
127 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ | 146 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ |
128 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ | 147 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ |
148 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */ | ||
149 | { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ | ||
129 | }; | 150 | }; |
130 | 151 | ||
131 | static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; | 152 | static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 }; |
132 | 153 | ||
133 | /* Fan status register bitmasks */ | 154 | /* Fan status register bitmasks */ |
134 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ | 155 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ |
135 | #define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */ | 156 | #define FSCHMD_FAN_NOT_PRESENT 0x08 |
157 | #define FSCHMD_FAN_DISABLED 0x80 | ||
136 | 158 | ||
137 | 159 | ||
138 | /* actual temperature registers */ | 160 | /* actual temperature registers */ |
139 | static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { | 161 | static const u8 FSCHMD_REG_TEMP_ACT[7][11] = { |
140 | { 0x64, 0x32, 0x35 }, /* pos */ | 162 | { 0x64, 0x32, 0x35 }, /* pos */ |
141 | { 0x64, 0x32, 0x35 }, /* her */ | 163 | { 0x64, 0x32, 0x35 }, /* her */ |
142 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ | 164 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ |
143 | { 0x64, 0x32, 0x35 }, /* hrc */ | 165 | { 0x64, 0x32, 0x35 }, /* hrc */ |
144 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ | 166 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ |
167 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */ | ||
168 | { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ | ||
169 | 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, | ||
145 | }; | 170 | }; |
146 | 171 | ||
147 | /* temperature state registers */ | 172 | /* temperature state registers */ |
148 | static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | 173 | static const u8 FSCHMD_REG_TEMP_STATE[7][11] = { |
149 | { 0x71, 0x81, 0x91 }, /* pos */ | 174 | { 0x71, 0x81, 0x91 }, /* pos */ |
150 | { 0x71, 0x81, 0x91 }, /* her */ | 175 | { 0x71, 0x81, 0x91 }, /* her */ |
151 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ | 176 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ |
152 | { 0x71, 0x81, 0x91 }, /* hrc */ | 177 | { 0x71, 0x81, 0x91 }, /* hrc */ |
153 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ | 178 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ |
179 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */ | ||
180 | { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ | ||
181 | 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, | ||
154 | }; | 182 | }; |
155 | 183 | ||
156 | /* temperature high limit registers, FSC does not document these. Proven to be | 184 | /* temperature high limit registers, FSC does not document these. Proven to be |
@@ -158,24 +186,31 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | |||
158 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers | 186 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers |
159 | at these addresses, but doesn't want to confirm they are the same as with | 187 | at these addresses, but doesn't want to confirm they are the same as with |
160 | the fscher?? */ | 188 | the fscher?? */ |
161 | static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { | 189 | static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = { |
162 | { 0, 0, 0 }, /* pos */ | 190 | { 0, 0, 0 }, /* pos */ |
163 | { 0x76, 0x86, 0x96 }, /* her */ | 191 | { 0x76, 0x86, 0x96 }, /* her */ |
164 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ | 192 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ |
165 | { 0x76, 0x86, 0x96 }, /* hrc */ | 193 | { 0x76, 0x86, 0x96 }, /* hrc */ |
166 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ | 194 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ |
195 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */ | ||
196 | { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ | ||
197 | 0xba, 0xca, 0xda, 0xea, 0xfa }, | ||
167 | }; | 198 | }; |
168 | 199 | ||
169 | /* These were found through experimenting with an fscher, currently they are | 200 | /* These were found through experimenting with an fscher, currently they are |
170 | not used, but we keep them around for future reference. | 201 | not used, but we keep them around for future reference. |
202 | On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), | ||
203 | AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence | ||
204 | the fan speed. | ||
171 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; | 205 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; |
172 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ | 206 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ |
173 | 207 | ||
174 | static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; | 208 | static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 }; |
175 | 209 | ||
176 | /* temp status register bitmasks */ | 210 | /* temp status register bitmasks */ |
177 | #define FSCHMD_TEMP_WORKING 0x01 | 211 | #define FSCHMD_TEMP_WORKING 0x01 |
178 | #define FSCHMD_TEMP_ALERT 0x02 | 212 | #define FSCHMD_TEMP_ALERT 0x02 |
213 | #define FSCHMD_TEMP_DISABLED 0x80 | ||
179 | /* there only really is an alarm if the sensor is working and alert == 1 */ | 214 | /* there only really is an alarm if the sensor is working and alert == 1 */ |
180 | #define FSCHMD_TEMP_ALARM_MASK \ | 215 | #define FSCHMD_TEMP_ALARM_MASK \ |
181 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) | 216 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) |
@@ -201,6 +236,8 @@ static const struct i2c_device_id fschmd_id[] = { | |||
201 | { "fscscy", fscscy }, | 236 | { "fscscy", fscscy }, |
202 | { "fschrc", fschrc }, | 237 | { "fschrc", fschrc }, |
203 | { "fschmd", fschmd }, | 238 | { "fschmd", fschmd }, |
239 | { "fschds", fschds }, | ||
240 | { "fscsyl", fscsyl }, | ||
204 | { } | 241 | { } |
205 | }; | 242 | }; |
206 | MODULE_DEVICE_TABLE(i2c, fschmd_id); | 243 | MODULE_DEVICE_TABLE(i2c, fschmd_id); |
@@ -242,14 +279,14 @@ struct fschmd_data { | |||
242 | u8 watchdog_control; /* watchdog control register */ | 279 | u8 watchdog_control; /* watchdog control register */ |
243 | u8 watchdog_state; /* watchdog status register */ | 280 | u8 watchdog_state; /* watchdog status register */ |
244 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ | 281 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ |
245 | u8 volt[3]; /* 12, 5, battery voltage */ | 282 | u8 volt[6]; /* voltage */ |
246 | u8 temp_act[5]; /* temperature */ | 283 | u8 temp_act[11]; /* temperature */ |
247 | u8 temp_status[5]; /* status of sensor */ | 284 | u8 temp_status[11]; /* status of sensor */ |
248 | u8 temp_max[5]; /* high temp limit, notice: undocumented! */ | 285 | u8 temp_max[11]; /* high temp limit, notice: undocumented! */ |
249 | u8 fan_act[6]; /* fans revolutions per second */ | 286 | u8 fan_act[7]; /* fans revolutions per second */ |
250 | u8 fan_status[6]; /* fan status */ | 287 | u8 fan_status[7]; /* fan status */ |
251 | u8 fan_min[6]; /* fan min value for rps */ | 288 | u8 fan_min[7]; /* fan min value for rps */ |
252 | u8 fan_ripple[6]; /* divider for rps */ | 289 | u8 fan_ripple[7]; /* divider for rps */ |
253 | }; | 290 | }; |
254 | 291 | ||
255 | /* Global variables to hold information read from special DMI tables, which are | 292 | /* Global variables to hold information read from special DMI tables, which are |
@@ -257,8 +294,8 @@ struct fschmd_data { | |||
257 | protect these with a lock as they are only modified from our attach function | 294 | protect these with a lock as they are only modified from our attach function |
258 | which always gets called with the i2c-core lock held and never accessed | 295 | which always gets called with the i2c-core lock held and never accessed |
259 | before the attach function is done with them. */ | 296 | before the attach function is done with them. */ |
260 | static int dmi_mult[3] = { 490, 200, 100 }; | 297 | static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; |
261 | static int dmi_offset[3] = { 0, 0, 0 }; | 298 | static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; |
262 | static int dmi_vref = -1; | 299 | static int dmi_vref = -1; |
263 | 300 | ||
264 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that | 301 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that |
@@ -450,10 +487,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev, | |||
450 | struct device_attribute *devattr, char *buf) | 487 | struct device_attribute *devattr, char *buf) |
451 | { | 488 | { |
452 | int index = to_sensor_dev_attr(devattr)->index; | 489 | int index = to_sensor_dev_attr(devattr)->index; |
453 | int val = fschmd_update_device(dev)->fan_min[index]; | 490 | struct fschmd_data *data = fschmd_update_device(dev); |
491 | int val = data->fan_min[index]; | ||
454 | 492 | ||
455 | /* 0 = allow turning off, 1-255 = 50-100% */ | 493 | /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
456 | if (val) | 494 | if (val || data->kind == fscsyl - 1) |
457 | val = val / 2 + 128; | 495 | val = val / 2 + 128; |
458 | 496 | ||
459 | return sprintf(buf, "%d\n", val); | 497 | return sprintf(buf, "%d\n", val); |
@@ -466,8 +504,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, | |||
466 | struct fschmd_data *data = dev_get_drvdata(dev); | 504 | struct fschmd_data *data = dev_get_drvdata(dev); |
467 | unsigned long v = simple_strtoul(buf, NULL, 10); | 505 | unsigned long v = simple_strtoul(buf, NULL, 10); |
468 | 506 | ||
469 | /* register: 0 = allow turning off, 1-255 = 50-100% */ | 507 | /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
470 | if (v) { | 508 | if (v || data->kind == fscsyl - 1) { |
471 | v = SENSORS_LIMIT(v, 128, 255); | 509 | v = SENSORS_LIMIT(v, 128, 255); |
472 | v = (v - 128) * 2 + 1; | 510 | v = (v - 128) * 2 + 1; |
473 | } | 511 | } |
@@ -522,11 +560,15 @@ static ssize_t store_alert_led(struct device *dev, | |||
522 | return count; | 560 | return count; |
523 | } | 561 | } |
524 | 562 | ||
563 | static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); | ||
564 | |||
525 | static struct sensor_device_attribute fschmd_attr[] = { | 565 | static struct sensor_device_attribute fschmd_attr[] = { |
526 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), | 566 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), |
527 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), | 567 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), |
528 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), | 568 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), |
529 | SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), | 569 | SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3), |
570 | SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4), | ||
571 | SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5), | ||
530 | }; | 572 | }; |
531 | 573 | ||
532 | static struct sensor_device_attribute fschmd_temp_attr[] = { | 574 | static struct sensor_device_attribute fschmd_temp_attr[] = { |
@@ -550,6 +592,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = { | |||
550 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), | 592 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), |
551 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), | 593 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), |
552 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), | 594 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), |
595 | SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5), | ||
596 | SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5), | ||
597 | SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5), | ||
598 | SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5), | ||
599 | SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6), | ||
600 | SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6), | ||
601 | SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6), | ||
602 | SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6), | ||
603 | SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7), | ||
604 | SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7), | ||
605 | SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7), | ||
606 | SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7), | ||
607 | SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8), | ||
608 | SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8), | ||
609 | SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8), | ||
610 | SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8), | ||
611 | SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9), | ||
612 | SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9), | ||
613 | SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9), | ||
614 | SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9), | ||
615 | SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10), | ||
616 | SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10), | ||
617 | SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10), | ||
618 | SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10), | ||
553 | }; | 619 | }; |
554 | 620 | ||
555 | static struct sensor_device_attribute fschmd_fan_attr[] = { | 621 | static struct sensor_device_attribute fschmd_fan_attr[] = { |
@@ -589,6 +655,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { | |||
589 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), | 655 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), |
590 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | 656 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, |
591 | store_pwm_auto_point1_pwm, 5), | 657 | store_pwm_auto_point1_pwm, 5), |
658 | SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6), | ||
659 | SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6), | ||
660 | SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6), | ||
661 | SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6), | ||
662 | SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | ||
663 | store_pwm_auto_point1_pwm, 6), | ||
592 | }; | 664 | }; |
593 | 665 | ||
594 | 666 | ||
@@ -624,10 +696,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout) | |||
624 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); | 696 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); |
625 | 697 | ||
626 | /* Write new timeout value */ | 698 | /* Write new timeout value */ |
627 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET, | 699 | i2c_smbus_write_byte_data(data->client, |
628 | data->watchdog_preset); | 700 | FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); |
629 | /* Write new control register, do not trigger! */ | 701 | /* Write new control register, do not trigger! */ |
630 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 702 | i2c_smbus_write_byte_data(data->client, |
703 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
631 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); | 704 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); |
632 | 705 | ||
633 | ret = data->watchdog_preset * resolution; | 706 | ret = data->watchdog_preset * resolution; |
@@ -662,8 +735,9 @@ static int watchdog_trigger(struct fschmd_data *data) | |||
662 | } | 735 | } |
663 | 736 | ||
664 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; | 737 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; |
665 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 738 | i2c_smbus_write_byte_data(data->client, |
666 | data->watchdog_control); | 739 | FSCHMD_REG_WDOG_CONTROL[data->kind], |
740 | data->watchdog_control); | ||
667 | leave: | 741 | leave: |
668 | mutex_unlock(&data->watchdog_lock); | 742 | mutex_unlock(&data->watchdog_lock); |
669 | return ret; | 743 | return ret; |
@@ -682,7 +756,8 @@ static int watchdog_stop(struct fschmd_data *data) | |||
682 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; | 756 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; |
683 | /* Don't store the stop flag in our watchdog control register copy, as | 757 | /* Don't store the stop flag in our watchdog control register copy, as |
684 | its a write only bit (read always returns 0) */ | 758 | its a write only bit (read always returns 0) */ |
685 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 759 | i2c_smbus_write_byte_data(data->client, |
760 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
686 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); | 761 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); |
687 | leave: | 762 | leave: |
688 | mutex_unlock(&data->watchdog_lock); | 763 | mutex_unlock(&data->watchdog_lock); |
@@ -856,7 +931,7 @@ static struct file_operations watchdog_fops = { | |||
856 | 931 | ||
857 | /* DMI decode routine to read voltage scaling factors from special DMI tables, | 932 | /* DMI decode routine to read voltage scaling factors from special DMI tables, |
858 | which are available on FSC machines with an fscher or later chip. */ | 933 | which are available on FSC machines with an fscher or later chip. */ |
859 | static void fschmd_dmi_decode(const struct dmi_header *header) | 934 | static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) |
860 | { | 935 | { |
861 | int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; | 936 | int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0; |
862 | 937 | ||
@@ -912,6 +987,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header) | |||
912 | dmi_mult[i] = mult[i] * 10; | 987 | dmi_mult[i] = mult[i] * 10; |
913 | dmi_offset[i] = offset[i] * 10; | 988 | dmi_offset[i] = offset[i] * 10; |
914 | } | 989 | } |
990 | /* According to the docs there should be separate dmi entries | ||
991 | for the mult's and offsets of in3-5 of the syl, but on | ||
992 | my test machine these are not present */ | ||
993 | dmi_mult[3] = dmi_mult[2]; | ||
994 | dmi_mult[4] = dmi_mult[1]; | ||
995 | dmi_mult[5] = dmi_mult[2]; | ||
996 | dmi_offset[3] = dmi_offset[2]; | ||
997 | dmi_offset[4] = dmi_offset[1]; | ||
998 | dmi_offset[5] = dmi_offset[2]; | ||
915 | dmi_vref = vref; | 999 | dmi_vref = vref; |
916 | } | 1000 | } |
917 | } | 1001 | } |
@@ -920,8 +1004,6 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
920 | struct i2c_board_info *info) | 1004 | struct i2c_board_info *info) |
921 | { | 1005 | { |
922 | struct i2c_adapter *adapter = client->adapter; | 1006 | struct i2c_adapter *adapter = client->adapter; |
923 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", | ||
924 | "fschrc", "fschmd" }; | ||
925 | 1007 | ||
926 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 1008 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
927 | return -ENODEV; | 1009 | return -ENODEV; |
@@ -948,11 +1030,15 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
948 | kind = fschrc; | 1030 | kind = fschrc; |
949 | else if (!strcmp(id, "HMD")) | 1031 | else if (!strcmp(id, "HMD")) |
950 | kind = fschmd; | 1032 | kind = fschmd; |
1033 | else if (!strcmp(id, "HDS")) | ||
1034 | kind = fschds; | ||
1035 | else if (!strcmp(id, "SYL")) | ||
1036 | kind = fscsyl; | ||
951 | else | 1037 | else |
952 | return -ENODEV; | 1038 | return -ENODEV; |
953 | } | 1039 | } |
954 | 1040 | ||
955 | strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); | 1041 | strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE); |
956 | 1042 | ||
957 | return 0; | 1043 | return 0; |
958 | } | 1044 | } |
@@ -961,8 +1047,8 @@ static int fschmd_probe(struct i2c_client *client, | |||
961 | const struct i2c_device_id *id) | 1047 | const struct i2c_device_id *id) |
962 | { | 1048 | { |
963 | struct fschmd_data *data; | 1049 | struct fschmd_data *data; |
964 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | 1050 | const char * const names[7] = { "Poseidon", "Hermes", "Scylla", |
965 | "Heracles", "Heimdall" }; | 1051 | "Heracles", "Heimdall", "Hades", "Syleus" }; |
966 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; | 1052 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; |
967 | int i, err; | 1053 | int i, err; |
968 | enum chips kind = id->driver_data; | 1054 | enum chips kind = id->driver_data; |
@@ -991,7 +1077,7 @@ static int fschmd_probe(struct i2c_client *client, | |||
991 | 1077 | ||
992 | /* Read the special DMI table for fscher and newer chips */ | 1078 | /* Read the special DMI table for fscher and newer chips */ |
993 | if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { | 1079 | if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) { |
994 | dmi_walk(fschmd_dmi_decode); | 1080 | dmi_walk(fschmd_dmi_decode, NULL); |
995 | if (dmi_vref == -1) { | 1081 | if (dmi_vref == -1) { |
996 | dev_warn(&client->dev, | 1082 | dev_warn(&client->dev, |
997 | "Couldn't get voltage scaling factors from " | 1083 | "Couldn't get voltage scaling factors from " |
@@ -1000,21 +1086,25 @@ static int fschmd_probe(struct i2c_client *client, | |||
1000 | } | 1086 | } |
1001 | } | 1087 | } |
1002 | 1088 | ||
1089 | /* i2c kind goes from 1-6, we want from 0-5 to address arrays */ | ||
1090 | data->kind = kind - 1; | ||
1091 | |||
1003 | /* Read in some never changing registers */ | 1092 | /* Read in some never changing registers */ |
1004 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); | 1093 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); |
1005 | data->global_control = i2c_smbus_read_byte_data(client, | 1094 | data->global_control = i2c_smbus_read_byte_data(client, |
1006 | FSCHMD_REG_CONTROL); | 1095 | FSCHMD_REG_CONTROL); |
1007 | data->watchdog_control = i2c_smbus_read_byte_data(client, | 1096 | data->watchdog_control = i2c_smbus_read_byte_data(client, |
1008 | FSCHMD_REG_WDOG_CONTROL); | 1097 | FSCHMD_REG_WDOG_CONTROL[data->kind]); |
1009 | data->watchdog_state = i2c_smbus_read_byte_data(client, | 1098 | data->watchdog_state = i2c_smbus_read_byte_data(client, |
1010 | FSCHMD_REG_WDOG_STATE); | 1099 | FSCHMD_REG_WDOG_STATE[data->kind]); |
1011 | data->watchdog_preset = i2c_smbus_read_byte_data(client, | 1100 | data->watchdog_preset = i2c_smbus_read_byte_data(client, |
1012 | FSCHMD_REG_WDOG_PRESET); | 1101 | FSCHMD_REG_WDOG_PRESET[data->kind]); |
1013 | 1102 | ||
1014 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ | 1103 | err = device_create_file(&client->dev, &dev_attr_alert_led); |
1015 | data->kind = kind - 1; | 1104 | if (err) |
1105 | goto exit_detach; | ||
1016 | 1106 | ||
1017 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { | 1107 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { |
1018 | err = device_create_file(&client->dev, | 1108 | err = device_create_file(&client->dev, |
1019 | &fschmd_attr[i].dev_attr); | 1109 | &fschmd_attr[i].dev_attr); |
1020 | if (err) | 1110 | if (err) |
@@ -1027,6 +1117,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1027 | show_temp_max) | 1117 | show_temp_max) |
1028 | continue; | 1118 | continue; |
1029 | 1119 | ||
1120 | if (kind == fscsyl) { | ||
1121 | if (i % 4 == 0) | ||
1122 | data->temp_status[i / 4] = | ||
1123 | i2c_smbus_read_byte_data(client, | ||
1124 | FSCHMD_REG_TEMP_STATE | ||
1125 | [data->kind][i / 4]); | ||
1126 | if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED) | ||
1127 | continue; | ||
1128 | } | ||
1129 | |||
1030 | err = device_create_file(&client->dev, | 1130 | err = device_create_file(&client->dev, |
1031 | &fschmd_temp_attr[i].dev_attr); | 1131 | &fschmd_temp_attr[i].dev_attr); |
1032 | if (err) | 1132 | if (err) |
@@ -1040,6 +1140,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1040 | "pwm3_auto_point1_pwm")) | 1140 | "pwm3_auto_point1_pwm")) |
1041 | continue; | 1141 | continue; |
1042 | 1142 | ||
1143 | if (kind == fscsyl) { | ||
1144 | if (i % 5 == 0) | ||
1145 | data->fan_status[i / 5] = | ||
1146 | i2c_smbus_read_byte_data(client, | ||
1147 | FSCHMD_REG_FAN_STATE | ||
1148 | [data->kind][i / 5]); | ||
1149 | if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED) | ||
1150 | continue; | ||
1151 | } | ||
1152 | |||
1043 | err = device_create_file(&client->dev, | 1153 | err = device_create_file(&client->dev, |
1044 | &fschmd_fan_attr[i].dev_attr); | 1154 | &fschmd_fan_attr[i].dev_attr); |
1045 | if (err) | 1155 | if (err) |
@@ -1126,7 +1236,8 @@ static int fschmd_remove(struct i2c_client *client) | |||
1126 | if (data->hwmon_dev) | 1236 | if (data->hwmon_dev) |
1127 | hwmon_device_unregister(data->hwmon_dev); | 1237 | hwmon_device_unregister(data->hwmon_dev); |
1128 | 1238 | ||
1129 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) | 1239 | device_remove_file(&client->dev, &dev_attr_alert_led); |
1240 | for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++) | ||
1130 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); | 1241 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); |
1131 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) | 1242 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) |
1132 | device_remove_file(&client->dev, | 1243 | device_remove_file(&client->dev, |
@@ -1171,7 +1282,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1171 | data->temp_act[i] < data->temp_max[i]) | 1282 | data->temp_act[i] < data->temp_max[i]) |
1172 | i2c_smbus_write_byte_data(client, | 1283 | i2c_smbus_write_byte_data(client, |
1173 | FSCHMD_REG_TEMP_STATE[data->kind][i], | 1284 | FSCHMD_REG_TEMP_STATE[data->kind][i], |
1174 | FSCHMD_TEMP_ALERT); | 1285 | data->temp_status[i]); |
1175 | } | 1286 | } |
1176 | 1287 | ||
1177 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { | 1288 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { |
@@ -1193,12 +1304,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1193 | data->fan_act[i]) | 1304 | data->fan_act[i]) |
1194 | i2c_smbus_write_byte_data(client, | 1305 | i2c_smbus_write_byte_data(client, |
1195 | FSCHMD_REG_FAN_STATE[data->kind][i], | 1306 | FSCHMD_REG_FAN_STATE[data->kind][i], |
1196 | FSCHMD_FAN_ALARM); | 1307 | data->fan_status[i]); |
1197 | } | 1308 | } |
1198 | 1309 | ||
1199 | for (i = 0; i < 3; i++) | 1310 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) |
1200 | data->volt[i] = i2c_smbus_read_byte_data(client, | 1311 | data->volt[i] = i2c_smbus_read_byte_data(client, |
1201 | FSCHMD_REG_VOLT[i]); | 1312 | FSCHMD_REG_VOLT[data->kind][i]); |
1202 | 1313 | ||
1203 | data->last_updated = jiffies; | 1314 | data->last_updated = jiffies; |
1204 | data->valid = 1; | 1315 | data->valid = 1; |
@@ -1220,8 +1331,8 @@ static void __exit fschmd_exit(void) | |||
1220 | } | 1331 | } |
1221 | 1332 | ||
1222 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | 1333 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
1223 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " | 1334 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades " |
1224 | "Heimdall driver"); | 1335 | "and Syleus driver"); |
1225 | MODULE_LICENSE("GPL"); | 1336 | MODULE_LICENSE("GPL"); |
1226 | 1337 | ||
1227 | module_init(fschmd_init); | 1338 | module_init(fschmd_init); |
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index a4d92d246d52..d3612a1f1981 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c | |||
@@ -65,6 +65,10 @@ | |||
65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ | 65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ |
66 | #define HDAPS_INPUT_FLAT 4 | 66 | #define HDAPS_INPUT_FLAT 4 |
67 | 67 | ||
68 | #define HDAPS_X_AXIS (1 << 0) | ||
69 | #define HDAPS_Y_AXIS (1 << 1) | ||
70 | #define HDAPS_BOTH_AXES (HDAPS_X_AXIS | HDAPS_Y_AXIS) | ||
71 | |||
68 | static struct platform_device *pdev; | 72 | static struct platform_device *pdev; |
69 | static struct input_polled_dev *hdaps_idev; | 73 | static struct input_polled_dev *hdaps_idev; |
70 | static unsigned int hdaps_invert; | 74 | static unsigned int hdaps_invert; |
@@ -182,11 +186,11 @@ static int __hdaps_read_pair(unsigned int port1, unsigned int port2, | |||
182 | km_activity = inb(HDAPS_PORT_KMACT); | 186 | km_activity = inb(HDAPS_PORT_KMACT); |
183 | __device_complete(); | 187 | __device_complete(); |
184 | 188 | ||
185 | /* if hdaps_invert is set, negate the two values */ | 189 | /* hdaps_invert is a bitvector to negate the axes */ |
186 | if (hdaps_invert) { | 190 | if (hdaps_invert & HDAPS_X_AXIS) |
187 | *x = -*x; | 191 | *x = -*x; |
192 | if (hdaps_invert & HDAPS_Y_AXIS) | ||
188 | *y = -*y; | 193 | *y = -*y; |
189 | } | ||
190 | 194 | ||
191 | return 0; | 195 | return 0; |
192 | } | 196 | } |
@@ -436,7 +440,8 @@ static ssize_t hdaps_invert_store(struct device *dev, | |||
436 | { | 440 | { |
437 | int invert; | 441 | int invert; |
438 | 442 | ||
439 | if (sscanf(buf, "%d", &invert) != 1 || (invert != 1 && invert != 0)) | 443 | if (sscanf(buf, "%d", &invert) != 1 || |
444 | invert < 0 || invert > HDAPS_BOTH_AXES) | ||
440 | return -EINVAL; | 445 | return -EINVAL; |
441 | 446 | ||
442 | hdaps_invert = invert; | 447 | hdaps_invert = invert; |
@@ -483,56 +488,52 @@ static int __init hdaps_dmi_match(const struct dmi_system_id *id) | |||
483 | /* hdaps_dmi_match_invert - found an inverted match. */ | 488 | /* hdaps_dmi_match_invert - found an inverted match. */ |
484 | static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) | 489 | static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id) |
485 | { | 490 | { |
486 | hdaps_invert = 1; | 491 | hdaps_invert = (unsigned long)id->driver_data; |
487 | printk(KERN_INFO "hdaps: inverting axis readings.\n"); | 492 | printk(KERN_INFO "hdaps: inverting axis (%u) readings.\n", |
493 | hdaps_invert); | ||
488 | return hdaps_dmi_match(id); | 494 | return hdaps_dmi_match(id); |
489 | } | 495 | } |
490 | 496 | ||
491 | #define HDAPS_DMI_MATCH_NORMAL(vendor, model) { \ | 497 | #define HDAPS_DMI_MATCH_INVERT(vendor, model, axes) { \ |
492 | .ident = vendor " " model, \ | ||
493 | .callback = hdaps_dmi_match, \ | ||
494 | .matches = { \ | ||
495 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ | ||
496 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ | ||
497 | } \ | ||
498 | } | ||
499 | |||
500 | #define HDAPS_DMI_MATCH_INVERT(vendor, model) { \ | ||
501 | .ident = vendor " " model, \ | 498 | .ident = vendor " " model, \ |
502 | .callback = hdaps_dmi_match_invert, \ | 499 | .callback = hdaps_dmi_match_invert, \ |
500 | .driver_data = (void *)axes, \ | ||
503 | .matches = { \ | 501 | .matches = { \ |
504 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ | 502 | DMI_MATCH(DMI_BOARD_VENDOR, vendor), \ |
505 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ | 503 | DMI_MATCH(DMI_PRODUCT_VERSION, model) \ |
506 | } \ | 504 | } \ |
507 | } | 505 | } |
508 | 506 | ||
507 | #define HDAPS_DMI_MATCH_NORMAL(vendor, model) \ | ||
508 | HDAPS_DMI_MATCH_INVERT(vendor, model, 0) | ||
509 | |||
509 | /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match | 510 | /* Note that HDAPS_DMI_MATCH_NORMAL("ThinkPad T42") would match |
510 | "ThinkPad T42p", so the order of the entries matters. | 511 | "ThinkPad T42p", so the order of the entries matters. |
511 | If your ThinkPad is not recognized, please update to latest | 512 | If your ThinkPad is not recognized, please update to latest |
512 | BIOS. This is especially the case for some R52 ThinkPads. */ | 513 | BIOS. This is especially the case for some R52 ThinkPads. */ |
513 | static struct dmi_system_id __initdata hdaps_whitelist[] = { | 514 | static struct dmi_system_id __initdata hdaps_whitelist[] = { |
514 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p"), | 515 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad R50p", HDAPS_BOTH_AXES), |
515 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), | 516 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R50"), |
516 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), | 517 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R51"), |
517 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"), | 518 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad R52"), |
518 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i"), | 519 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61i", HDAPS_BOTH_AXES), |
519 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61"), | 520 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad R61", HDAPS_BOTH_AXES), |
520 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p"), | 521 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T41p", HDAPS_BOTH_AXES), |
521 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"), | 522 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T41"), |
522 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p"), | 523 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad T42p", HDAPS_BOTH_AXES), |
523 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"), | 524 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T42"), |
524 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"), | 525 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad T43"), |
525 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60"), | 526 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T60", HDAPS_BOTH_AXES), |
526 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p"), | 527 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61p", HDAPS_BOTH_AXES), |
527 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61"), | 528 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad T61", HDAPS_BOTH_AXES), |
528 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"), | 529 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X40"), |
529 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad X41"), | 530 | HDAPS_DMI_MATCH_INVERT("IBM", "ThinkPad X41", HDAPS_Y_AXIS), |
530 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60"), | 531 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X60", HDAPS_BOTH_AXES), |
531 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s"), | 532 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61s", HDAPS_BOTH_AXES), |
532 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61"), | 533 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad X61", HDAPS_BOTH_AXES), |
533 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), | 534 | HDAPS_DMI_MATCH_NORMAL("IBM", "ThinkPad Z60m"), |
534 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m"), | 535 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61m", HDAPS_BOTH_AXES), |
535 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p"), | 536 | HDAPS_DMI_MATCH_INVERT("LENOVO", "ThinkPad Z61p", HDAPS_BOTH_AXES), |
536 | { .ident = NULL } | 537 | { .ident = NULL } |
537 | }; | 538 | }; |
538 | 539 | ||
@@ -627,8 +628,9 @@ static void __exit hdaps_exit(void) | |||
627 | module_init(hdaps_init); | 628 | module_init(hdaps_init); |
628 | module_exit(hdaps_exit); | 629 | module_exit(hdaps_exit); |
629 | 630 | ||
630 | module_param_named(invert, hdaps_invert, bool, 0); | 631 | module_param_named(invert, hdaps_invert, int, 0); |
631 | MODULE_PARM_DESC(invert, "invert data along each axis"); | 632 | MODULE_PARM_DESC(invert, "invert data along each axis. 1 invert x-axis, " |
633 | "2 invert y-axis, 3 invert both axes."); | ||
632 | 634 | ||
633 | MODULE_AUTHOR("Robert Love"); | 635 | MODULE_AUTHOR("Robert Love"); |
634 | MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver"); | 636 | MODULE_DESCRIPTION("IBM Hard Drive Active Protection System (HDAPS) driver"); |
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/hwmon/pcf8591.c index 16ce3e193776..1d7ffebd679d 100644 --- a/drivers/i2c/chips/pcf8591.c +++ b/drivers/hwmon/pcf8591.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> | 2 | Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> |
3 | Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with | 3 | Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with |
4 | the help of Jean Delvare <khali@linux-fr.org> | 4 | the help of Jean Delvare <khali@linux-fr.org> |
5 | 5 | ||
6 | This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
@@ -41,13 +41,13 @@ MODULE_PARM_DESC(input_mode, | |||
41 | " 3 = two differential inputs\n"); | 41 | " 3 = two differential inputs\n"); |
42 | 42 | ||
43 | /* The PCF8591 control byte | 43 | /* The PCF8591 control byte |
44 | 7 6 5 4 3 2 1 0 | 44 | 7 6 5 4 3 2 1 0 |
45 | | 0 |AOEF| AIP | 0 |AINC| AICH | */ | 45 | | 0 |AOEF| AIP | 0 |AINC| AICH | */ |
46 | 46 | ||
47 | /* Analog Output Enable Flag (analog output active if 1) */ | 47 | /* Analog Output Enable Flag (analog output active if 1) */ |
48 | #define PCF8591_CONTROL_AOEF 0x40 | 48 | #define PCF8591_CONTROL_AOEF 0x40 |
49 | 49 | ||
50 | /* Analog Input Programming | 50 | /* Analog Input Programming |
51 | 0x00 = four single ended inputs | 51 | 0x00 = four single ended inputs |
52 | 0x10 = three differential inputs | 52 | 0x10 = three differential inputs |
53 | 0x20 = single ended and differential mixed | 53 | 0x20 = single ended and differential mixed |
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(input_mode, | |||
58 | #define PCF8591_CONTROL_AINC 0x04 | 58 | #define PCF8591_CONTROL_AINC 0x04 |
59 | 59 | ||
60 | /* Channel selection | 60 | /* Channel selection |
61 | 0x00 = channel 0 | 61 | 0x00 = channel 0 |
62 | 0x01 = channel 1 | 62 | 0x01 = channel 1 |
63 | 0x02 = channel 2 | 63 | 0x02 = channel 2 |
64 | 0x03 = channel 3 */ | 64 | 0x03 = channel 3 */ |
@@ -114,7 +114,7 @@ static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr | |||
114 | return -EINVAL; | 114 | return -EINVAL; |
115 | } | 115 | } |
116 | 116 | ||
117 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, | 117 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, |
118 | show_out0_ouput, set_out0_output); | 118 | show_out0_ouput, set_out0_output); |
119 | 119 | ||
120 | static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) | 120 | static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) |
@@ -139,7 +139,7 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr | |||
139 | return count; | 139 | return count; |
140 | } | 140 | } |
141 | 141 | ||
142 | static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, | 142 | static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, |
143 | show_out0_enable, set_out0_enable); | 143 | show_out0_enable, set_out0_enable); |
144 | 144 | ||
145 | static struct attribute *pcf8591_attributes[] = { | 145 | static struct attribute *pcf8591_attributes[] = { |
@@ -196,7 +196,7 @@ static int pcf8591_probe(struct i2c_client *client, | |||
196 | err = -ENOMEM; | 196 | err = -ENOMEM; |
197 | goto exit; | 197 | goto exit; |
198 | } | 198 | } |
199 | 199 | ||
200 | i2c_set_clientdata(client, data); | 200 | i2c_set_clientdata(client, data); |
201 | mutex_init(&data->update_lock); | 201 | mutex_init(&data->update_lock); |
202 | 202 | ||
@@ -249,8 +249,8 @@ static void pcf8591_init_client(struct i2c_client *client) | |||
249 | data->aout = PCF8591_INIT_AOUT; | 249 | data->aout = PCF8591_INIT_AOUT; |
250 | 250 | ||
251 | i2c_smbus_write_byte_data(client, data->control, data->aout); | 251 | i2c_smbus_write_byte_data(client, data->control, data->aout); |
252 | 252 | ||
253 | /* The first byte transmitted contains the conversion code of the | 253 | /* The first byte transmitted contains the conversion code of the |
254 | previous read cycle. FLUSH IT! */ | 254 | previous read cycle. FLUSH IT! */ |
255 | i2c_smbus_read_byte(client); | 255 | i2c_smbus_read_byte(client); |
256 | } | 256 | } |
@@ -267,8 +267,8 @@ static int pcf8591_read_channel(struct device *dev, int channel) | |||
267 | data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) | 267 | data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK) |
268 | | channel; | 268 | | channel; |
269 | i2c_smbus_write_byte(client, data->control); | 269 | i2c_smbus_write_byte(client, data->control); |
270 | 270 | ||
271 | /* The first byte transmitted contains the conversion code of | 271 | /* The first byte transmitted contains the conversion code of |
272 | the previous read cycle. FLUSH IT! */ | 272 | the previous read cycle. FLUSH IT! */ |
273 | i2c_smbus_read_byte(client); | 273 | i2c_smbus_read_byte(client); |
274 | } | 274 | } |
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index feae743ba991..e64b42058b21 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -36,6 +36,7 @@ | |||
36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 | 36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 |
37 | 0x8860 0xa1 | 37 | 0x8860 0xa1 |
38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 | 38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 |
39 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 | ||
39 | */ | 40 | */ |
40 | 41 | ||
41 | #include <linux/module.h> | 42 | #include <linux/module.h> |
@@ -52,12 +53,13 @@ | |||
52 | #include <asm/io.h> | 53 | #include <asm/io.h> |
53 | #include "lm75.h" | 54 | #include "lm75.h" |
54 | 55 | ||
55 | enum kinds { w83627ehf, w83627dhg }; | 56 | enum kinds { w83627ehf, w83627dhg, w83667hg }; |
56 | 57 | ||
57 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ | 58 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ |
58 | static const char * w83627ehf_device_names[] = { | 59 | static const char * w83627ehf_device_names[] = { |
59 | "w83627ehf", | 60 | "w83627ehf", |
60 | "w83627dhg", | 61 | "w83627dhg", |
62 | "w83667hg", | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | static unsigned short force_id; | 65 | static unsigned short force_id; |
@@ -71,6 +73,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
71 | */ | 73 | */ |
72 | 74 | ||
73 | #define W83627EHF_LD_HWM 0x0b | 75 | #define W83627EHF_LD_HWM 0x0b |
76 | #define W83667HG_LD_VID 0x0d | ||
74 | 77 | ||
75 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ | 78 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ |
76 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | 79 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ |
@@ -83,6 +86,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
83 | #define SIO_W83627EHF_ID 0x8850 | 86 | #define SIO_W83627EHF_ID 0x8850 |
84 | #define SIO_W83627EHG_ID 0x8860 | 87 | #define SIO_W83627EHG_ID 0x8860 |
85 | #define SIO_W83627DHG_ID 0xa020 | 88 | #define SIO_W83627DHG_ID 0xa020 |
89 | #define SIO_W83667HG_ID 0xa510 | ||
86 | #define SIO_ID_MASK 0xFFF0 | 90 | #define SIO_ID_MASK 0xFFF0 |
87 | 91 | ||
88 | static inline void | 92 | static inline void |
@@ -289,6 +293,7 @@ struct w83627ehf_data { | |||
289 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | 293 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ |
290 | u8 pwm_enable[4]; /* 1->manual | 294 | u8 pwm_enable[4]; /* 1->manual |
291 | 2->thermal cruise (also called SmartFan I) */ | 295 | 2->thermal cruise (also called SmartFan I) */ |
296 | u8 pwm_num; /* number of pwm */ | ||
292 | u8 pwm[4]; | 297 | u8 pwm[4]; |
293 | u8 target_temp[4]; | 298 | u8 target_temp[4]; |
294 | u8 tolerance[4]; | 299 | u8 tolerance[4]; |
@@ -298,6 +303,9 @@ struct w83627ehf_data { | |||
298 | 303 | ||
299 | u8 vid; | 304 | u8 vid; |
300 | u8 vrm; | 305 | u8 vrm; |
306 | |||
307 | u8 temp3_disable; | ||
308 | u8 in6_skip; | ||
301 | }; | 309 | }; |
302 | 310 | ||
303 | struct w83627ehf_sio_data { | 311 | struct w83627ehf_sio_data { |
@@ -866,25 +874,37 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf) | |||
866 | return sprintf(buf, "%d\n", (int)data->temp_type[nr]); | 874 | return sprintf(buf, "%d\n", (int)data->temp_type[nr]); |
867 | } | 875 | } |
868 | 876 | ||
869 | static struct sensor_device_attribute sda_temp[] = { | 877 | static struct sensor_device_attribute sda_temp_input[] = { |
870 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), | 878 | SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0), |
871 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), | 879 | SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0), |
872 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), | 880 | SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 1), |
881 | }; | ||
882 | |||
883 | static struct sensor_device_attribute sda_temp_max[] = { | ||
873 | SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, | 884 | SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp1_max, |
874 | store_temp1_max, 0), | 885 | store_temp1_max, 0), |
875 | SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, | 886 | SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max, |
876 | store_temp_max, 0), | 887 | store_temp_max, 0), |
877 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, | 888 | SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max, |
878 | store_temp_max, 1), | 889 | store_temp_max, 1), |
890 | }; | ||
891 | |||
892 | static struct sensor_device_attribute sda_temp_max_hyst[] = { | ||
879 | SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, | 893 | SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1_max_hyst, |
880 | store_temp1_max_hyst, 0), | 894 | store_temp1_max_hyst, 0), |
881 | SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 895 | SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
882 | store_temp_max_hyst, 0), | 896 | store_temp_max_hyst, 0), |
883 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, | 897 | SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst, |
884 | store_temp_max_hyst, 1), | 898 | store_temp_max_hyst, 1), |
899 | }; | ||
900 | |||
901 | static struct sensor_device_attribute sda_temp_alarm[] = { | ||
885 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), | 902 | SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4), |
886 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), | 903 | SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5), |
887 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), | 904 | SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13), |
905 | }; | ||
906 | |||
907 | static struct sensor_device_attribute sda_temp_type[] = { | ||
888 | SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), | 908 | SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0), |
889 | SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), | 909 | SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1), |
890 | SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), | 910 | SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2), |
@@ -1181,6 +1201,8 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1181 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) | 1201 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) |
1182 | device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); | 1202 | device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr); |
1183 | for (i = 0; i < data->in_num; i++) { | 1203 | for (i = 0; i < data->in_num; i++) { |
1204 | if ((i == 6) && data->in6_skip) | ||
1205 | continue; | ||
1184 | device_remove_file(dev, &sda_in_input[i].dev_attr); | 1206 | device_remove_file(dev, &sda_in_input[i].dev_attr); |
1185 | device_remove_file(dev, &sda_in_alarm[i].dev_attr); | 1207 | device_remove_file(dev, &sda_in_alarm[i].dev_attr); |
1186 | device_remove_file(dev, &sda_in_min[i].dev_attr); | 1208 | device_remove_file(dev, &sda_in_min[i].dev_attr); |
@@ -1192,15 +1214,22 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1192 | device_remove_file(dev, &sda_fan_div[i].dev_attr); | 1214 | device_remove_file(dev, &sda_fan_div[i].dev_attr); |
1193 | device_remove_file(dev, &sda_fan_min[i].dev_attr); | 1215 | device_remove_file(dev, &sda_fan_min[i].dev_attr); |
1194 | } | 1216 | } |
1195 | for (i = 0; i < 4; i++) { | 1217 | for (i = 0; i < data->pwm_num; i++) { |
1196 | device_remove_file(dev, &sda_pwm[i].dev_attr); | 1218 | device_remove_file(dev, &sda_pwm[i].dev_attr); |
1197 | device_remove_file(dev, &sda_pwm_mode[i].dev_attr); | 1219 | device_remove_file(dev, &sda_pwm_mode[i].dev_attr); |
1198 | device_remove_file(dev, &sda_pwm_enable[i].dev_attr); | 1220 | device_remove_file(dev, &sda_pwm_enable[i].dev_attr); |
1199 | device_remove_file(dev, &sda_target_temp[i].dev_attr); | 1221 | device_remove_file(dev, &sda_target_temp[i].dev_attr); |
1200 | device_remove_file(dev, &sda_tolerance[i].dev_attr); | 1222 | device_remove_file(dev, &sda_tolerance[i].dev_attr); |
1201 | } | 1223 | } |
1202 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) | 1224 | for (i = 0; i < 3; i++) { |
1203 | device_remove_file(dev, &sda_temp[i].dev_attr); | 1225 | if ((i == 2) && data->temp3_disable) |
1226 | continue; | ||
1227 | device_remove_file(dev, &sda_temp_input[i].dev_attr); | ||
1228 | device_remove_file(dev, &sda_temp_max[i].dev_attr); | ||
1229 | device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr); | ||
1230 | device_remove_file(dev, &sda_temp_alarm[i].dev_attr); | ||
1231 | device_remove_file(dev, &sda_temp_type[i].dev_attr); | ||
1232 | } | ||
1204 | 1233 | ||
1205 | device_remove_file(dev, &dev_attr_name); | 1234 | device_remove_file(dev, &dev_attr_name); |
1206 | device_remove_file(dev, &dev_attr_cpu0_vid); | 1235 | device_remove_file(dev, &dev_attr_cpu0_vid); |
@@ -1222,6 +1251,8 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data) | |||
1222 | for (i = 0; i < 2; i++) { | 1251 | for (i = 0; i < 2; i++) { |
1223 | tmp = w83627ehf_read_value(data, | 1252 | tmp = w83627ehf_read_value(data, |
1224 | W83627EHF_REG_TEMP_CONFIG[i]); | 1253 | W83627EHF_REG_TEMP_CONFIG[i]); |
1254 | if ((i == 1) && data->temp3_disable) | ||
1255 | continue; | ||
1225 | if (tmp & 0x01) | 1256 | if (tmp & 0x01) |
1226 | w83627ehf_write_value(data, | 1257 | w83627ehf_write_value(data, |
1227 | W83627EHF_REG_TEMP_CONFIG[i], | 1258 | W83627EHF_REG_TEMP_CONFIG[i], |
@@ -1272,8 +1303,17 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1272 | data->name = w83627ehf_device_names[sio_data->kind]; | 1303 | data->name = w83627ehf_device_names[sio_data->kind]; |
1273 | platform_set_drvdata(pdev, data); | 1304 | platform_set_drvdata(pdev, data); |
1274 | 1305 | ||
1275 | /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */ | 1306 | /* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */ |
1276 | data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10; | 1307 | data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9; |
1308 | /* 667HG has 3 pwms */ | ||
1309 | data->pwm_num = (sio_data->kind == w83667hg) ? 3 : 4; | ||
1310 | |||
1311 | /* Check temp3 configuration bit for 667HG */ | ||
1312 | if (sio_data->kind == w83667hg) { | ||
1313 | data->temp3_disable = w83627ehf_read_value(data, | ||
1314 | W83627EHF_REG_TEMP_CONFIG[1]) & 0x01; | ||
1315 | data->in6_skip = !data->temp3_disable; | ||
1316 | } | ||
1277 | 1317 | ||
1278 | /* Initialize the chip */ | 1318 | /* Initialize the chip */ |
1279 | w83627ehf_init_device(data); | 1319 | w83627ehf_init_device(data); |
@@ -1281,44 +1321,64 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1281 | data->vrm = vid_which_vrm(); | 1321 | data->vrm = vid_which_vrm(); |
1282 | superio_enter(sio_data->sioreg); | 1322 | superio_enter(sio_data->sioreg); |
1283 | /* Read VID value */ | 1323 | /* Read VID value */ |
1284 | superio_select(sio_data->sioreg, W83627EHF_LD_HWM); | 1324 | if (sio_data->kind == w83667hg) { |
1285 | if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { | 1325 | /* W83667HG has different pins for VID input and output, so |
1286 | /* Set VID input sensibility if needed. In theory the BIOS | 1326 | we can get the VID input values directly at logical device D |
1287 | should have set it, but in practice it's not always the | 1327 | 0xe3. */ |
1288 | case. We only do it for the W83627EHF/EHG because the | 1328 | superio_select(sio_data->sioreg, W83667HG_LD_VID); |
1289 | W83627DHG is more complex in this respect. */ | 1329 | data->vid = superio_inb(sio_data->sioreg, 0xe3); |
1290 | if (sio_data->kind == w83627ehf) { | ||
1291 | en_vrm10 = superio_inb(sio_data->sioreg, | ||
1292 | SIO_REG_EN_VRM10); | ||
1293 | if ((en_vrm10 & 0x08) && data->vrm == 90) { | ||
1294 | dev_warn(dev, "Setting VID input voltage to " | ||
1295 | "TTL\n"); | ||
1296 | superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, | ||
1297 | en_vrm10 & ~0x08); | ||
1298 | } else if (!(en_vrm10 & 0x08) && data->vrm == 100) { | ||
1299 | dev_warn(dev, "Setting VID input voltage to " | ||
1300 | "VRM10\n"); | ||
1301 | superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10, | ||
1302 | en_vrm10 | 0x08); | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA); | ||
1307 | if (sio_data->kind == w83627ehf) /* 6 VID pins only */ | ||
1308 | data->vid &= 0x3f; | ||
1309 | |||
1310 | err = device_create_file(dev, &dev_attr_cpu0_vid); | 1330 | err = device_create_file(dev, &dev_attr_cpu0_vid); |
1311 | if (err) | 1331 | if (err) |
1312 | goto exit_release; | 1332 | goto exit_release; |
1313 | } else { | 1333 | } else { |
1314 | dev_info(dev, "VID pins in output mode, CPU VID not " | 1334 | superio_select(sio_data->sioreg, W83627EHF_LD_HWM); |
1315 | "available\n"); | 1335 | if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) { |
1336 | /* Set VID input sensibility if needed. In theory the | ||
1337 | BIOS should have set it, but in practice it's not | ||
1338 | always the case. We only do it for the W83627EHF/EHG | ||
1339 | because the W83627DHG is more complex in this | ||
1340 | respect. */ | ||
1341 | if (sio_data->kind == w83627ehf) { | ||
1342 | en_vrm10 = superio_inb(sio_data->sioreg, | ||
1343 | SIO_REG_EN_VRM10); | ||
1344 | if ((en_vrm10 & 0x08) && data->vrm == 90) { | ||
1345 | dev_warn(dev, "Setting VID input " | ||
1346 | "voltage to TTL\n"); | ||
1347 | superio_outb(sio_data->sioreg, | ||
1348 | SIO_REG_EN_VRM10, | ||
1349 | en_vrm10 & ~0x08); | ||
1350 | } else if (!(en_vrm10 & 0x08) | ||
1351 | && data->vrm == 100) { | ||
1352 | dev_warn(dev, "Setting VID input " | ||
1353 | "voltage to VRM10\n"); | ||
1354 | superio_outb(sio_data->sioreg, | ||
1355 | SIO_REG_EN_VRM10, | ||
1356 | en_vrm10 | 0x08); | ||
1357 | } | ||
1358 | } | ||
1359 | |||
1360 | data->vid = superio_inb(sio_data->sioreg, | ||
1361 | SIO_REG_VID_DATA); | ||
1362 | if (sio_data->kind == w83627ehf) /* 6 VID pins only */ | ||
1363 | data->vid &= 0x3f; | ||
1364 | |||
1365 | err = device_create_file(dev, &dev_attr_cpu0_vid); | ||
1366 | if (err) | ||
1367 | goto exit_release; | ||
1368 | } else { | ||
1369 | dev_info(dev, "VID pins in output mode, CPU VID not " | ||
1370 | "available\n"); | ||
1371 | } | ||
1316 | } | 1372 | } |
1317 | 1373 | ||
1318 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | 1374 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ |
1319 | 1375 | if (sio_data->kind == w83667hg) { | |
1320 | fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2; | 1376 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; |
1321 | fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6; | 1377 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; |
1378 | } else { | ||
1379 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | ||
1380 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); | ||
1381 | } | ||
1322 | superio_exit(sio_data->sioreg); | 1382 | superio_exit(sio_data->sioreg); |
1323 | 1383 | ||
1324 | /* It looks like fan4 and fan5 pins can be alternatively used | 1384 | /* It looks like fan4 and fan5 pins can be alternatively used |
@@ -1329,9 +1389,9 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1329 | 1389 | ||
1330 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ | 1390 | data->has_fan = 0x07; /* fan1, fan2 and fan3 */ |
1331 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | 1391 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); |
1332 | if ((i & (1 << 2)) && (!fan4pin)) | 1392 | if ((i & (1 << 2)) && fan4pin) |
1333 | data->has_fan |= (1 << 3); | 1393 | data->has_fan |= (1 << 3); |
1334 | if (!(i & (1 << 1)) && (!fan5pin)) | 1394 | if (!(i & (1 << 1)) && fan5pin) |
1335 | data->has_fan |= (1 << 4); | 1395 | data->has_fan |= (1 << 4); |
1336 | 1396 | ||
1337 | /* Read fan clock dividers immediately */ | 1397 | /* Read fan clock dividers immediately */ |
@@ -1344,14 +1404,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1344 | goto exit_remove; | 1404 | goto exit_remove; |
1345 | 1405 | ||
1346 | /* if fan4 is enabled create the sf3 files for it */ | 1406 | /* if fan4 is enabled create the sf3 files for it */ |
1347 | if (data->has_fan & (1 << 3)) | 1407 | if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4) |
1348 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { | 1408 | for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) { |
1349 | if ((err = device_create_file(dev, | 1409 | if ((err = device_create_file(dev, |
1350 | &sda_sf3_arrays_fan4[i].dev_attr))) | 1410 | &sda_sf3_arrays_fan4[i].dev_attr))) |
1351 | goto exit_remove; | 1411 | goto exit_remove; |
1352 | } | 1412 | } |
1353 | 1413 | ||
1354 | for (i = 0; i < data->in_num; i++) | 1414 | for (i = 0; i < data->in_num; i++) { |
1415 | if ((i == 6) && data->in6_skip) | ||
1416 | continue; | ||
1355 | if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) | 1417 | if ((err = device_create_file(dev, &sda_in_input[i].dev_attr)) |
1356 | || (err = device_create_file(dev, | 1418 | || (err = device_create_file(dev, |
1357 | &sda_in_alarm[i].dev_attr)) | 1419 | &sda_in_alarm[i].dev_attr)) |
@@ -1360,6 +1422,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1360 | || (err = device_create_file(dev, | 1422 | || (err = device_create_file(dev, |
1361 | &sda_in_max[i].dev_attr))) | 1423 | &sda_in_max[i].dev_attr))) |
1362 | goto exit_remove; | 1424 | goto exit_remove; |
1425 | } | ||
1363 | 1426 | ||
1364 | for (i = 0; i < 5; i++) { | 1427 | for (i = 0; i < 5; i++) { |
1365 | if (data->has_fan & (1 << i)) { | 1428 | if (data->has_fan & (1 << i)) { |
@@ -1372,7 +1435,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1372 | || (err = device_create_file(dev, | 1435 | || (err = device_create_file(dev, |
1373 | &sda_fan_min[i].dev_attr))) | 1436 | &sda_fan_min[i].dev_attr))) |
1374 | goto exit_remove; | 1437 | goto exit_remove; |
1375 | if (i < 4 && /* w83627ehf only has 4 pwm */ | 1438 | if (i < data->pwm_num && |
1376 | ((err = device_create_file(dev, | 1439 | ((err = device_create_file(dev, |
1377 | &sda_pwm[i].dev_attr)) | 1440 | &sda_pwm[i].dev_attr)) |
1378 | || (err = device_create_file(dev, | 1441 | || (err = device_create_file(dev, |
@@ -1387,9 +1450,21 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
1387 | } | 1450 | } |
1388 | } | 1451 | } |
1389 | 1452 | ||
1390 | for (i = 0; i < ARRAY_SIZE(sda_temp); i++) | 1453 | for (i = 0; i < 3; i++) { |
1391 | if ((err = device_create_file(dev, &sda_temp[i].dev_attr))) | 1454 | if ((i == 2) && data->temp3_disable) |
1455 | continue; | ||
1456 | if ((err = device_create_file(dev, | ||
1457 | &sda_temp_input[i].dev_attr)) | ||
1458 | || (err = device_create_file(dev, | ||
1459 | &sda_temp_max[i].dev_attr)) | ||
1460 | || (err = device_create_file(dev, | ||
1461 | &sda_temp_max_hyst[i].dev_attr)) | ||
1462 | || (err = device_create_file(dev, | ||
1463 | &sda_temp_alarm[i].dev_attr)) | ||
1464 | || (err = device_create_file(dev, | ||
1465 | &sda_temp_type[i].dev_attr))) | ||
1392 | goto exit_remove; | 1466 | goto exit_remove; |
1467 | } | ||
1393 | 1468 | ||
1394 | err = device_create_file(dev, &dev_attr_name); | 1469 | err = device_create_file(dev, &dev_attr_name); |
1395 | if (err) | 1470 | if (err) |
@@ -1442,6 +1517,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1442 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; | 1517 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; |
1443 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; | 1518 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; |
1444 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; | 1519 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; |
1520 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; | ||
1445 | 1521 | ||
1446 | u16 val; | 1522 | u16 val; |
1447 | const char *sio_name; | 1523 | const char *sio_name; |
@@ -1466,6 +1542,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1466 | sio_data->kind = w83627dhg; | 1542 | sio_data->kind = w83627dhg; |
1467 | sio_name = sio_name_W83627DHG; | 1543 | sio_name = sio_name_W83627DHG; |
1468 | break; | 1544 | break; |
1545 | case SIO_W83667HG_ID: | ||
1546 | sio_data->kind = w83667hg; | ||
1547 | sio_name = sio_name_W83667HG; | ||
1548 | break; | ||
1469 | default: | 1549 | default: |
1470 | if (val != 0xffff) | 1550 | if (val != 0xffff) |
1471 | pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", | 1551 | pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n", |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 230238df56c4..10411848fd70 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #include <linux/i2c.h> | 65 | #include <linux/i2c.h> |
66 | #include <linux/acpi.h> | 66 | #include <linux/acpi.h> |
67 | #include <linux/io.h> | 67 | #include <linux/io.h> |
68 | #include <linux/dmi.h> | ||
68 | 69 | ||
69 | /* I801 SMBus address offsets */ | 70 | /* I801 SMBus address offsets */ |
70 | #define SMBHSTSTS (0 + i801_smba) | 71 | #define SMBHSTSTS (0 + i801_smba) |
@@ -616,10 +617,81 @@ static void __init input_apanel_init(void) | |||
616 | static void __init input_apanel_init(void) {} | 617 | static void __init input_apanel_init(void) {} |
617 | #endif | 618 | #endif |
618 | 619 | ||
620 | #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE | ||
621 | struct dmi_onboard_device_info { | ||
622 | const char *name; | ||
623 | u8 type; | ||
624 | unsigned short i2c_addr; | ||
625 | const char *i2c_type; | ||
626 | }; | ||
627 | |||
628 | static struct dmi_onboard_device_info __devinitdata dmi_devices[] = { | ||
629 | { "Syleus", DMI_DEV_TYPE_OTHER, 0x73, "fscsyl" }, | ||
630 | { "Hermes", DMI_DEV_TYPE_OTHER, 0x73, "fscher" }, | ||
631 | { "Hades", DMI_DEV_TYPE_OTHER, 0x73, "fschds" }, | ||
632 | }; | ||
633 | |||
634 | static void __devinit dmi_check_onboard_device(u8 type, const char *name, | ||
635 | struct i2c_adapter *adap) | ||
636 | { | ||
637 | int i; | ||
638 | struct i2c_board_info info; | ||
639 | |||
640 | for (i = 0; i < ARRAY_SIZE(dmi_devices); i++) { | ||
641 | /* & ~0x80, ignore enabled/disabled bit */ | ||
642 | if ((type & ~0x80) != dmi_devices[i].type) | ||
643 | continue; | ||
644 | if (strcmp(name, dmi_devices[i].name)) | ||
645 | continue; | ||
646 | |||
647 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
648 | info.addr = dmi_devices[i].i2c_addr; | ||
649 | strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); | ||
650 | i2c_new_device(adap, &info); | ||
651 | break; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | /* We use our own function to check for onboard devices instead of | ||
656 | dmi_find_device() as some buggy BIOS's have the devices we are interested | ||
657 | in marked as disabled */ | ||
658 | static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm, | ||
659 | void *adap) | ||
660 | { | ||
661 | int i, count; | ||
662 | |||
663 | if (dm->type != 10) | ||
664 | return; | ||
665 | |||
666 | count = (dm->length - sizeof(struct dmi_header)) / 2; | ||
667 | for (i = 0; i < count; i++) { | ||
668 | const u8 *d = (char *)(dm + 1) + (i * 2); | ||
669 | const char *name = ((char *) dm) + dm->length; | ||
670 | u8 type = d[0]; | ||
671 | u8 s = d[1]; | ||
672 | |||
673 | if (!s) | ||
674 | continue; | ||
675 | s--; | ||
676 | while (s > 0 && name[0]) { | ||
677 | name += strlen(name) + 1; | ||
678 | s--; | ||
679 | } | ||
680 | if (name[0] == 0) /* Bogus string reference */ | ||
681 | continue; | ||
682 | |||
683 | dmi_check_onboard_device(type, name, adap); | ||
684 | } | ||
685 | } | ||
686 | #endif | ||
687 | |||
619 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) | 688 | static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id) |
620 | { | 689 | { |
621 | unsigned char temp; | 690 | unsigned char temp; |
622 | int err; | 691 | int err; |
692 | #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE | ||
693 | const char *vendor; | ||
694 | #endif | ||
623 | 695 | ||
624 | I801_dev = dev; | 696 | I801_dev = dev; |
625 | i801_features = 0; | 697 | i801_features = 0; |
@@ -712,6 +784,11 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id | |||
712 | i2c_new_device(&i801_adapter, &info); | 784 | i2c_new_device(&i801_adapter, &info); |
713 | } | 785 | } |
714 | #endif | 786 | #endif |
787 | #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE | ||
788 | vendor = dmi_get_system_info(DMI_BOARD_VENDOR); | ||
789 | if (vendor && !strcmp(vendor, "FUJITSU SIEMENS")) | ||
790 | dmi_walk(dmi_check_onboard_devices, &i801_adapter); | ||
791 | #endif | ||
715 | 792 | ||
716 | return 0; | 793 | return 0; |
717 | 794 | ||
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index c80312c1f382..8f8c81eb0aee 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig | |||
@@ -64,19 +64,6 @@ config SENSORS_PCA9539 | |||
64 | This driver is deprecated and will be dropped soon. Use | 64 | This driver is deprecated and will be dropped soon. Use |
65 | drivers/gpio/pca953x.c instead. | 65 | drivers/gpio/pca953x.c instead. |
66 | 66 | ||
67 | config SENSORS_PCF8591 | ||
68 | tristate "Philips PCF8591" | ||
69 | depends on EXPERIMENTAL | ||
70 | default n | ||
71 | help | ||
72 | If you say yes here you get support for Philips PCF8591 chips. | ||
73 | |||
74 | This driver can also be built as a module. If so, the module | ||
75 | will be called pcf8591. | ||
76 | |||
77 | These devices are hard to detect and rarely found on mainstream | ||
78 | hardware. If unsure, say N. | ||
79 | |||
80 | config SENSORS_MAX6875 | 67 | config SENSORS_MAX6875 |
81 | tristate "Maxim MAX6875 Power supply supervisor" | 68 | tristate "Maxim MAX6875 Power supply supervisor" |
82 | depends on EXPERIMENTAL | 69 | depends on EXPERIMENTAL |
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index d142f238a2de..55a376037183 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile | |||
@@ -15,7 +15,6 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o | |||
15 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o | 15 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o |
16 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o | 16 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o |
17 | obj-$(CONFIG_PCF8575) += pcf8575.o | 17 | obj-$(CONFIG_PCF8575) += pcf8575.o |
18 | obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o | ||
19 | obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o | 18 | obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o |
20 | 19 | ||
21 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) | 20 | ifeq ($(CONFIG_I2C_DEBUG_CHIP),y) |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 16e11c2ee19a..af9f43021172 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -103,7 +103,7 @@ static void parse_da_table(const struct dmi_header *dm) | |||
103 | da_num_tokens += tokens; | 103 | da_num_tokens += tokens; |
104 | } | 104 | } |
105 | 105 | ||
106 | static void find_tokens(const struct dmi_header *dm) | 106 | static void find_tokens(const struct dmi_header *dm, void *dummy) |
107 | { | 107 | { |
108 | switch (dm->type) { | 108 | switch (dm->type) { |
109 | case 0xd4: /* Indexed IO */ | 109 | case 0xd4: /* Indexed IO */ |
@@ -356,7 +356,7 @@ static int __init dell_init(void) | |||
356 | if (!dmi_check_system(dell_device_table)) | 356 | if (!dmi_check_system(dell_device_table)) |
357 | return -ENODEV; | 357 | return -ENODEV; |
358 | 358 | ||
359 | dmi_walk(find_tokens); | 359 | dmi_walk(find_tokens, NULL); |
360 | 360 | ||
361 | if (!da_tokens) { | 361 | if (!da_tokens) { |
362 | printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n"); | 362 | printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n"); |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 6cf155d6b350..3137361ccbfe 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -380,7 +380,7 @@ asm(".text \n\t" | |||
380 | * This function checks whether or not a SMBIOS/DMI record is | 380 | * This function checks whether or not a SMBIOS/DMI record is |
381 | * the 64bit CRU info or not | 381 | * the 64bit CRU info or not |
382 | */ | 382 | */ |
383 | static void __devinit dmi_find_cru(const struct dmi_header *dm) | 383 | static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy) |
384 | { | 384 | { |
385 | struct smbios_cru64_info *smbios_cru64_ptr; | 385 | struct smbios_cru64_info *smbios_cru64_ptr; |
386 | unsigned long cru_physical_address; | 386 | unsigned long cru_physical_address; |
@@ -403,7 +403,7 @@ static int __devinit detect_cru_service(void) | |||
403 | { | 403 | { |
404 | cru_rom_addr = NULL; | 404 | cru_rom_addr = NULL; |
405 | 405 | ||
406 | dmi_walk(dmi_find_cru); | 406 | dmi_walk(dmi_find_cru, NULL); |
407 | 407 | ||
408 | /* if cru_rom_addr has been set then we found a CRU service */ | 408 | /* if cru_rom_addr has been set then we found a CRU service */ |
409 | return ((cru_rom_addr != NULL) ? 0 : -ENODEV); | 409 | return ((cru_rom_addr != NULL) ? 0 : -ENODEV); |
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index d741b9ceb0e0..bb5489c82c99 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
@@ -47,7 +47,8 @@ extern int dmi_get_year(int field); | |||
47 | extern int dmi_name_in_vendors(const char *str); | 47 | extern int dmi_name_in_vendors(const char *str); |
48 | extern int dmi_name_in_serial(const char *str); | 48 | extern int dmi_name_in_serial(const char *str); |
49 | extern int dmi_available; | 49 | extern int dmi_available; |
50 | extern int dmi_walk(void (*decode)(const struct dmi_header *)); | 50 | extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
51 | void *private_data); | ||
51 | extern bool dmi_match(enum dmi_field f, const char *str); | 52 | extern bool dmi_match(enum dmi_field f, const char *str); |
52 | 53 | ||
53 | #else | 54 | #else |
@@ -61,8 +62,8 @@ static inline int dmi_get_year(int year) { return 0; } | |||
61 | static inline int dmi_name_in_vendors(const char *s) { return 0; } | 62 | static inline int dmi_name_in_vendors(const char *s) { return 0; } |
62 | static inline int dmi_name_in_serial(const char *s) { return 0; } | 63 | static inline int dmi_name_in_serial(const char *s) { return 0; } |
63 | #define dmi_available 0 | 64 | #define dmi_available 0 |
64 | static inline int dmi_walk(void (*decode)(const struct dmi_header *)) | 65 | static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
65 | { return -1; } | 66 | void *private_data) { return -1; } |
66 | static inline bool dmi_match(enum dmi_field f, const char *str) | 67 | static inline bool dmi_match(enum dmi_field f, const char *str) |
67 | { return false; } | 68 | { return false; } |
68 | static inline const struct dmi_system_id * | 69 | static inline const struct dmi_system_id * |