diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 08:52:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 08:52:52 -0400 |
commit | 3cb603284b3d256ae9ae9e65887cee8416bfef15 (patch) | |
tree | a7012e9ca585c4ada1ff8896de326f540b460f80 | |
parent | 2355e4290336fcda4b4a799448f745155a000226 (diff) | |
parent | c5794cfac09a585945e1632451900594db19393b (diff) |
Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging
* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (26 commits)
hwmon: (w83627ehf) Better fix for negative temperature values
hwmon: (w83627ehf) Uninline is_word_sized
hwmon: (lm75) Document why clones are not detected
hwmon: (w83627ehf) Move fan pins check to a separate function
hwmon: (w83627ehf) Skip reading unused voltage registers
hwmon: (lm75) Add support for Analog Devices ADT75
hwmon: (pmbus_core) Simplify sign extensions
hwmon: (pmbus) Add support for Lineage Power DC-DC converters
hwmon: (pmbus/ltc2978) Add support for LTC3880 to LTC2978 driver
hwmon: (pmbus/ltc2978) Explicit driver for LTC2978
hwmon: (pmbus) Add support for TEMP2 peak attributes
hwmon: AD7314 driver (ported from IIO)
hwmon: (pmbus) Add support for Intersil power management chips
hwmon: (pmbus) Always call _pmbus_read_byte in core driver
hwmon: (pmbus) Replace EINVAL return codes with more appropriate errors
hwmon: (pmbus) Provide more documentation
hwmon/f71882fg: Make the decision wether to register fan attr. per fan
hwmon/f71882fg: Add a f71882fg_create_fan_sysfs_files helper function
hwmon/f71882fg: Make all fan/pwm attr tables 2 dimensional
hwmon: (exynos4_tmu) Remove IRQF_DISABLED
...
30 files changed, 2755 insertions, 331 deletions
diff --git a/Documentation/hwmon/ad7314 b/Documentation/hwmon/ad7314 new file mode 100644 index 000000000000..1912549c7467 --- /dev/null +++ b/Documentation/hwmon/ad7314 | |||
@@ -0,0 +1,25 @@ | |||
1 | Kernel driver ad7314 | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Analog Devices AD7314 | ||
6 | Prefix: 'ad7314' | ||
7 | Datasheet: Publicly available at Analog Devices website. | ||
8 | * Analog Devices ADT7301 | ||
9 | Prefix: 'adt7301' | ||
10 | Datasheet: Publicly available at Analog Devices website. | ||
11 | * Analog Devices ADT7302 | ||
12 | Prefix: 'adt7302' | ||
13 | Datasheet: Publicly available at Analog Devices website. | ||
14 | |||
15 | Description | ||
16 | ----------- | ||
17 | |||
18 | Driver supports the above parts. The ad7314 has a 10 bit | ||
19 | sensor with 1lsb = 0.25 degrees centigrade. The adt7301 and | ||
20 | adt7302 have 14 bit sensors with 1lsb = 0.03125 degrees centigrade. | ||
21 | |||
22 | Notes | ||
23 | ----- | ||
24 | |||
25 | Currently power down mode is not supported. | ||
diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275 index 097b3ccc4be7..ab70d96d2dfd 100644 --- a/Documentation/hwmon/adm1275 +++ b/Documentation/hwmon/adm1275 | |||
@@ -6,6 +6,10 @@ Supported chips: | |||
6 | Prefix: 'adm1275' | 6 | Prefix: 'adm1275' |
7 | Addresses scanned: - | 7 | Addresses scanned: - |
8 | Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf | 8 | Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf |
9 | * Analog Devices ADM1276 | ||
10 | Prefix: 'adm1276' | ||
11 | Addresses scanned: - | ||
12 | Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1276.pdf | ||
9 | 13 | ||
10 | Author: Guenter Roeck <guenter.roeck@ericsson.com> | 14 | Author: Guenter Roeck <guenter.roeck@ericsson.com> |
11 | 15 | ||
@@ -13,13 +17,13 @@ Author: Guenter Roeck <guenter.roeck@ericsson.com> | |||
13 | Description | 17 | Description |
14 | ----------- | 18 | ----------- |
15 | 19 | ||
16 | This driver supports hardware montoring for Analog Devices ADM1275 Hot-Swap | 20 | This driver supports hardware montoring for Analog Devices ADM1275 and ADM1276 |
17 | Controller and Digital Power Monitor. | 21 | Hot-Swap Controller and Digital Power Monitor. |
18 | 22 | ||
19 | The ADM1275 is a hot-swap controller that allows a circuit board to be removed | 23 | ADM1275 and ADM1276 are hot-swap controllers that allow a circuit board to be |
20 | from or inserted into a live backplane. It also features current and voltage | 24 | removed from or inserted into a live backplane. They also feature current and |
21 | readback via an integrated 12-bit analog-to-digital converter (ADC), accessed | 25 | voltage readback via an integrated 12-bit analog-to-digital converter (ADC), |
22 | using a PMBus. interface. | 26 | accessed using a PMBus interface. |
23 | 27 | ||
24 | The driver is a client driver to the core PMBus driver. Please see | 28 | The driver is a client driver to the core PMBus driver. Please see |
25 | Documentation/hwmon/pmbus for details on PMBus client drivers. | 29 | Documentation/hwmon/pmbus for details on PMBus client drivers. |
@@ -48,17 +52,25 @@ attributes are write-only, all other attributes are read-only. | |||
48 | 52 | ||
49 | in1_label "vin1" or "vout1" depending on chip variant and | 53 | in1_label "vin1" or "vout1" depending on chip variant and |
50 | configuration. | 54 | configuration. |
51 | in1_input Measured voltage. From READ_VOUT register. | 55 | in1_input Measured voltage. |
52 | in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register. | 56 | in1_min Minumum Voltage. |
53 | in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register. | 57 | in1_max Maximum voltage. |
54 | in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status. | 58 | in1_min_alarm Voltage low alarm. |
55 | in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status. | 59 | in1_max_alarm Voltage high alarm. |
56 | in1_highest Historical maximum voltage. | 60 | in1_highest Historical maximum voltage. |
57 | in1_reset_history Write any value to reset history. | 61 | in1_reset_history Write any value to reset history. |
58 | 62 | ||
59 | curr1_label "iout1" | 63 | curr1_label "iout1" |
60 | curr1_input Measured current. From READ_IOUT register. | 64 | curr1_input Measured current. |
61 | curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register. | 65 | curr1_max Maximum current. |
62 | curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register. | 66 | curr1_max_alarm Current high alarm. |
67 | curr1_lcrit Critical minimum current. Depending on the chip | ||
68 | configuration, either curr1_lcrit or curr1_crit is | ||
69 | supported, but not both. | ||
70 | curr1_lcrit_alarm Critical current low alarm. | ||
71 | curr1_crit Critical maximum current. Depending on the chip | ||
72 | configuration, either curr1_lcrit or curr1_crit is | ||
73 | supported, but not both. | ||
74 | curr1_crit_alarm Critical current high alarm. | ||
63 | curr1_highest Historical maximum current. | 75 | curr1_highest Historical maximum current. |
64 | curr1_reset_history Write any value to reset history. | 76 | curr1_reset_history Write any value to reset history. |
diff --git a/Documentation/hwmon/exynos4_tmu b/Documentation/hwmon/exynos4_tmu new file mode 100644 index 000000000000..c3c6b41db607 --- /dev/null +++ b/Documentation/hwmon/exynos4_tmu | |||
@@ -0,0 +1,81 @@ | |||
1 | Kernel driver exynos4_tmu | ||
2 | ================= | ||
3 | |||
4 | Supported chips: | ||
5 | * ARM SAMSUNG EXYNOS4 series of SoC | ||
6 | Prefix: 'exynos4-tmu' | ||
7 | Datasheet: Not publicly available | ||
8 | |||
9 | Authors: Donggeun Kim <dg77.kim@samsung.com> | ||
10 | |||
11 | Description | ||
12 | ----------- | ||
13 | |||
14 | This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC. | ||
15 | |||
16 | The chip only exposes the measured 8-bit temperature code value | ||
17 | through a register. | ||
18 | Temperature can be taken from the temperature code. | ||
19 | There are three equations converting from temperature to temperature code. | ||
20 | |||
21 | The three equations are: | ||
22 | 1. Two point trimming | ||
23 | Tc = (T - 25) * (TI2 - TI1) / (85 - 25) + TI1 | ||
24 | |||
25 | 2. One point trimming | ||
26 | Tc = T + TI1 - 25 | ||
27 | |||
28 | 3. No trimming | ||
29 | Tc = T + 50 | ||
30 | |||
31 | Tc: Temperature code, T: Temperature, | ||
32 | TI1: Trimming info for 25 degree Celsius (stored at TRIMINFO register) | ||
33 | Temperature code measured at 25 degree Celsius which is unchanged | ||
34 | TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register) | ||
35 | Temperature code measured at 85 degree Celsius which is unchanged | ||
36 | |||
37 | TMU(Thermal Management Unit) in EXYNOS4 generates interrupt | ||
38 | when temperature exceeds pre-defined levels. | ||
39 | The maximum number of configurable threshold is four. | ||
40 | The threshold levels are defined as follows: | ||
41 | Level_0: current temperature > trigger_level_0 + threshold | ||
42 | Level_1: current temperature > trigger_level_1 + threshold | ||
43 | Level_2: current temperature > trigger_level_2 + threshold | ||
44 | Level_3: current temperature > trigger_level_3 + threshold | ||
45 | |||
46 | The threshold and each trigger_level are set | ||
47 | through the corresponding registers. | ||
48 | |||
49 | When an interrupt occurs, this driver notify user space of | ||
50 | one of four threshold levels for the interrupt | ||
51 | through kobject_uevent_env and sysfs_notify functions. | ||
52 | Although an interrupt condition for level_0 can be set, | ||
53 | it is not notified to user space through sysfs_notify function. | ||
54 | |||
55 | Sysfs Interface | ||
56 | --------------- | ||
57 | name name of the temperature sensor | ||
58 | RO | ||
59 | |||
60 | temp1_input temperature | ||
61 | RO | ||
62 | |||
63 | temp1_max temperature for level_1 interrupt | ||
64 | RO | ||
65 | |||
66 | temp1_crit temperature for level_2 interrupt | ||
67 | RO | ||
68 | |||
69 | temp1_emergency temperature for level_3 interrupt | ||
70 | RO | ||
71 | |||
72 | temp1_max_alarm alarm for level_1 interrupt | ||
73 | RO | ||
74 | |||
75 | temp1_crit_alarm | ||
76 | alarm for level_2 interrupt | ||
77 | RO | ||
78 | |||
79 | temp1_emergency_alarm | ||
80 | alarm for level_3 interrupt | ||
81 | RO | ||
diff --git a/Documentation/hwmon/lm75 b/Documentation/hwmon/lm75 index a1790401fdde..c91a1d15fa28 100644 --- a/Documentation/hwmon/lm75 +++ b/Documentation/hwmon/lm75 | |||
@@ -12,26 +12,46 @@ Supported chips: | |||
12 | Addresses scanned: I2C 0x48 - 0x4f | 12 | Addresses scanned: I2C 0x48 - 0x4f |
13 | Datasheet: Publicly available at the National Semiconductor website | 13 | Datasheet: Publicly available at the National Semiconductor website |
14 | http://www.national.com/ | 14 | http://www.national.com/ |
15 | * Dallas Semiconductor DS75 | 15 | * Dallas Semiconductor DS75, DS1775 |
16 | Prefix: 'lm75' | 16 | Prefixes: 'ds75', 'ds1775' |
17 | Addresses scanned: I2C 0x48 - 0x4f | 17 | Addresses scanned: none |
18 | Datasheet: Publicly available at the Dallas Semiconductor website | ||
19 | http://www.maxim-ic.com/ | ||
20 | * Dallas Semiconductor DS1775 | ||
21 | Prefix: 'lm75' | ||
22 | Addresses scanned: I2C 0x48 - 0x4f | ||
23 | Datasheet: Publicly available at the Dallas Semiconductor website | 18 | Datasheet: Publicly available at the Dallas Semiconductor website |
24 | http://www.maxim-ic.com/ | 19 | http://www.maxim-ic.com/ |
25 | * Maxim MAX6625, MAX6626 | 20 | * Maxim MAX6625, MAX6626 |
26 | Prefix: 'lm75' | 21 | Prefixes: 'max6625', 'max6626' |
27 | Addresses scanned: I2C 0x48 - 0x4b | 22 | Addresses scanned: none |
28 | Datasheet: Publicly available at the Maxim website | 23 | Datasheet: Publicly available at the Maxim website |
29 | http://www.maxim-ic.com/ | 24 | http://www.maxim-ic.com/ |
30 | * Microchip (TelCom) TCN75 | 25 | * Microchip (TelCom) TCN75 |
31 | Prefix: 'lm75' | 26 | Prefix: 'lm75' |
32 | Addresses scanned: I2C 0x48 - 0x4f | 27 | Addresses scanned: none |
28 | Datasheet: Publicly available at the Microchip website | ||
29 | http://www.microchip.com/ | ||
30 | * Microchip MCP9800, MCP9801, MCP9802, MCP9803 | ||
31 | Prefix: 'mcp980x' | ||
32 | Addresses scanned: none | ||
33 | Datasheet: Publicly available at the Microchip website | 33 | Datasheet: Publicly available at the Microchip website |
34 | http://www.microchip.com/ | 34 | http://www.microchip.com/ |
35 | * Analog Devices ADT75 | ||
36 | Prefix: 'adt75' | ||
37 | Addresses scanned: none | ||
38 | Datasheet: Publicly available at the Analog Devices website | ||
39 | http://www.analog.com/adt75 | ||
40 | * ST Microelectronics STDS75 | ||
41 | Prefix: 'stds75' | ||
42 | Addresses scanned: none | ||
43 | Datasheet: Publicly available at the ST website | ||
44 | http://www.st.com/internet/analog/product/121769.jsp | ||
45 | * Texas Instruments TMP100, TMP101, TMP105, TMP75, TMP175, TMP275 | ||
46 | Prefixes: 'tmp100', 'tmp101', 'tmp105', 'tmp175', 'tmp75', 'tmp275' | ||
47 | Addresses scanned: none | ||
48 | Datasheet: Publicly available at the Texas Instruments website | ||
49 | http://www.ti.com/product/tmp100 | ||
50 | http://www.ti.com/product/tmp101 | ||
51 | http://www.ti.com/product/tmp105 | ||
52 | http://www.ti.com/product/tmp75 | ||
53 | http://www.ti.com/product/tmp175 | ||
54 | http://www.ti.com/product/tmp275 | ||
35 | 55 | ||
36 | Author: Frodo Looijaard <frodol@dds.nl> | 56 | Author: Frodo Looijaard <frodol@dds.nl> |
37 | 57 | ||
@@ -50,21 +70,16 @@ range of -55 to +125 degrees. | |||
50 | The LM75 only updates its values each 1.5 seconds; reading it more often | 70 | The LM75 only updates its values each 1.5 seconds; reading it more often |
51 | will do no harm, but will return 'old' values. | 71 | will do no harm, but will return 'old' values. |
52 | 72 | ||
53 | The LM75 is usually used in combination with LM78-like chips, to measure | 73 | The original LM75 was typically used in combination with LM78-like chips |
54 | the temperature of the processor(s). | 74 | on PC motherboards, to measure the temperature of the processor(s). Clones |
55 | 75 | are now used in various embedded designs. | |
56 | The DS75, DS1775, MAX6625, and MAX6626 are supported as well. | ||
57 | They are not distinguished from an LM75. While most of these chips | ||
58 | have three additional bits of accuracy (12 vs. 9 for the LM75), | ||
59 | the additional bits are not supported. Not only that, but these chips will | ||
60 | not be detected if not in 9-bit precision mode (use the force parameter if | ||
61 | needed). | ||
62 | |||
63 | The TCN75 is supported as well, and is not distinguished from an LM75. | ||
64 | 76 | ||
65 | The LM75 is essentially an industry standard; there may be other | 77 | The LM75 is essentially an industry standard; there may be other |
66 | LM75 clones not listed here, with or without various enhancements, | 78 | LM75 clones not listed here, with or without various enhancements, |
67 | that are supported. | 79 | that are supported. The clones are not detected by the driver, unless |
80 | they reproduce the exact register tricks of the original LM75, and must | ||
81 | therefore be instantiated explicitly. The specific enhancements (such as | ||
82 | higher resolution) are not currently supported by the driver. | ||
68 | 83 | ||
69 | The LM77 is not supported, contrary to what we pretended for a long time. | 84 | The LM77 is not supported, contrary to what we pretended for a long time. |
70 | Both chips are simply not compatible, value encoding differs. | 85 | Both chips are simply not compatible, value encoding differs. |
diff --git a/Documentation/hwmon/ltc2978 b/Documentation/hwmon/ltc2978 new file mode 100644 index 000000000000..c365f9beb5dd --- /dev/null +++ b/Documentation/hwmon/ltc2978 | |||
@@ -0,0 +1,103 @@ | |||
1 | Kernel driver ltc2978 | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Linear Technology LTC2978 | ||
6 | Prefix: 'ltc2978' | ||
7 | Addresses scanned: - | ||
8 | Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf | ||
9 | * Linear Technology LTC3880 | ||
10 | Prefix: 'ltc3880' | ||
11 | Addresses scanned: - | ||
12 | Datasheet: http://cds.linear.com/docs/Datasheet/3880f.pdf | ||
13 | |||
14 | Author: Guenter Roeck <guenter.roeck@ericsson.com> | ||
15 | |||
16 | |||
17 | Description | ||
18 | ----------- | ||
19 | |||
20 | The LTC2978 is an octal power supply monitor, supervisor, sequencer and | ||
21 | margin controller. The LTC3880 is a dual, PolyPhase DC/DC synchronous | ||
22 | step-down switching regulator controller. | ||
23 | |||
24 | |||
25 | Usage Notes | ||
26 | ----------- | ||
27 | |||
28 | This driver does not probe for PMBus devices. You will have to instantiate | ||
29 | devices explicitly. | ||
30 | |||
31 | Example: the following commands will load the driver for an LTC2978 at address | ||
32 | 0x60 on I2C bus #1: | ||
33 | |||
34 | # modprobe ltc2978 | ||
35 | # echo ltc2978 0x60 > /sys/bus/i2c/devices/i2c-1/new_device | ||
36 | |||
37 | |||
38 | Sysfs attributes | ||
39 | ---------------- | ||
40 | |||
41 | in1_label "vin" | ||
42 | in1_input Measured input voltage. | ||
43 | in1_min Minimum input voltage. | ||
44 | in1_max Maximum input voltage. | ||
45 | in1_lcrit Critical minimum input voltage. | ||
46 | in1_crit Critical maximum input voltage. | ||
47 | in1_min_alarm Input voltage low alarm. | ||
48 | in1_max_alarm Input voltage high alarm. | ||
49 | in1_lcrit_alarm Input voltage critical low alarm. | ||
50 | in1_crit_alarm Input voltage critical high alarm. | ||
51 | in1_lowest Lowest input voltage. LTC2978 only. | ||
52 | in1_highest Highest input voltage. | ||
53 | in1_reset_history Reset history. Writing into this attribute will reset | ||
54 | history for all attributes. | ||
55 | |||
56 | in[2-9]_label "vout[1-8]". Channels 3 to 9 on LTC2978 only. | ||
57 | in[2-9]_input Measured output voltage. | ||
58 | in[2-9]_min Minimum output voltage. | ||
59 | in[2-9]_max Maximum output voltage. | ||
60 | in[2-9]_lcrit Critical minimum output voltage. | ||
61 | in[2-9]_crit Critical maximum output voltage. | ||
62 | in[2-9]_min_alarm Output voltage low alarm. | ||
63 | in[2-9]_max_alarm Output voltage high alarm. | ||
64 | in[2-9]_lcrit_alarm Output voltage critical low alarm. | ||
65 | in[2-9]_crit_alarm Output voltage critical high alarm. | ||
66 | in[2-9]_lowest Lowest output voltage. LTC2978 only. | ||
67 | in[2-9]_highest Lowest output voltage. | ||
68 | in[2-9]_reset_history Reset history. Writing into this attribute will reset | ||
69 | history for all attributes. | ||
70 | |||
71 | temp[1-3]_input Measured temperature. | ||
72 | On LTC2978, only one temperature measurement is | ||
73 | supported and reflects the internal temperature. | ||
74 | On LTC3880, temp1 and temp2 report external | ||
75 | temperatures, and temp3 reports the internal | ||
76 | temperature. | ||
77 | temp[1-3]_min Mimimum temperature. | ||
78 | temp[1-3]_max Maximum temperature. | ||
79 | temp[1-3]_lcrit Critical low temperature. | ||
80 | temp[1-3]_crit Critical high temperature. | ||
81 | temp[1-3]_min_alarm Chip temperature low alarm. | ||
82 | temp[1-3]_max_alarm Chip temperature high alarm. | ||
83 | temp[1-3]_lcrit_alarm Chip temperature critical low alarm. | ||
84 | temp[1-3]_crit_alarm Chip temperature critical high alarm. | ||
85 | temp[1-3]_lowest Lowest measured temperature. LTC2978 only. | ||
86 | temp[1-3]_highest Highest measured temperature. | ||
87 | temp[1-3]_reset_history Reset history. Writing into this attribute will reset | ||
88 | history for all attributes. | ||
89 | |||
90 | power[1-2]_label "pout[1-2]". LTC3880 only. | ||
91 | power[1-2]_input Measured power. | ||
92 | |||
93 | curr1_label "iin". LTC3880 only. | ||
94 | curr1_input Measured input current. | ||
95 | curr1_max Maximum input current. | ||
96 | curr1_max_alarm Input current high alarm. | ||
97 | |||
98 | curr[2-3]_label "iout[1-2]". LTC3880 only. | ||
99 | curr[2-3]_input Measured input current. | ||
100 | curr[2-3]_max Maximum input current. | ||
101 | curr[2-3]_crit Critical input current. | ||
102 | curr[2-3]_max_alarm Input current high alarm. | ||
103 | curr[2-3]_crit_alarm Input current critical high alarm. | ||
diff --git a/Documentation/hwmon/pmbus b/Documentation/hwmon/pmbus index c36c1c1a62bb..15ac911ce51b 100644 --- a/Documentation/hwmon/pmbus +++ b/Documentation/hwmon/pmbus | |||
@@ -8,11 +8,6 @@ Supported chips: | |||
8 | Addresses scanned: - | 8 | Addresses scanned: - |
9 | Datasheet: | 9 | Datasheet: |
10 | http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395 | 10 | http://archive.ericsson.net/service/internet/picov/get?DocNo=28701-EN/LZT146395 |
11 | * Linear Technology LTC2978 | ||
12 | Octal PMBus Power Supply Monitor and Controller | ||
13 | Prefix: 'ltc2978' | ||
14 | Addresses scanned: - | ||
15 | Datasheet: http://cds.linear.com/docs/Datasheet/2978fa.pdf | ||
16 | * ON Semiconductor ADP4000, NCP4200, NCP4208 | 11 | * ON Semiconductor ADP4000, NCP4200, NCP4208 |
17 | Prefixes: 'adp4000', 'ncp4200', 'ncp4208' | 12 | Prefixes: 'adp4000', 'ncp4200', 'ncp4208' |
18 | Addresses scanned: - | 13 | Addresses scanned: - |
@@ -20,6 +15,14 @@ Supported chips: | |||
20 | http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF | 15 | http://www.onsemi.com/pub_link/Collateral/ADP4000-D.PDF |
21 | http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF | 16 | http://www.onsemi.com/pub_link/Collateral/NCP4200-D.PDF |
22 | http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF | 17 | http://www.onsemi.com/pub_link/Collateral/JUNE%202009-%20REV.%200.PDF |
18 | * Lineage Power | ||
19 | Prefixes: 'pdt003', 'pdt006', 'pdt012', 'udt020' | ||
20 | Addresses scanned: - | ||
21 | Datasheets: | ||
22 | http://www.lineagepower.com/oem/pdf/PDT003A0X.pdf | ||
23 | http://www.lineagepower.com/oem/pdf/PDT006A0X.pdf | ||
24 | http://www.lineagepower.com/oem/pdf/PDT012A0X.pdf | ||
25 | http://www.lineagepower.com/oem/pdf/UDT020A0X.pdf | ||
23 | * Generic PMBus devices | 26 | * Generic PMBus devices |
24 | Prefix: 'pmbus' | 27 | Prefix: 'pmbus' |
25 | Addresses scanned: - | 28 | Addresses scanned: - |
diff --git a/Documentation/hwmon/pmbus-core b/Documentation/hwmon/pmbus-core new file mode 100644 index 000000000000..31e4720fed18 --- /dev/null +++ b/Documentation/hwmon/pmbus-core | |||
@@ -0,0 +1,283 @@ | |||
1 | PMBus core driver and internal API | ||
2 | ================================== | ||
3 | |||
4 | Introduction | ||
5 | ============ | ||
6 | |||
7 | [from pmbus.org] The Power Management Bus (PMBus) is an open standard | ||
8 | power-management protocol with a fully defined command language that facilitates | ||
9 | communication with power converters and other devices in a power system. The | ||
10 | protocol is implemented over the industry-standard SMBus serial interface and | ||
11 | enables programming, control, and real-time monitoring of compliant power | ||
12 | conversion products. This flexible and highly versatile standard allows for | ||
13 | communication between devices based on both analog and digital technologies, and | ||
14 | provides true interoperability which will reduce design complexity and shorten | ||
15 | time to market for power system designers. Pioneered by leading power supply and | ||
16 | semiconductor companies, this open power system standard is maintained and | ||
17 | promoted by the PMBus Implementers Forum (PMBus-IF), comprising 30+ adopters | ||
18 | with the objective to provide support to, and facilitate adoption among, users. | ||
19 | |||
20 | Unfortunately, while PMBus commands are standardized, there are no mandatory | ||
21 | commands, and manufacturers can add as many non-standard commands as they like. | ||
22 | Also, different PMBUs devices act differently if non-supported commands are | ||
23 | executed. Some devices return an error, some devices return 0xff or 0xffff and | ||
24 | set a status error flag, and some devices may simply hang up. | ||
25 | |||
26 | Despite all those difficulties, a generic PMBus device driver is still useful | ||
27 | and supported since kernel version 2.6.39. However, it was necessary to support | ||
28 | device specific extensions in addition to the core PMBus driver, since it is | ||
29 | simply unknown what new device specific functionality PMBus device developers | ||
30 | come up with next. | ||
31 | |||
32 | To make device specific extensions as scalable as possible, and to avoid having | ||
33 | to modify the core PMBus driver repeatedly for new devices, the PMBus driver was | ||
34 | split into core, generic, and device specific code. The core code (in | ||
35 | pmbus_core.c) provides generic functionality. The generic code (in pmbus.c) | ||
36 | provides support for generic PMBus devices. Device specific code is responsible | ||
37 | for device specific initialization and, if needed, maps device specific | ||
38 | functionality into generic functionality. This is to some degree comparable | ||
39 | to PCI code, where generic code is augmented as needed with quirks for all kinds | ||
40 | of devices. | ||
41 | |||
42 | PMBus device capabilities auto-detection | ||
43 | ======================================== | ||
44 | |||
45 | For generic PMBus devices, code in pmbus.c attempts to auto-detect all supported | ||
46 | PMBus commands. Auto-detection is somewhat limited, since there are simply too | ||
47 | many variables to consider. For example, it is almost impossible to autodetect | ||
48 | which PMBus commands are paged and which commands are replicated across all | ||
49 | pages (see the PMBus specification for details on multi-page PMBus devices). | ||
50 | |||
51 | For this reason, it often makes sense to provide a device specific driver if not | ||
52 | all commands can be auto-detected. The data structures in this driver can be | ||
53 | used to inform the core driver about functionality supported by individual | ||
54 | chips. | ||
55 | |||
56 | Some commands are always auto-detected. This applies to all limit commands | ||
57 | (lcrit, min, max, and crit attributes) as well as associated alarm attributes. | ||
58 | Limits and alarm attributes are auto-detected because there are simply too many | ||
59 | possible combinations to provide a manual configuration interface. | ||
60 | |||
61 | PMBus internal API | ||
62 | ================== | ||
63 | |||
64 | The API between core and device specific PMBus code is defined in | ||
65 | drivers/hwmon/pmbus/pmbus.h. In addition to the internal API, pmbus.h defines | ||
66 | standard PMBus commands and virtual PMBus commands. | ||
67 | |||
68 | Standard PMBus commands | ||
69 | ----------------------- | ||
70 | |||
71 | Standard PMBus commands (commands values 0x00 to 0xff) are defined in the PMBUs | ||
72 | specification. | ||
73 | |||
74 | Virtual PMBus commands | ||
75 | ---------------------- | ||
76 | |||
77 | Virtual PMBus commands are provided to enable support for non-standard | ||
78 | functionality which has been implemented by several chip vendors and is thus | ||
79 | desirable to support. | ||
80 | |||
81 | Virtual PMBus commands start with command value 0x100 and can thus easily be | ||
82 | distinguished from standard PMBus commands (which can not have values larger | ||
83 | than 0xff). Support for virtual PMBus commands is device specific and thus has | ||
84 | to be implemented in device specific code. | ||
85 | |||
86 | Virtual commands are named PMBUS_VIRT_xxx and start with PMBUS_VIRT_BASE. All | ||
87 | virtual commands are word sized. | ||
88 | |||
89 | There are currently two types of virtual commands. | ||
90 | |||
91 | - READ commands are read-only; writes are either ignored or return an error. | ||
92 | - RESET commands are read/write. Reading reset registers returns zero | ||
93 | (used for detection), writing any value causes the associated history to be | ||
94 | reset. | ||
95 | |||
96 | Virtual commands have to be handled in device specific driver code. Chip driver | ||
97 | code returns non-negative values if a virtual command is supported, or a | ||
98 | negative error code if not. The chip driver may return -ENODATA or any other | ||
99 | Linux error code in this case, though an error code other than -ENODATA is | ||
100 | handled more efficiently and thus preferred. Either case, the calling PMBus | ||
101 | core code will abort if the chip driver returns an error code when reading | ||
102 | or writing virtual registers (in other words, the PMBus core code will never | ||
103 | send a virtual command to a chip). | ||
104 | |||
105 | PMBus driver information | ||
106 | ------------------------ | ||
107 | |||
108 | PMBus driver information, defined in struct pmbus_driver_info, is the main means | ||
109 | for device specific drivers to pass information to the core PMBus driver. | ||
110 | Specifically, it provides the following information. | ||
111 | |||
112 | - For devices supporting its data in Direct Data Format, it provides coefficients | ||
113 | for converting register values into normalized data. This data is usually | ||
114 | provided by chip manufacturers in device datasheets. | ||
115 | - Supported chip functionality can be provided to the core driver. This may be | ||
116 | necessary for chips which react badly if non-supported commands are executed, | ||
117 | and/or to speed up device detection and initialization. | ||
118 | - Several function entry points are provided to support overriding and/or | ||
119 | augmenting generic command execution. This functionality can be used to map | ||
120 | non-standard PMBus commands to standard commands, or to augment standard | ||
121 | command return values with device specific information. | ||
122 | |||
123 | API functions | ||
124 | ------------- | ||
125 | |||
126 | Functions provided by chip driver | ||
127 | --------------------------------- | ||
128 | |||
129 | All functions return the command return value (read) or zero (write) if | ||
130 | successful. A return value of -ENODATA indicates that there is no manufacturer | ||
131 | specific command, but that a standard PMBus command may exist. Any other | ||
132 | negative return value indicates that the commands does not exist for this | ||
133 | chip, and that no attempt should be made to read or write the standard | ||
134 | command. | ||
135 | |||
136 | As mentioned above, an exception to this rule applies to virtual commands, | ||
137 | which _must_ be handled in driver specific code. See "Virtual PMBus Commands" | ||
138 | above for more details. | ||
139 | |||
140 | Command execution in the core PMBus driver code is as follows. | ||
141 | |||
142 | if (chip_access_function) { | ||
143 | status = chip_access_function(); | ||
144 | if (status != -ENODATA) | ||
145 | return status; | ||
146 | } | ||
147 | if (command >= PMBUS_VIRT_BASE) /* For word commands/registers only */ | ||
148 | return -EINVAL; | ||
149 | return generic_access(); | ||
150 | |||
151 | Chip drivers may provide pointers to the following functions in struct | ||
152 | pmbus_driver_info. All functions are optional. | ||
153 | |||
154 | int (*read_byte_data)(struct i2c_client *client, int page, int reg); | ||
155 | |||
156 | Read byte from page <page>, register <reg>. | ||
157 | <page> may be -1, which means "current page". | ||
158 | |||
159 | int (*read_word_data)(struct i2c_client *client, int page, int reg); | ||
160 | |||
161 | Read word from page <page>, register <reg>. | ||
162 | |||
163 | int (*write_word_data)(struct i2c_client *client, int page, int reg, | ||
164 | u16 word); | ||
165 | |||
166 | Write word to page <page>, register <reg>. | ||
167 | |||
168 | int (*write_byte)(struct i2c_client *client, int page, u8 value); | ||
169 | |||
170 | Write byte to page <page>, register <reg>. | ||
171 | <page> may be -1, which means "current page". | ||
172 | |||
173 | int (*identify)(struct i2c_client *client, struct pmbus_driver_info *info); | ||
174 | |||
175 | Determine supported PMBus functionality. This function is only necessary | ||
176 | if a chip driver supports multiple chips, and the chip functionality is not | ||
177 | pre-determined. It is currently only used by the generic pmbus driver | ||
178 | (pmbus.c). | ||
179 | |||
180 | Functions exported by core driver | ||
181 | --------------------------------- | ||
182 | |||
183 | Chip drivers are expected to use the following functions to read or write | ||
184 | PMBus registers. Chip drivers may also use direct I2C commands. If direct I2C | ||
185 | commands are used, the chip driver code must not directly modify the current | ||
186 | page, since the selected page is cached in the core driver and the core driver | ||
187 | will assume that it is selected. Using pmbus_set_page() to select a new page | ||
188 | is mandatory. | ||
189 | |||
190 | int pmbus_set_page(struct i2c_client *client, u8 page); | ||
191 | |||
192 | Set PMBus page register to <page> for subsequent commands. | ||
193 | |||
194 | int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); | ||
195 | |||
196 | Read word data from <page>, <reg>. Similar to i2c_smbus_read_word_data(), but | ||
197 | selects page first. | ||
198 | |||
199 | int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, | ||
200 | u16 word); | ||
201 | |||
202 | Write word data to <page>, <reg>. Similar to i2c_smbus_write_word_data(), but | ||
203 | selects page first. | ||
204 | |||
205 | int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg); | ||
206 | |||
207 | Read byte data from <page>, <reg>. Similar to i2c_smbus_read_byte_data(), but | ||
208 | selects page first. <page> may be -1, which means "current page". | ||
209 | |||
210 | int pmbus_write_byte(struct i2c_client *client, int page, u8 value); | ||
211 | |||
212 | Write byte data to <page>, <reg>. Similar to i2c_smbus_write_byte(), but | ||
213 | selects page first. <page> may be -1, which means "current page". | ||
214 | |||
215 | void pmbus_clear_faults(struct i2c_client *client); | ||
216 | |||
217 | Execute PMBus "Clear Fault" command on all chip pages. | ||
218 | This function calls the device specific write_byte function if defined. | ||
219 | Therefore, it must _not_ be called from that function. | ||
220 | |||
221 | bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); | ||
222 | |||
223 | Check if byte register exists. Return true if the register exists, false | ||
224 | otherwise. | ||
225 | This function calls the device specific write_byte function if defined to | ||
226 | obtain the chip status. Therefore, it must _not_ be called from that function. | ||
227 | |||
228 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); | ||
229 | |||
230 | Check if word register exists. Return true if the register exists, false | ||
231 | otherwise. | ||
232 | This function calls the device specific write_byte function if defined to | ||
233 | obtain the chip status. Therefore, it must _not_ be called from that function. | ||
234 | |||
235 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | ||
236 | struct pmbus_driver_info *info); | ||
237 | |||
238 | Execute probe function. Similar to standard probe function for other drivers, | ||
239 | with the pointer to struct pmbus_driver_info as additional argument. Calls | ||
240 | identify function if supported. Must only be called from device probe | ||
241 | function. | ||
242 | |||
243 | void pmbus_do_remove(struct i2c_client *client); | ||
244 | |||
245 | Execute driver remove function. Similar to standard driver remove function. | ||
246 | |||
247 | const struct pmbus_driver_info | ||
248 | *pmbus_get_driver_info(struct i2c_client *client); | ||
249 | |||
250 | Return pointer to struct pmbus_driver_info as passed to pmbus_do_probe(). | ||
251 | |||
252 | |||
253 | PMBus driver platform data | ||
254 | ========================== | ||
255 | |||
256 | PMBus platform data is defined in include/linux/i2c/pmbus.h. Platform data | ||
257 | currently only provides a flag field with a single bit used. | ||
258 | |||
259 | #define PMBUS_SKIP_STATUS_CHECK (1 << 0) | ||
260 | |||
261 | struct pmbus_platform_data { | ||
262 | u32 flags; /* Device specific flags */ | ||
263 | }; | ||
264 | |||
265 | |||
266 | Flags | ||
267 | ----- | ||
268 | |||
269 | PMBUS_SKIP_STATUS_CHECK | ||
270 | |||
271 | During register detection, skip checking the status register for | ||
272 | communication or command errors. | ||
273 | |||
274 | Some PMBus chips respond with valid data when trying to read an unsupported | ||
275 | register. For such chips, checking the status register is mandatory when | ||
276 | trying to determine if a chip register exists or not. | ||
277 | Other PMBus chips don't support the STATUS_CML register, or report | ||
278 | communication errors for no explicable reason. For such chips, checking the | ||
279 | status register must be disabled. | ||
280 | |||
281 | Some i2c controllers do not support single-byte commands (write commands with | ||
282 | no data, i2c_smbus_write_byte()). With such controllers, clearing the status | ||
283 | register is impossible, and the PMBUS_SKIP_STATUS_CHECK flag must be set. | ||
diff --git a/Documentation/hwmon/zl6100 b/Documentation/hwmon/zl6100 new file mode 100644 index 000000000000..7617798b5c97 --- /dev/null +++ b/Documentation/hwmon/zl6100 | |||
@@ -0,0 +1,125 @@ | |||
1 | Kernel driver zl6100 | ||
2 | ==================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Intersil / Zilker Labs ZL2004 | ||
6 | Prefix: 'zl2004' | ||
7 | Addresses scanned: - | ||
8 | Datasheet: http://www.intersil.com/data/fn/fn6847.pdf | ||
9 | * Intersil / Zilker Labs ZL2006 | ||
10 | Prefix: 'zl2006' | ||
11 | Addresses scanned: - | ||
12 | Datasheet: http://www.intersil.com/data/fn/fn6850.pdf | ||
13 | * Intersil / Zilker Labs ZL2008 | ||
14 | Prefix: 'zl2008' | ||
15 | Addresses scanned: - | ||
16 | Datasheet: http://www.intersil.com/data/fn/fn6859.pdf | ||
17 | * Intersil / Zilker Labs ZL2105 | ||
18 | Prefix: 'zl2105' | ||
19 | Addresses scanned: - | ||
20 | Datasheet: http://www.intersil.com/data/fn/fn6851.pdf | ||
21 | * Intersil / Zilker Labs ZL2106 | ||
22 | Prefix: 'zl2106' | ||
23 | Addresses scanned: - | ||
24 | Datasheet: http://www.intersil.com/data/fn/fn6852.pdf | ||
25 | * Intersil / Zilker Labs ZL6100 | ||
26 | Prefix: 'zl6100' | ||
27 | Addresses scanned: - | ||
28 | Datasheet: http://www.intersil.com/data/fn/fn6876.pdf | ||
29 | * Intersil / Zilker Labs ZL6105 | ||
30 | Prefix: 'zl6105' | ||
31 | Addresses scanned: - | ||
32 | Datasheet: http://www.intersil.com/data/fn/fn6906.pdf | ||
33 | |||
34 | Author: Guenter Roeck <guenter.roeck@ericsson.com> | ||
35 | |||
36 | |||
37 | Description | ||
38 | ----------- | ||
39 | |||
40 | This driver supports hardware montoring for Intersil / Zilker Labs ZL6100 and | ||
41 | compatible digital DC-DC controllers. | ||
42 | |||
43 | The driver is a client driver to the core PMBus driver. Please see | ||
44 | Documentation/hwmon/pmbus and Documentation.hwmon/pmbus-core for details | ||
45 | on PMBus client drivers. | ||
46 | |||
47 | |||
48 | Usage Notes | ||
49 | ----------- | ||
50 | |||
51 | This driver does not auto-detect devices. You will have to instantiate the | ||
52 | devices explicitly. Please see Documentation/i2c/instantiating-devices for | ||
53 | details. | ||
54 | |||
55 | WARNING: Do not access chip registers using the i2cdump command, and do not use | ||
56 | any of the i2ctools commands on a command register used to save and restore | ||
57 | configuration data (0x11, 0x12, 0x15, 0x16, and 0xf4). The chips supported by | ||
58 | this driver interpret any access to those command registers (including read | ||
59 | commands) as request to execute the command in question. Unless write accesses | ||
60 | to those registers are protected, this may result in power loss, board resets, | ||
61 | and/or Flash corruption. Worst case, your board may turn into a brick. | ||
62 | |||
63 | |||
64 | Platform data support | ||
65 | --------------------- | ||
66 | |||
67 | The driver supports standard PMBus driver platform data. | ||
68 | |||
69 | |||
70 | Module parameters | ||
71 | ----------------- | ||
72 | |||
73 | delay | ||
74 | ----- | ||
75 | |||
76 | Some Intersil/Zilker Labs DC-DC controllers require a minimum interval between | ||
77 | I2C bus accesses. According to Intersil, the minimum interval is 2 ms, though | ||
78 | 1 ms appears to be sufficient and has not caused any problems in testing. | ||
79 | The problem is known to affect ZL6100, ZL2105, and ZL2008. It is known not to | ||
80 | affect ZL2004 and ZL6105. The driver automatically sets the interval to 1 ms | ||
81 | except for ZL2004 and ZL6105. To enable manual override, the driver provides a | ||
82 | writeable module parameter, 'delay', which can be used to set the interval to | ||
83 | a value between 0 and 65,535 microseconds. | ||
84 | |||
85 | |||
86 | Sysfs entries | ||
87 | ------------- | ||
88 | |||
89 | The following attributes are supported. Limits are read-write; all other | ||
90 | attributes are read-only. | ||
91 | |||
92 | in1_label "vin" | ||
93 | in1_input Measured input voltage. | ||
94 | in1_min Minimum input voltage. | ||
95 | in1_max Maximum input voltage. | ||
96 | in1_lcrit Critical minumum input voltage. | ||
97 | in1_crit Critical maximum input voltage. | ||
98 | in1_min_alarm Input voltage low alarm. | ||
99 | in1_max_alarm Input voltage high alarm. | ||
100 | in1_lcrit_alarm Input voltage critical low alarm. | ||
101 | in1_crit_alarm Input voltage critical high alarm. | ||
102 | |||
103 | in2_label "vout1" | ||
104 | in2_input Measured output voltage. | ||
105 | in2_lcrit Critical minumum output Voltage. | ||
106 | in2_crit Critical maximum output voltage. | ||
107 | in2_lcrit_alarm Critical output voltage critical low alarm. | ||
108 | in2_crit_alarm Critical output voltage critical high alarm. | ||
109 | |||
110 | curr1_label "iout1" | ||
111 | curr1_input Measured output current. | ||
112 | curr1_lcrit Critical minimum output current. | ||
113 | curr1_crit Critical maximum output current. | ||
114 | curr1_lcrit_alarm Output current critical low alarm. | ||
115 | curr1_crit_alarm Output current critical high alarm. | ||
116 | |||
117 | temp[12]_input Measured temperature. | ||
118 | temp[12]_min Minimum temperature. | ||
119 | temp[12]_max Maximum temperature. | ||
120 | temp[12]_lcrit Critical low temperature. | ||
121 | temp[12]_crit Critical high temperature. | ||
122 | temp[12]_min_alarm Chip temperature low alarm. | ||
123 | temp[12]_max_alarm Chip temperature high alarm. | ||
124 | temp[12]_lcrit_alarm Chip temperature critical low alarm. | ||
125 | temp[12]_crit_alarm Chip temperature critical high alarm. | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 0b62c3c6b7ce..9b347acf1559 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -68,6 +68,16 @@ config SENSORS_ABITUGURU3 | |||
68 | This driver can also be built as a module. If so, the module | 68 | This driver can also be built as a module. If so, the module |
69 | will be called abituguru3. | 69 | will be called abituguru3. |
70 | 70 | ||
71 | config SENSORS_AD7314 | ||
72 | tristate "Analog Devices AD7314 and compatibles" | ||
73 | depends on SPI && EXPERIMENTAL | ||
74 | help | ||
75 | If you say yes here you get support for the Analog Devices | ||
76 | AD7314, ADT7301 and ADT7302 temperature sensors. | ||
77 | |||
78 | This driver can also be built as a module. If so, the module | ||
79 | will be called ad7314. | ||
80 | |||
71 | config SENSORS_AD7414 | 81 | config SENSORS_AD7414 |
72 | tristate "Analog Devices AD7414" | 82 | tristate "Analog Devices AD7414" |
73 | depends on I2C && EXPERIMENTAL | 83 | depends on I2C && EXPERIMENTAL |
@@ -303,6 +313,16 @@ config SENSORS_DS1621 | |||
303 | This driver can also be built as a module. If so, the module | 313 | This driver can also be built as a module. If so, the module |
304 | will be called ds1621. | 314 | will be called ds1621. |
305 | 315 | ||
316 | config SENSORS_EXYNOS4_TMU | ||
317 | tristate "Temperature sensor on Samsung EXYNOS4" | ||
318 | depends on EXYNOS4_DEV_TMU | ||
319 | help | ||
320 | If you say yes here you get support for TMU (Thermal Managment | ||
321 | Unit) on SAMSUNG EXYNOS4 series of SoC. | ||
322 | |||
323 | This driver can also be built as a module. If so, the module | ||
324 | will be called exynos4-tmu. | ||
325 | |||
306 | config SENSORS_I5K_AMB | 326 | config SENSORS_I5K_AMB |
307 | tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets" | 327 | tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets" |
308 | depends on PCI && EXPERIMENTAL | 328 | depends on PCI && EXPERIMENTAL |
@@ -531,6 +551,7 @@ config SENSORS_LM75 | |||
531 | If you say yes here you get support for one common type of | 551 | If you say yes here you get support for one common type of |
532 | temperature sensor chip, with models including: | 552 | temperature sensor chip, with models including: |
533 | 553 | ||
554 | - Analog Devices ADT75 | ||
534 | - Dallas Semiconductor DS75 and DS1775 | 555 | - Dallas Semiconductor DS75 and DS1775 |
535 | - Maxim MAX6625 and MAX6626 | 556 | - Maxim MAX6625 and MAX6626 |
536 | - Microchip MCP980x | 557 | - Microchip MCP980x |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 3c9ccefea791..8251ce8cd035 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o | |||
21 | 21 | ||
22 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o | 22 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o |
23 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o | 23 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o |
24 | obj-$(CONFIG_SENSORS_AD7314) += ad7314.o | ||
24 | obj-$(CONFIG_SENSORS_AD7414) += ad7414.o | 25 | obj-$(CONFIG_SENSORS_AD7414) += ad7414.o |
25 | obj-$(CONFIG_SENSORS_AD7418) += ad7418.o | 26 | obj-$(CONFIG_SENSORS_AD7418) += ad7418.o |
26 | obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o | 27 | obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o |
@@ -47,6 +48,7 @@ obj-$(CONFIG_SENSORS_DS1621) += ds1621.o | |||
47 | obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o | 48 | obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o |
48 | obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o | 49 | obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o |
49 | obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o | 50 | obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o |
51 | obj-$(CONFIG_SENSORS_EXYNOS4_TMU) += exynos4_tmu.o | ||
50 | obj-$(CONFIG_SENSORS_F71805F) += f71805f.o | 52 | obj-$(CONFIG_SENSORS_F71805F) += f71805f.o |
51 | obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o | 53 | obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o |
52 | obj-$(CONFIG_SENSORS_F75375S) += f75375s.o | 54 | obj-$(CONFIG_SENSORS_F75375S) += f75375s.o |
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c new file mode 100644 index 000000000000..318e38e85376 --- /dev/null +++ b/drivers/hwmon/ad7314.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 | ||
3 | * | ||
4 | * Copyright 2010 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | * | ||
8 | * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk> | ||
9 | */ | ||
10 | #include <linux/device.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/slab.h> | ||
13 | #include <linux/sysfs.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/hwmon.h> | ||
18 | #include <linux/hwmon-sysfs.h> | ||
19 | |||
20 | /* | ||
21 | * AD7314 power mode | ||
22 | */ | ||
23 | #define AD7314_PD 0x2000 | ||
24 | |||
25 | /* | ||
26 | * AD7314 temperature masks | ||
27 | */ | ||
28 | #define AD7314_TEMP_SIGN 0x200 | ||
29 | #define AD7314_TEMP_MASK 0x7FE0 | ||
30 | #define AD7314_TEMP_OFFSET 5 | ||
31 | |||
32 | /* | ||
33 | * ADT7301 and ADT7302 temperature masks | ||
34 | */ | ||
35 | #define ADT7301_TEMP_SIGN 0x2000 | ||
36 | #define ADT7301_TEMP_MASK 0x3FFF | ||
37 | |||
38 | enum ad7314_variant { | ||
39 | adt7301, | ||
40 | adt7302, | ||
41 | ad7314, | ||
42 | }; | ||
43 | |||
44 | struct ad7314_data { | ||
45 | struct spi_device *spi_dev; | ||
46 | struct device *hwmon_dev; | ||
47 | u16 rx ____cacheline_aligned; | ||
48 | }; | ||
49 | |||
50 | static int ad7314_spi_read(struct ad7314_data *chip, s16 *data) | ||
51 | { | ||
52 | int ret; | ||
53 | |||
54 | ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx)); | ||
55 | if (ret < 0) { | ||
56 | dev_err(&chip->spi_dev->dev, "SPI read error\n"); | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | *data = be16_to_cpu(chip->rx); | ||
61 | |||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static ssize_t ad7314_show_temperature(struct device *dev, | ||
66 | struct device_attribute *attr, | ||
67 | char *buf) | ||
68 | { | ||
69 | struct ad7314_data *chip = dev_get_drvdata(dev); | ||
70 | s16 data; | ||
71 | int ret; | ||
72 | |||
73 | ret = ad7314_spi_read(chip, &data); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | switch (spi_get_device_id(chip->spi_dev)->driver_data) { | ||
77 | case ad7314: | ||
78 | data = (data & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET; | ||
79 | data = (data << 6) >> 6; | ||
80 | |||
81 | return sprintf(buf, "%d\n", 250 * data); | ||
82 | case adt7301: | ||
83 | case adt7302: | ||
84 | /* | ||
85 | * Documented as a 13 bit twos complement register | ||
86 | * with a sign bit - which is a 14 bit 2's complement | ||
87 | * register. 1lsb - 31.25 milli degrees centigrade | ||
88 | */ | ||
89 | data &= ADT7301_TEMP_MASK; | ||
90 | data = (data << 2) >> 2; | ||
91 | |||
92 | return sprintf(buf, "%d\n", | ||
93 | DIV_ROUND_CLOSEST(data * 3125, 100)); | ||
94 | default: | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, | ||
100 | ad7314_show_temperature, NULL, 0); | ||
101 | |||
102 | static struct attribute *ad7314_attributes[] = { | ||
103 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
104 | NULL, | ||
105 | }; | ||
106 | |||
107 | static const struct attribute_group ad7314_group = { | ||
108 | .attrs = ad7314_attributes, | ||
109 | }; | ||
110 | |||
111 | static int __devinit ad7314_probe(struct spi_device *spi_dev) | ||
112 | { | ||
113 | int ret; | ||
114 | struct ad7314_data *chip; | ||
115 | |||
116 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
117 | if (chip == NULL) { | ||
118 | ret = -ENOMEM; | ||
119 | goto error_ret; | ||
120 | } | ||
121 | dev_set_drvdata(&spi_dev->dev, chip); | ||
122 | |||
123 | ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group); | ||
124 | if (ret < 0) | ||
125 | goto error_free_chip; | ||
126 | chip->hwmon_dev = hwmon_device_register(&spi_dev->dev); | ||
127 | if (IS_ERR(chip->hwmon_dev)) { | ||
128 | ret = PTR_ERR(chip->hwmon_dev); | ||
129 | goto error_remove_group; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | error_remove_group: | ||
134 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | ||
135 | error_free_chip: | ||
136 | kfree(chip); | ||
137 | error_ret: | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int __devexit ad7314_remove(struct spi_device *spi_dev) | ||
142 | { | ||
143 | struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); | ||
144 | |||
145 | hwmon_device_unregister(chip->hwmon_dev); | ||
146 | sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group); | ||
147 | kfree(chip); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static const struct spi_device_id ad7314_id[] = { | ||
153 | { "adt7301", adt7301 }, | ||
154 | { "adt7302", adt7302 }, | ||
155 | { "ad7314", ad7314 }, | ||
156 | { } | ||
157 | }; | ||
158 | MODULE_DEVICE_TABLE(spi, ad7314_id); | ||
159 | |||
160 | static struct spi_driver ad7314_driver = { | ||
161 | .driver = { | ||
162 | .name = "ad7314", | ||
163 | .bus = &spi_bus_type, | ||
164 | .owner = THIS_MODULE, | ||
165 | }, | ||
166 | .probe = ad7314_probe, | ||
167 | .remove = __devexit_p(ad7314_remove), | ||
168 | .id_table = ad7314_id, | ||
169 | }; | ||
170 | |||
171 | static __init int ad7314_init(void) | ||
172 | { | ||
173 | return spi_register_driver(&ad7314_driver); | ||
174 | } | ||
175 | module_init(ad7314_init); | ||
176 | |||
177 | static __exit void ad7314_exit(void) | ||
178 | { | ||
179 | spi_unregister_driver(&ad7314_driver); | ||
180 | } | ||
181 | module_exit(ad7314_exit); | ||
182 | |||
183 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | ||
184 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" | ||
185 | " temperature sensor driver"); | ||
186 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c new file mode 100644 index 000000000000..faa0884f61f6 --- /dev/null +++ b/drivers/hwmon/exynos4_tmu.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * exynos4_tmu.c - Samsung EXYNOS4 TMU (Thermal Management Unit) | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics | ||
5 | * Donggeun Kim <dg77.kim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/workqueue.h> | ||
31 | #include <linux/sysfs.h> | ||
32 | #include <linux/kobject.h> | ||
33 | #include <linux/io.h> | ||
34 | #include <linux/mutex.h> | ||
35 | |||
36 | #include <linux/hwmon.h> | ||
37 | #include <linux/hwmon-sysfs.h> | ||
38 | |||
39 | #include <linux/platform_data/exynos4_tmu.h> | ||
40 | |||
41 | #define EXYNOS4_TMU_REG_TRIMINFO 0x0 | ||
42 | #define EXYNOS4_TMU_REG_CONTROL 0x20 | ||
43 | #define EXYNOS4_TMU_REG_STATUS 0x28 | ||
44 | #define EXYNOS4_TMU_REG_CURRENT_TEMP 0x40 | ||
45 | #define EXYNOS4_TMU_REG_THRESHOLD_TEMP 0x44 | ||
46 | #define EXYNOS4_TMU_REG_TRIG_LEVEL0 0x50 | ||
47 | #define EXYNOS4_TMU_REG_TRIG_LEVEL1 0x54 | ||
48 | #define EXYNOS4_TMU_REG_TRIG_LEVEL2 0x58 | ||
49 | #define EXYNOS4_TMU_REG_TRIG_LEVEL3 0x5C | ||
50 | #define EXYNOS4_TMU_REG_PAST_TEMP0 0x60 | ||
51 | #define EXYNOS4_TMU_REG_PAST_TEMP1 0x64 | ||
52 | #define EXYNOS4_TMU_REG_PAST_TEMP2 0x68 | ||
53 | #define EXYNOS4_TMU_REG_PAST_TEMP3 0x6C | ||
54 | #define EXYNOS4_TMU_REG_INTEN 0x70 | ||
55 | #define EXYNOS4_TMU_REG_INTSTAT 0x74 | ||
56 | #define EXYNOS4_TMU_REG_INTCLEAR 0x78 | ||
57 | |||
58 | #define EXYNOS4_TMU_GAIN_SHIFT 8 | ||
59 | #define EXYNOS4_TMU_REF_VOLTAGE_SHIFT 24 | ||
60 | |||
61 | #define EXYNOS4_TMU_TRIM_TEMP_MASK 0xff | ||
62 | #define EXYNOS4_TMU_CORE_ON 3 | ||
63 | #define EXYNOS4_TMU_CORE_OFF 2 | ||
64 | #define EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET 50 | ||
65 | #define EXYNOS4_TMU_TRIG_LEVEL0_MASK 0x1 | ||
66 | #define EXYNOS4_TMU_TRIG_LEVEL1_MASK 0x10 | ||
67 | #define EXYNOS4_TMU_TRIG_LEVEL2_MASK 0x100 | ||
68 | #define EXYNOS4_TMU_TRIG_LEVEL3_MASK 0x1000 | ||
69 | #define EXYNOS4_TMU_INTCLEAR_VAL 0x1111 | ||
70 | |||
71 | struct exynos4_tmu_data { | ||
72 | struct exynos4_tmu_platform_data *pdata; | ||
73 | struct device *hwmon_dev; | ||
74 | struct resource *mem; | ||
75 | void __iomem *base; | ||
76 | int irq; | ||
77 | struct work_struct irq_work; | ||
78 | struct mutex lock; | ||
79 | struct clk *clk; | ||
80 | u8 temp_error1, temp_error2; | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * TMU treats temperature as a mapped temperature code. | ||
85 | * The temperature is converted differently depending on the calibration type. | ||
86 | */ | ||
87 | static int temp_to_code(struct exynos4_tmu_data *data, u8 temp) | ||
88 | { | ||
89 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
90 | int temp_code; | ||
91 | |||
92 | /* temp should range between 25 and 125 */ | ||
93 | if (temp < 25 || temp > 125) { | ||
94 | temp_code = -EINVAL; | ||
95 | goto out; | ||
96 | } | ||
97 | |||
98 | switch (pdata->cal_type) { | ||
99 | case TYPE_TWO_POINT_TRIMMING: | ||
100 | temp_code = (temp - 25) * | ||
101 | (data->temp_error2 - data->temp_error1) / | ||
102 | (85 - 25) + data->temp_error1; | ||
103 | break; | ||
104 | case TYPE_ONE_POINT_TRIMMING: | ||
105 | temp_code = temp + data->temp_error1 - 25; | ||
106 | break; | ||
107 | default: | ||
108 | temp_code = temp + EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET; | ||
109 | break; | ||
110 | } | ||
111 | out: | ||
112 | return temp_code; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * Calculate a temperature value from a temperature code. | ||
117 | * The unit of the temperature is degree Celsius. | ||
118 | */ | ||
119 | static int code_to_temp(struct exynos4_tmu_data *data, u8 temp_code) | ||
120 | { | ||
121 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
122 | int temp; | ||
123 | |||
124 | /* temp_code should range between 75 and 175 */ | ||
125 | if (temp_code < 75 || temp_code > 175) { | ||
126 | temp = -ENODATA; | ||
127 | goto out; | ||
128 | } | ||
129 | |||
130 | switch (pdata->cal_type) { | ||
131 | case TYPE_TWO_POINT_TRIMMING: | ||
132 | temp = (temp_code - data->temp_error1) * (85 - 25) / | ||
133 | (data->temp_error2 - data->temp_error1) + 25; | ||
134 | break; | ||
135 | case TYPE_ONE_POINT_TRIMMING: | ||
136 | temp = temp_code - data->temp_error1 + 25; | ||
137 | break; | ||
138 | default: | ||
139 | temp = temp_code - EXYNOS4_TMU_DEF_CODE_TO_TEMP_OFFSET; | ||
140 | break; | ||
141 | } | ||
142 | out: | ||
143 | return temp; | ||
144 | } | ||
145 | |||
146 | static int exynos4_tmu_initialize(struct platform_device *pdev) | ||
147 | { | ||
148 | struct exynos4_tmu_data *data = platform_get_drvdata(pdev); | ||
149 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
150 | unsigned int status, trim_info; | ||
151 | int ret = 0, threshold_code; | ||
152 | |||
153 | mutex_lock(&data->lock); | ||
154 | clk_enable(data->clk); | ||
155 | |||
156 | status = readb(data->base + EXYNOS4_TMU_REG_STATUS); | ||
157 | if (!status) { | ||
158 | ret = -EBUSY; | ||
159 | goto out; | ||
160 | } | ||
161 | |||
162 | /* Save trimming info in order to perform calibration */ | ||
163 | trim_info = readl(data->base + EXYNOS4_TMU_REG_TRIMINFO); | ||
164 | data->temp_error1 = trim_info & EXYNOS4_TMU_TRIM_TEMP_MASK; | ||
165 | data->temp_error2 = ((trim_info >> 8) & EXYNOS4_TMU_TRIM_TEMP_MASK); | ||
166 | |||
167 | /* Write temperature code for threshold */ | ||
168 | threshold_code = temp_to_code(data, pdata->threshold); | ||
169 | if (threshold_code < 0) { | ||
170 | ret = threshold_code; | ||
171 | goto out; | ||
172 | } | ||
173 | writeb(threshold_code, | ||
174 | data->base + EXYNOS4_TMU_REG_THRESHOLD_TEMP); | ||
175 | |||
176 | writeb(pdata->trigger_levels[0], | ||
177 | data->base + EXYNOS4_TMU_REG_TRIG_LEVEL0); | ||
178 | writeb(pdata->trigger_levels[1], | ||
179 | data->base + EXYNOS4_TMU_REG_TRIG_LEVEL1); | ||
180 | writeb(pdata->trigger_levels[2], | ||
181 | data->base + EXYNOS4_TMU_REG_TRIG_LEVEL2); | ||
182 | writeb(pdata->trigger_levels[3], | ||
183 | data->base + EXYNOS4_TMU_REG_TRIG_LEVEL3); | ||
184 | |||
185 | writel(EXYNOS4_TMU_INTCLEAR_VAL, | ||
186 | data->base + EXYNOS4_TMU_REG_INTCLEAR); | ||
187 | out: | ||
188 | clk_disable(data->clk); | ||
189 | mutex_unlock(&data->lock); | ||
190 | |||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static void exynos4_tmu_control(struct platform_device *pdev, bool on) | ||
195 | { | ||
196 | struct exynos4_tmu_data *data = platform_get_drvdata(pdev); | ||
197 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
198 | unsigned int con, interrupt_en; | ||
199 | |||
200 | mutex_lock(&data->lock); | ||
201 | clk_enable(data->clk); | ||
202 | |||
203 | con = pdata->reference_voltage << EXYNOS4_TMU_REF_VOLTAGE_SHIFT | | ||
204 | pdata->gain << EXYNOS4_TMU_GAIN_SHIFT; | ||
205 | if (on) { | ||
206 | con |= EXYNOS4_TMU_CORE_ON; | ||
207 | interrupt_en = pdata->trigger_level3_en << 12 | | ||
208 | pdata->trigger_level2_en << 8 | | ||
209 | pdata->trigger_level1_en << 4 | | ||
210 | pdata->trigger_level0_en; | ||
211 | } else { | ||
212 | con |= EXYNOS4_TMU_CORE_OFF; | ||
213 | interrupt_en = 0; /* Disable all interrupts */ | ||
214 | } | ||
215 | writel(interrupt_en, data->base + EXYNOS4_TMU_REG_INTEN); | ||
216 | writel(con, data->base + EXYNOS4_TMU_REG_CONTROL); | ||
217 | |||
218 | clk_disable(data->clk); | ||
219 | mutex_unlock(&data->lock); | ||
220 | } | ||
221 | |||
222 | static int exynos4_tmu_read(struct exynos4_tmu_data *data) | ||
223 | { | ||
224 | u8 temp_code; | ||
225 | int temp; | ||
226 | |||
227 | mutex_lock(&data->lock); | ||
228 | clk_enable(data->clk); | ||
229 | |||
230 | temp_code = readb(data->base + EXYNOS4_TMU_REG_CURRENT_TEMP); | ||
231 | temp = code_to_temp(data, temp_code); | ||
232 | |||
233 | clk_disable(data->clk); | ||
234 | mutex_unlock(&data->lock); | ||
235 | |||
236 | return temp; | ||
237 | } | ||
238 | |||
239 | static void exynos4_tmu_work(struct work_struct *work) | ||
240 | { | ||
241 | struct exynos4_tmu_data *data = container_of(work, | ||
242 | struct exynos4_tmu_data, irq_work); | ||
243 | |||
244 | mutex_lock(&data->lock); | ||
245 | clk_enable(data->clk); | ||
246 | |||
247 | writel(EXYNOS4_TMU_INTCLEAR_VAL, data->base + EXYNOS4_TMU_REG_INTCLEAR); | ||
248 | |||
249 | kobject_uevent(&data->hwmon_dev->kobj, KOBJ_CHANGE); | ||
250 | |||
251 | enable_irq(data->irq); | ||
252 | |||
253 | clk_disable(data->clk); | ||
254 | mutex_unlock(&data->lock); | ||
255 | } | ||
256 | |||
257 | static irqreturn_t exynos4_tmu_irq(int irq, void *id) | ||
258 | { | ||
259 | struct exynos4_tmu_data *data = id; | ||
260 | |||
261 | disable_irq_nosync(irq); | ||
262 | schedule_work(&data->irq_work); | ||
263 | |||
264 | return IRQ_HANDLED; | ||
265 | } | ||
266 | |||
267 | static ssize_t exynos4_tmu_show_name(struct device *dev, | ||
268 | struct device_attribute *attr, char *buf) | ||
269 | { | ||
270 | return sprintf(buf, "exynos4-tmu\n"); | ||
271 | } | ||
272 | |||
273 | static ssize_t exynos4_tmu_show_temp(struct device *dev, | ||
274 | struct device_attribute *attr, char *buf) | ||
275 | { | ||
276 | struct exynos4_tmu_data *data = dev_get_drvdata(dev); | ||
277 | int ret; | ||
278 | |||
279 | ret = exynos4_tmu_read(data); | ||
280 | if (ret < 0) | ||
281 | return ret; | ||
282 | |||
283 | /* convert from degree Celsius to millidegree Celsius */ | ||
284 | return sprintf(buf, "%d\n", ret * 1000); | ||
285 | } | ||
286 | |||
287 | static ssize_t exynos4_tmu_show_alarm(struct device *dev, | ||
288 | struct device_attribute *devattr, char *buf) | ||
289 | { | ||
290 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
291 | struct exynos4_tmu_data *data = dev_get_drvdata(dev); | ||
292 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
293 | int temp; | ||
294 | unsigned int trigger_level; | ||
295 | |||
296 | temp = exynos4_tmu_read(data); | ||
297 | if (temp < 0) | ||
298 | return temp; | ||
299 | |||
300 | trigger_level = pdata->threshold + pdata->trigger_levels[attr->index]; | ||
301 | |||
302 | return sprintf(buf, "%d\n", !!(temp > trigger_level)); | ||
303 | } | ||
304 | |||
305 | static ssize_t exynos4_tmu_show_level(struct device *dev, | ||
306 | struct device_attribute *devattr, char *buf) | ||
307 | { | ||
308 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
309 | struct exynos4_tmu_data *data = dev_get_drvdata(dev); | ||
310 | struct exynos4_tmu_platform_data *pdata = data->pdata; | ||
311 | unsigned int temp = pdata->threshold + | ||
312 | pdata->trigger_levels[attr->index]; | ||
313 | |||
314 | return sprintf(buf, "%u\n", temp * 1000); | ||
315 | } | ||
316 | |||
317 | static DEVICE_ATTR(name, S_IRUGO, exynos4_tmu_show_name, NULL); | ||
318 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, exynos4_tmu_show_temp, NULL, 0); | ||
319 | |||
320 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, | ||
321 | exynos4_tmu_show_alarm, NULL, 1); | ||
322 | static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, | ||
323 | exynos4_tmu_show_alarm, NULL, 2); | ||
324 | static SENSOR_DEVICE_ATTR(temp1_emergency_alarm, S_IRUGO, | ||
325 | exynos4_tmu_show_alarm, NULL, 3); | ||
326 | |||
327 | static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, exynos4_tmu_show_level, NULL, 1); | ||
328 | static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, exynos4_tmu_show_level, NULL, 2); | ||
329 | static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO, | ||
330 | exynos4_tmu_show_level, NULL, 3); | ||
331 | |||
332 | static struct attribute *exynos4_tmu_attributes[] = { | ||
333 | &dev_attr_name.attr, | ||
334 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
335 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
336 | &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, | ||
337 | &sensor_dev_attr_temp1_emergency_alarm.dev_attr.attr, | ||
338 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
339 | &sensor_dev_attr_temp1_crit.dev_attr.attr, | ||
340 | &sensor_dev_attr_temp1_emergency.dev_attr.attr, | ||
341 | NULL, | ||
342 | }; | ||
343 | |||
344 | static const struct attribute_group exynos4_tmu_attr_group = { | ||
345 | .attrs = exynos4_tmu_attributes, | ||
346 | }; | ||
347 | |||
348 | static int __devinit exynos4_tmu_probe(struct platform_device *pdev) | ||
349 | { | ||
350 | struct exynos4_tmu_data *data; | ||
351 | struct exynos4_tmu_platform_data *pdata = pdev->dev.platform_data; | ||
352 | int ret; | ||
353 | |||
354 | if (!pdata) { | ||
355 | dev_err(&pdev->dev, "No platform init data supplied.\n"); | ||
356 | return -ENODEV; | ||
357 | } | ||
358 | |||
359 | data = kzalloc(sizeof(struct exynos4_tmu_data), GFP_KERNEL); | ||
360 | if (!data) { | ||
361 | dev_err(&pdev->dev, "Failed to allocate driver structure\n"); | ||
362 | return -ENOMEM; | ||
363 | } | ||
364 | |||
365 | data->irq = platform_get_irq(pdev, 0); | ||
366 | if (data->irq < 0) { | ||
367 | ret = data->irq; | ||
368 | dev_err(&pdev->dev, "Failed to get platform irq\n"); | ||
369 | goto err_free; | ||
370 | } | ||
371 | |||
372 | INIT_WORK(&data->irq_work, exynos4_tmu_work); | ||
373 | |||
374 | data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
375 | if (!data->mem) { | ||
376 | ret = -ENOENT; | ||
377 | dev_err(&pdev->dev, "Failed to get platform resource\n"); | ||
378 | goto err_free; | ||
379 | } | ||
380 | |||
381 | data->mem = request_mem_region(data->mem->start, | ||
382 | resource_size(data->mem), pdev->name); | ||
383 | if (!data->mem) { | ||
384 | ret = -ENODEV; | ||
385 | dev_err(&pdev->dev, "Failed to request memory region\n"); | ||
386 | goto err_free; | ||
387 | } | ||
388 | |||
389 | data->base = ioremap(data->mem->start, resource_size(data->mem)); | ||
390 | if (!data->base) { | ||
391 | ret = -ENODEV; | ||
392 | dev_err(&pdev->dev, "Failed to ioremap memory\n"); | ||
393 | goto err_mem_region; | ||
394 | } | ||
395 | |||
396 | ret = request_irq(data->irq, exynos4_tmu_irq, | ||
397 | IRQF_TRIGGER_RISING, | ||
398 | "exynos4-tmu", data); | ||
399 | if (ret) { | ||
400 | dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); | ||
401 | goto err_io_remap; | ||
402 | } | ||
403 | |||
404 | data->clk = clk_get(NULL, "tmu_apbif"); | ||
405 | if (IS_ERR(data->clk)) { | ||
406 | ret = PTR_ERR(data->clk); | ||
407 | dev_err(&pdev->dev, "Failed to get clock\n"); | ||
408 | goto err_irq; | ||
409 | } | ||
410 | |||
411 | data->pdata = pdata; | ||
412 | platform_set_drvdata(pdev, data); | ||
413 | mutex_init(&data->lock); | ||
414 | |||
415 | ret = exynos4_tmu_initialize(pdev); | ||
416 | if (ret) { | ||
417 | dev_err(&pdev->dev, "Failed to initialize TMU\n"); | ||
418 | goto err_clk; | ||
419 | } | ||
420 | |||
421 | ret = sysfs_create_group(&pdev->dev.kobj, &exynos4_tmu_attr_group); | ||
422 | if (ret) { | ||
423 | dev_err(&pdev->dev, "Failed to create sysfs group\n"); | ||
424 | goto err_clk; | ||
425 | } | ||
426 | |||
427 | data->hwmon_dev = hwmon_device_register(&pdev->dev); | ||
428 | if (IS_ERR(data->hwmon_dev)) { | ||
429 | ret = PTR_ERR(data->hwmon_dev); | ||
430 | dev_err(&pdev->dev, "Failed to register hwmon device\n"); | ||
431 | goto err_create_group; | ||
432 | } | ||
433 | |||
434 | exynos4_tmu_control(pdev, true); | ||
435 | |||
436 | return 0; | ||
437 | |||
438 | err_create_group: | ||
439 | sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group); | ||
440 | err_clk: | ||
441 | platform_set_drvdata(pdev, NULL); | ||
442 | clk_put(data->clk); | ||
443 | err_irq: | ||
444 | free_irq(data->irq, data); | ||
445 | err_io_remap: | ||
446 | iounmap(data->base); | ||
447 | err_mem_region: | ||
448 | release_mem_region(data->mem->start, resource_size(data->mem)); | ||
449 | err_free: | ||
450 | kfree(data); | ||
451 | |||
452 | return ret; | ||
453 | } | ||
454 | |||
455 | static int __devexit exynos4_tmu_remove(struct platform_device *pdev) | ||
456 | { | ||
457 | struct exynos4_tmu_data *data = platform_get_drvdata(pdev); | ||
458 | |||
459 | exynos4_tmu_control(pdev, false); | ||
460 | |||
461 | hwmon_device_unregister(data->hwmon_dev); | ||
462 | sysfs_remove_group(&pdev->dev.kobj, &exynos4_tmu_attr_group); | ||
463 | |||
464 | clk_put(data->clk); | ||
465 | |||
466 | free_irq(data->irq, data); | ||
467 | |||
468 | iounmap(data->base); | ||
469 | release_mem_region(data->mem->start, resource_size(data->mem)); | ||
470 | |||
471 | platform_set_drvdata(pdev, NULL); | ||
472 | |||
473 | kfree(data); | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | #ifdef CONFIG_PM | ||
479 | static int exynos4_tmu_suspend(struct platform_device *pdev, pm_message_t state) | ||
480 | { | ||
481 | exynos4_tmu_control(pdev, false); | ||
482 | |||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static int exynos4_tmu_resume(struct platform_device *pdev) | ||
487 | { | ||
488 | exynos4_tmu_initialize(pdev); | ||
489 | exynos4_tmu_control(pdev, true); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | #else | ||
494 | #define exynos4_tmu_suspend NULL | ||
495 | #define exynos4_tmu_resume NULL | ||
496 | #endif | ||
497 | |||
498 | static struct platform_driver exynos4_tmu_driver = { | ||
499 | .driver = { | ||
500 | .name = "exynos4-tmu", | ||
501 | .owner = THIS_MODULE, | ||
502 | }, | ||
503 | .probe = exynos4_tmu_probe, | ||
504 | .remove = __devexit_p(exynos4_tmu_remove), | ||
505 | .suspend = exynos4_tmu_suspend, | ||
506 | .resume = exynos4_tmu_resume, | ||
507 | }; | ||
508 | |||
509 | static int __init exynos4_tmu_driver_init(void) | ||
510 | { | ||
511 | return platform_driver_register(&exynos4_tmu_driver); | ||
512 | } | ||
513 | module_init(exynos4_tmu_driver_init); | ||
514 | |||
515 | static void __exit exynos4_tmu_driver_exit(void) | ||
516 | { | ||
517 | platform_driver_unregister(&exynos4_tmu_driver); | ||
518 | } | ||
519 | module_exit(exynos4_tmu_driver_exit); | ||
520 | |||
521 | MODULE_DESCRIPTION("EXYNOS4 TMU Driver"); | ||
522 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); | ||
523 | MODULE_LICENSE("GPL"); | ||
524 | MODULE_ALIAS("platform:exynos4-tmu"); | ||
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 2d96ed2bf8ed..59dd881c71d8 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c | |||
@@ -605,7 +605,7 @@ static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = { | |||
605 | 605 | ||
606 | /* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the | 606 | /* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the |
607 | standard models */ | 607 | standard models */ |
608 | static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = { | 608 | static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { { |
609 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, | 609 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, |
610 | show_pwm_auto_point_channel, | 610 | show_pwm_auto_point_channel, |
611 | store_pwm_auto_point_channel, 0, 0), | 611 | store_pwm_auto_point_channel, 0, 0), |
@@ -627,7 +627,7 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = { | |||
627 | 0, 0), | 627 | 0, 0), |
628 | SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO, | 628 | SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO, |
629 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), | 629 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), |
630 | 630 | }, { | |
631 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, | 631 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, |
632 | show_pwm_auto_point_channel, | 632 | show_pwm_auto_point_channel, |
633 | store_pwm_auto_point_channel, 0, 1), | 633 | store_pwm_auto_point_channel, 0, 1), |
@@ -649,7 +649,7 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = { | |||
649 | 0, 1), | 649 | 0, 1), |
650 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, | 650 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, |
651 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), | 651 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), |
652 | 652 | }, { | |
653 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, | 653 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, |
654 | show_pwm_auto_point_channel, | 654 | show_pwm_auto_point_channel, |
655 | store_pwm_auto_point_channel, 0, 2), | 655 | store_pwm_auto_point_channel, 0, 2), |
@@ -671,12 +671,12 @@ static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = { | |||
671 | 0, 2), | 671 | 0, 2), |
672 | SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO, | 672 | SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO, |
673 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), | 673 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), |
674 | }; | 674 | } }; |
675 | 675 | ||
676 | /* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the | 676 | /* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the |
677 | pwm setting when the temperature is above the pwmX_auto_point1_temp can be | 677 | pwm setting when the temperature is above the pwmX_auto_point1_temp can be |
678 | programmed instead of being hardcoded to 0xff */ | 678 | programmed instead of being hardcoded to 0xff */ |
679 | static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = { | 679 | static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { { |
680 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, | 680 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, |
681 | show_pwm_auto_point_channel, | 681 | show_pwm_auto_point_channel, |
682 | store_pwm_auto_point_channel, 0, 0), | 682 | store_pwm_auto_point_channel, 0, 0), |
@@ -701,7 +701,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = { | |||
701 | 0, 0), | 701 | 0, 0), |
702 | SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO, | 702 | SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO, |
703 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), | 703 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), |
704 | 704 | }, { | |
705 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, | 705 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, |
706 | show_pwm_auto_point_channel, | 706 | show_pwm_auto_point_channel, |
707 | store_pwm_auto_point_channel, 0, 1), | 707 | store_pwm_auto_point_channel, 0, 1), |
@@ -726,7 +726,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = { | |||
726 | 0, 1), | 726 | 0, 1), |
727 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, | 727 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, |
728 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), | 728 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), |
729 | 729 | }, { | |
730 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, | 730 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, |
731 | show_pwm_auto_point_channel, | 731 | show_pwm_auto_point_channel, |
732 | store_pwm_auto_point_channel, 0, 2), | 732 | store_pwm_auto_point_channel, 0, 2), |
@@ -751,7 +751,7 @@ static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = { | |||
751 | 0, 2), | 751 | 0, 2), |
752 | SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO, | 752 | SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO, |
753 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), | 753 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), |
754 | }; | 754 | } }; |
755 | 755 | ||
756 | /* PWM attr for the standard models */ | 756 | /* PWM attr for the standard models */ |
757 | static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { { | 757 | static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { { |
@@ -928,7 +928,7 @@ static struct sensor_device_attribute_2 f8000_fan_attr[] = { | |||
928 | /* PWM attr for the f8000, zones mapped to temp instead of to pwm! | 928 | /* PWM attr for the f8000, zones mapped to temp instead of to pwm! |
929 | Also the register block at offset A0 maps to TEMP1 (so our temp2, as the | 929 | Also the register block at offset A0 maps to TEMP1 (so our temp2, as the |
930 | F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */ | 930 | F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */ |
931 | static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = { | 931 | static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { { |
932 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, | 932 | SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR, |
933 | show_pwm_auto_point_channel, | 933 | show_pwm_auto_point_channel, |
934 | store_pwm_auto_point_channel, 0, 0), | 934 | store_pwm_auto_point_channel, 0, 0), |
@@ -969,7 +969,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = { | |||
969 | show_pwm_auto_point_temp_hyst, NULL, 2, 2), | 969 | show_pwm_auto_point_temp_hyst, NULL, 2, 2), |
970 | SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO, | 970 | SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO, |
971 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), | 971 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), |
972 | 972 | }, { | |
973 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, | 973 | SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR, |
974 | show_pwm_auto_point_channel, | 974 | show_pwm_auto_point_channel, |
975 | store_pwm_auto_point_channel, 0, 1), | 975 | store_pwm_auto_point_channel, 0, 1), |
@@ -1010,7 +1010,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = { | |||
1010 | show_pwm_auto_point_temp_hyst, NULL, 2, 0), | 1010 | show_pwm_auto_point_temp_hyst, NULL, 2, 0), |
1011 | SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO, | 1011 | SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO, |
1012 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), | 1012 | show_pwm_auto_point_temp_hyst, NULL, 3, 0), |
1013 | 1013 | }, { | |
1014 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, | 1014 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, |
1015 | show_pwm_auto_point_channel, | 1015 | show_pwm_auto_point_channel, |
1016 | store_pwm_auto_point_channel, 0, 2), | 1016 | store_pwm_auto_point_channel, 0, 2), |
@@ -1051,7 +1051,7 @@ static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = { | |||
1051 | show_pwm_auto_point_temp_hyst, NULL, 2, 1), | 1051 | show_pwm_auto_point_temp_hyst, NULL, 2, 1), |
1052 | SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO, | 1052 | SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO, |
1053 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), | 1053 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), |
1054 | }; | 1054 | } }; |
1055 | 1055 | ||
1056 | /* Super I/O functions */ | 1056 | /* Super I/O functions */ |
1057 | static inline int superio_inb(int base, int reg) | 1057 | static inline int superio_inb(int base, int reg) |
@@ -2154,6 +2154,104 @@ static void f71882fg_remove_sysfs_files(struct platform_device *pdev, | |||
2154 | device_remove_file(&pdev->dev, &attr[i].dev_attr); | 2154 | device_remove_file(&pdev->dev, &attr[i].dev_attr); |
2155 | } | 2155 | } |
2156 | 2156 | ||
2157 | static int __devinit f71882fg_create_fan_sysfs_files( | ||
2158 | struct platform_device *pdev, int idx) | ||
2159 | { | ||
2160 | struct f71882fg_data *data = platform_get_drvdata(pdev); | ||
2161 | int err; | ||
2162 | |||
2163 | /* Sanity check the pwm setting */ | ||
2164 | err = 0; | ||
2165 | switch (data->type) { | ||
2166 | case f71858fg: | ||
2167 | if (((data->pwm_enable >> (idx * 2)) & 3) == 3) | ||
2168 | err = 1; | ||
2169 | break; | ||
2170 | case f71862fg: | ||
2171 | if (((data->pwm_enable >> (idx * 2)) & 1) != 1) | ||
2172 | err = 1; | ||
2173 | break; | ||
2174 | case f8000: | ||
2175 | if (idx == 2) | ||
2176 | err = data->pwm_enable & 0x20; | ||
2177 | break; | ||
2178 | default: | ||
2179 | break; | ||
2180 | } | ||
2181 | if (err) { | ||
2182 | dev_err(&pdev->dev, | ||
2183 | "Invalid (reserved) pwm settings: 0x%02x, " | ||
2184 | "skipping fan %d\n", | ||
2185 | (data->pwm_enable >> (idx * 2)) & 3, idx + 1); | ||
2186 | return 0; /* This is a non fatal condition */ | ||
2187 | } | ||
2188 | |||
2189 | err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[idx][0], | ||
2190 | ARRAY_SIZE(fxxxx_fan_attr[0])); | ||
2191 | if (err) | ||
2192 | return err; | ||
2193 | |||
2194 | if (f71882fg_fan_has_beep[data->type]) { | ||
2195 | err = f71882fg_create_sysfs_files(pdev, | ||
2196 | &fxxxx_fan_beep_attr[idx], | ||
2197 | 1); | ||
2198 | if (err) | ||
2199 | return err; | ||
2200 | } | ||
2201 | |||
2202 | dev_info(&pdev->dev, "Fan: %d is in %s mode\n", idx + 1, | ||
2203 | (data->pwm_enable & (1 << (2 * idx))) ? "duty-cycle" : "RPM"); | ||
2204 | |||
2205 | /* Check for unsupported auto pwm settings */ | ||
2206 | switch (data->type) { | ||
2207 | case f71808e: | ||
2208 | case f71808a: | ||
2209 | case f71869: | ||
2210 | case f71869a: | ||
2211 | case f71889fg: | ||
2212 | case f71889ed: | ||
2213 | case f71889a: | ||
2214 | data->pwm_auto_point_mapping[idx] = | ||
2215 | f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(idx)); | ||
2216 | if ((data->pwm_auto_point_mapping[idx] & 0x80) || | ||
2217 | (data->pwm_auto_point_mapping[idx] & 3) == 0) { | ||
2218 | dev_warn(&pdev->dev, | ||
2219 | "Auto pwm controlled by raw digital " | ||
2220 | "data, disabling pwm auto_point " | ||
2221 | "sysfs attributes for fan %d\n", idx + 1); | ||
2222 | return 0; /* This is a non fatal condition */ | ||
2223 | } | ||
2224 | break; | ||
2225 | default: | ||
2226 | break; | ||
2227 | } | ||
2228 | |||
2229 | switch (data->type) { | ||
2230 | case f71862fg: | ||
2231 | err = f71882fg_create_sysfs_files(pdev, | ||
2232 | &f71862fg_auto_pwm_attr[idx][0], | ||
2233 | ARRAY_SIZE(f71862fg_auto_pwm_attr[0])); | ||
2234 | break; | ||
2235 | case f71808e: | ||
2236 | case f71869: | ||
2237 | err = f71882fg_create_sysfs_files(pdev, | ||
2238 | &f71869_auto_pwm_attr[idx][0], | ||
2239 | ARRAY_SIZE(f71869_auto_pwm_attr[0])); | ||
2240 | break; | ||
2241 | case f8000: | ||
2242 | err = f71882fg_create_sysfs_files(pdev, | ||
2243 | &f8000_auto_pwm_attr[idx][0], | ||
2244 | ARRAY_SIZE(f8000_auto_pwm_attr[0])); | ||
2245 | break; | ||
2246 | default: | ||
2247 | err = f71882fg_create_sysfs_files(pdev, | ||
2248 | &fxxxx_auto_pwm_attr[idx][0], | ||
2249 | ARRAY_SIZE(fxxxx_auto_pwm_attr[0])); | ||
2250 | } | ||
2251 | |||
2252 | return err; | ||
2253 | } | ||
2254 | |||
2157 | static int __devinit f71882fg_probe(struct platform_device *pdev) | 2255 | static int __devinit f71882fg_probe(struct platform_device *pdev) |
2158 | { | 2256 | { |
2159 | struct f71882fg_data *data; | 2257 | struct f71882fg_data *data; |
@@ -2272,117 +2370,29 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
2272 | data->pwm_enable = | 2370 | data->pwm_enable = |
2273 | f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); | 2371 | f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); |
2274 | 2372 | ||
2275 | /* Sanity check the pwm settings */ | 2373 | for (i = 0; i < nr_fans; i++) { |
2276 | switch (data->type) { | 2374 | err = f71882fg_create_fan_sysfs_files(pdev, i); |
2277 | case f71858fg: | ||
2278 | err = 0; | ||
2279 | for (i = 0; i < nr_fans; i++) | ||
2280 | if (((data->pwm_enable >> (i * 2)) & 3) == 3) | ||
2281 | err = 1; | ||
2282 | break; | ||
2283 | case f71862fg: | ||
2284 | err = (data->pwm_enable & 0x15) != 0x15; | ||
2285 | break; | ||
2286 | case f8000: | ||
2287 | err = data->pwm_enable & 0x20; | ||
2288 | break; | ||
2289 | default: | ||
2290 | err = 0; | ||
2291 | break; | ||
2292 | } | ||
2293 | if (err) { | ||
2294 | dev_err(&pdev->dev, | ||
2295 | "Invalid (reserved) pwm settings: 0x%02x\n", | ||
2296 | (unsigned int)data->pwm_enable); | ||
2297 | err = -ENODEV; | ||
2298 | goto exit_unregister_sysfs; | ||
2299 | } | ||
2300 | |||
2301 | err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0], | ||
2302 | ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans); | ||
2303 | if (err) | ||
2304 | goto exit_unregister_sysfs; | ||
2305 | |||
2306 | if (f71882fg_fan_has_beep[data->type]) { | ||
2307 | err = f71882fg_create_sysfs_files(pdev, | ||
2308 | fxxxx_fan_beep_attr, nr_fans); | ||
2309 | if (err) | 2375 | if (err) |
2310 | goto exit_unregister_sysfs; | 2376 | goto exit_unregister_sysfs; |
2311 | } | 2377 | } |
2312 | 2378 | ||
2313 | switch (data->type) { | 2379 | /* Some types have 1 extra fan with limited functionality */ |
2314 | case f71808e: | ||
2315 | case f71808a: | ||
2316 | case f71869: | ||
2317 | case f71869a: | ||
2318 | case f71889fg: | ||
2319 | case f71889ed: | ||
2320 | case f71889a: | ||
2321 | for (i = 0; i < nr_fans; i++) { | ||
2322 | data->pwm_auto_point_mapping[i] = | ||
2323 | f71882fg_read8(data, | ||
2324 | F71882FG_REG_POINT_MAPPING(i)); | ||
2325 | if ((data->pwm_auto_point_mapping[i] & 0x80) || | ||
2326 | (data->pwm_auto_point_mapping[i] & 3) == 0) | ||
2327 | break; | ||
2328 | } | ||
2329 | if (i != nr_fans) { | ||
2330 | dev_warn(&pdev->dev, | ||
2331 | "Auto pwm controlled by raw digital " | ||
2332 | "data, disabling pwm auto_point " | ||
2333 | "sysfs attributes\n"); | ||
2334 | goto no_pwm_auto_point; | ||
2335 | } | ||
2336 | break; | ||
2337 | default: | ||
2338 | break; | ||
2339 | } | ||
2340 | |||
2341 | switch (data->type) { | 2380 | switch (data->type) { |
2342 | case f71808a: | 2381 | case f71808a: |
2343 | err = f71882fg_create_sysfs_files(pdev, | 2382 | err = f71882fg_create_sysfs_files(pdev, |
2344 | &fxxxx_auto_pwm_attr[0][0], | ||
2345 | ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); | ||
2346 | if (err) | ||
2347 | goto exit_unregister_sysfs; | ||
2348 | err = f71882fg_create_sysfs_files(pdev, | ||
2349 | f71808a_fan3_attr, | 2383 | f71808a_fan3_attr, |
2350 | ARRAY_SIZE(f71808a_fan3_attr)); | 2384 | ARRAY_SIZE(f71808a_fan3_attr)); |
2351 | break; | 2385 | break; |
2352 | case f71862fg: | ||
2353 | err = f71882fg_create_sysfs_files(pdev, | ||
2354 | f71862fg_auto_pwm_attr, | ||
2355 | ARRAY_SIZE(f71862fg_auto_pwm_attr)); | ||
2356 | break; | ||
2357 | case f71808e: | ||
2358 | case f71869: | ||
2359 | err = f71882fg_create_sysfs_files(pdev, | ||
2360 | f71869_auto_pwm_attr, | ||
2361 | ARRAY_SIZE(f71869_auto_pwm_attr)); | ||
2362 | break; | ||
2363 | case f8000: | 2386 | case f8000: |
2364 | err = f71882fg_create_sysfs_files(pdev, | 2387 | err = f71882fg_create_sysfs_files(pdev, |
2365 | f8000_fan_attr, | 2388 | f8000_fan_attr, |
2366 | ARRAY_SIZE(f8000_fan_attr)); | 2389 | ARRAY_SIZE(f8000_fan_attr)); |
2367 | if (err) | ||
2368 | goto exit_unregister_sysfs; | ||
2369 | err = f71882fg_create_sysfs_files(pdev, | ||
2370 | f8000_auto_pwm_attr, | ||
2371 | ARRAY_SIZE(f8000_auto_pwm_attr)); | ||
2372 | break; | 2390 | break; |
2373 | default: | 2391 | default: |
2374 | err = f71882fg_create_sysfs_files(pdev, | 2392 | break; |
2375 | &fxxxx_auto_pwm_attr[0][0], | ||
2376 | ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans); | ||
2377 | } | 2393 | } |
2378 | if (err) | 2394 | if (err) |
2379 | goto exit_unregister_sysfs; | 2395 | goto exit_unregister_sysfs; |
2380 | |||
2381 | no_pwm_auto_point: | ||
2382 | for (i = 0; i < nr_fans; i++) | ||
2383 | dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1, | ||
2384 | (data->pwm_enable & (1 << 2 * i)) ? | ||
2385 | "duty-cycle" : "RPM"); | ||
2386 | } | 2396 | } |
2387 | 2397 | ||
2388 | data->hwmon_dev = hwmon_device_register(&pdev->dev); | 2398 | data->hwmon_dev = hwmon_device_register(&pdev->dev); |
@@ -2476,22 +2486,23 @@ static int f71882fg_remove(struct platform_device *pdev) | |||
2476 | break; | 2486 | break; |
2477 | case f71862fg: | 2487 | case f71862fg: |
2478 | f71882fg_remove_sysfs_files(pdev, | 2488 | f71882fg_remove_sysfs_files(pdev, |
2479 | f71862fg_auto_pwm_attr, | 2489 | &f71862fg_auto_pwm_attr[0][0], |
2480 | ARRAY_SIZE(f71862fg_auto_pwm_attr)); | 2490 | ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) * |
2491 | nr_fans); | ||
2481 | break; | 2492 | break; |
2482 | case f71808e: | 2493 | case f71808e: |
2483 | case f71869: | 2494 | case f71869: |
2484 | f71882fg_remove_sysfs_files(pdev, | 2495 | f71882fg_remove_sysfs_files(pdev, |
2485 | f71869_auto_pwm_attr, | 2496 | &f71869_auto_pwm_attr[0][0], |
2486 | ARRAY_SIZE(f71869_auto_pwm_attr)); | 2497 | ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans); |
2487 | break; | 2498 | break; |
2488 | case f8000: | 2499 | case f8000: |
2489 | f71882fg_remove_sysfs_files(pdev, | 2500 | f71882fg_remove_sysfs_files(pdev, |
2490 | f8000_fan_attr, | 2501 | f8000_fan_attr, |
2491 | ARRAY_SIZE(f8000_fan_attr)); | 2502 | ARRAY_SIZE(f8000_fan_attr)); |
2492 | f71882fg_remove_sysfs_files(pdev, | 2503 | f71882fg_remove_sysfs_files(pdev, |
2493 | f8000_auto_pwm_attr, | 2504 | &f8000_auto_pwm_attr[0][0], |
2494 | ARRAY_SIZE(f8000_auto_pwm_attr)); | 2505 | ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans); |
2495 | break; | 2506 | break; |
2496 | default: | 2507 | default: |
2497 | f71882fg_remove_sysfs_files(pdev, | 2508 | f71882fg_remove_sysfs_files(pdev, |
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index ef902d5d06ab..90126a2a1e44 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c | |||
@@ -35,6 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | enum lm75_type { /* keep sorted in alphabetical order */ | 37 | enum lm75_type { /* keep sorted in alphabetical order */ |
38 | adt75, | ||
38 | ds1775, | 39 | ds1775, |
39 | ds75, | 40 | ds75, |
40 | lm75, | 41 | lm75, |
@@ -213,6 +214,7 @@ static int lm75_remove(struct i2c_client *client) | |||
213 | } | 214 | } |
214 | 215 | ||
215 | static const struct i2c_device_id lm75_ids[] = { | 216 | static const struct i2c_device_id lm75_ids[] = { |
217 | { "adt75", adt75, }, | ||
216 | { "ds1775", ds1775, }, | 218 | { "ds1775", ds1775, }, |
217 | { "ds75", ds75, }, | 219 | { "ds75", ds75, }, |
218 | { "lm75", lm75, }, | 220 | { "lm75", lm75, }, |
@@ -247,19 +249,30 @@ static int lm75_detect(struct i2c_client *new_client, | |||
247 | I2C_FUNC_SMBUS_WORD_DATA)) | 249 | I2C_FUNC_SMBUS_WORD_DATA)) |
248 | return -ENODEV; | 250 | return -ENODEV; |
249 | 251 | ||
250 | /* Now, we do the remaining detection. There is no identification- | 252 | /* |
251 | dedicated register so we have to rely on several tricks: | 253 | * Now, we do the remaining detection. There is no identification- |
252 | unused bits, registers cycling over 8-address boundaries, | 254 | * dedicated register so we have to rely on several tricks: |
253 | addresses 0x04-0x07 returning the last read value. | 255 | * unused bits, registers cycling over 8-address boundaries, |
254 | The cycling+unused addresses combination is not tested, | 256 | * addresses 0x04-0x07 returning the last read value. |
255 | since it would significantly slow the detection down and would | 257 | * The cycling+unused addresses combination is not tested, |
256 | hardly add any value. | 258 | * since it would significantly slow the detection down and would |
257 | 259 | * hardly add any value. | |
258 | The National Semiconductor LM75A is different than earlier | 260 | * |
259 | LM75s. It has an ID byte of 0xaX (where X is the chip | 261 | * The National Semiconductor LM75A is different than earlier |
260 | revision, with 1 being the only revision in existence) in | 262 | * LM75s. It has an ID byte of 0xaX (where X is the chip |
261 | register 7, and unused registers return 0xff rather than the | 263 | * revision, with 1 being the only revision in existence) in |
262 | last read value. */ | 264 | * register 7, and unused registers return 0xff rather than the |
265 | * last read value. | ||
266 | * | ||
267 | * Note that this function only detects the original National | ||
268 | * Semiconductor LM75 and the LM75A. Clones from other vendors | ||
269 | * aren't detected, on purpose, because they are typically never | ||
270 | * found on PC hardware. They are found on embedded designs where | ||
271 | * they can be instantiated explicitly so detection is not needed. | ||
272 | * The absence of identification registers on all these clones | ||
273 | * would make their exhaustive detection very difficult and weak, | ||
274 | * and odds are that the driver would bind to unsupported devices. | ||
275 | */ | ||
263 | 276 | ||
264 | /* Unused bits */ | 277 | /* Unused bits */ |
265 | conf = i2c_smbus_read_byte_data(new_client, 1); | 278 | conf = i2c_smbus_read_byte_data(new_client, 1); |
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index c9237b9dcff2..4b26f51920ba 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig | |||
@@ -20,17 +20,18 @@ config SENSORS_PMBUS | |||
20 | help | 20 | help |
21 | If you say yes here you get hardware monitoring support for generic | 21 | If you say yes here you get hardware monitoring support for generic |
22 | PMBus devices, including but not limited to ADP4000, BMR450, BMR451, | 22 | PMBus devices, including but not limited to ADP4000, BMR450, BMR451, |
23 | BMR453, BMR454, LTC2978, NCP4200, and NCP4208. | 23 | BMR453, BMR454, NCP4200, and NCP4208. |
24 | 24 | ||
25 | This driver can also be built as a module. If so, the module will | 25 | This driver can also be built as a module. If so, the module will |
26 | be called pmbus. | 26 | be called pmbus. |
27 | 27 | ||
28 | config SENSORS_ADM1275 | 28 | config SENSORS_ADM1275 |
29 | tristate "Analog Devices ADM1275" | 29 | tristate "Analog Devices ADM1275 and compatibles" |
30 | default n | 30 | default n |
31 | help | 31 | help |
32 | If you say yes here you get hardware monitoring support for Analog | 32 | If you say yes here you get hardware monitoring support for Analog |
33 | Devices ADM1275 Hot-Swap Controller and Digital Power Monitor. | 33 | Devices ADM1275 and ADM1276 Hot-Swap Controller and Digital Power |
34 | Monitor. | ||
34 | 35 | ||
35 | This driver can also be built as a module. If so, the module will | 36 | This driver can also be built as a module. If so, the module will |
36 | be called adm1275. | 37 | be called adm1275. |
@@ -45,6 +46,16 @@ config SENSORS_LM25066 | |||
45 | This driver can also be built as a module. If so, the module will | 46 | This driver can also be built as a module. If so, the module will |
46 | be called lm25066. | 47 | be called lm25066. |
47 | 48 | ||
49 | config SENSORS_LTC2978 | ||
50 | tristate "Linear Technologies LTC2978 and LTC3880" | ||
51 | default n | ||
52 | help | ||
53 | If you say yes here you get hardware monitoring support for Linear | ||
54 | Technology LTC2978 and LTC3880. | ||
55 | |||
56 | This driver can also be built as a module. If so, the module will | ||
57 | be called ltc2978. | ||
58 | |||
48 | config SENSORS_MAX16064 | 59 | config SENSORS_MAX16064 |
49 | tristate "Maxim MAX16064" | 60 | tristate "Maxim MAX16064" |
50 | default n | 61 | default n |
@@ -97,4 +108,15 @@ config SENSORS_UCD9200 | |||
97 | This driver can also be built as a module. If so, the module will | 108 | This driver can also be built as a module. If so, the module will |
98 | be called ucd9200. | 109 | be called ucd9200. |
99 | 110 | ||
111 | config SENSORS_ZL6100 | ||
112 | tristate "Intersil ZL6100 and compatibles" | ||
113 | default n | ||
114 | help | ||
115 | If you say yes here you get hardware monitoring support for Intersil | ||
116 | ZL2004, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, and ZL6105 Digital | ||
117 | DC/DC Controllers. | ||
118 | |||
119 | This driver can also be built as a module. If so, the module will | ||
120 | be called zl6100. | ||
121 | |||
100 | endif # PMBUS | 122 | endif # PMBUS |
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 623eedb1ed9a..789376c85dbb 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile | |||
@@ -6,8 +6,10 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o | |||
6 | obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o | 6 | obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o |
7 | obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o | 7 | obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o |
8 | obj-$(CONFIG_SENSORS_LM25066) += lm25066.o | 8 | obj-$(CONFIG_SENSORS_LM25066) += lm25066.o |
9 | obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o | ||
9 | obj-$(CONFIG_SENSORS_MAX16064) += max16064.o | 10 | obj-$(CONFIG_SENSORS_MAX16064) += max16064.o |
10 | obj-$(CONFIG_SENSORS_MAX34440) += max34440.o | 11 | obj-$(CONFIG_SENSORS_MAX34440) += max34440.o |
11 | obj-$(CONFIG_SENSORS_MAX8688) += max8688.o | 12 | obj-$(CONFIG_SENSORS_MAX8688) += max8688.o |
12 | obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o | 13 | obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o |
13 | obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o | 14 | obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o |
15 | obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o | ||
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index c936e2782309..980a4d9d5028 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include "pmbus.h" | 24 | #include "pmbus.h" |
25 | 25 | ||
26 | enum chips { adm1275, adm1276 }; | ||
27 | |||
26 | #define ADM1275_PEAK_IOUT 0xd0 | 28 | #define ADM1275_PEAK_IOUT 0xd0 |
27 | #define ADM1275_PEAK_VIN 0xd1 | 29 | #define ADM1275_PEAK_VIN 0xd1 |
28 | #define ADM1275_PEAK_VOUT 0xd2 | 30 | #define ADM1275_PEAK_VOUT 0xd2 |
@@ -31,14 +33,47 @@ | |||
31 | #define ADM1275_VIN_VOUT_SELECT (1 << 6) | 33 | #define ADM1275_VIN_VOUT_SELECT (1 << 6) |
32 | #define ADM1275_VRANGE (1 << 5) | 34 | #define ADM1275_VRANGE (1 << 5) |
33 | 35 | ||
36 | #define ADM1275_IOUT_WARN2_LIMIT 0xd7 | ||
37 | #define ADM1275_DEVICE_CONFIG 0xd8 | ||
38 | |||
39 | #define ADM1275_IOUT_WARN2_SELECT (1 << 4) | ||
40 | |||
41 | #define ADM1276_PEAK_PIN 0xda | ||
42 | |||
43 | #define ADM1275_MFR_STATUS_IOUT_WARN2 (1 << 0) | ||
44 | |||
45 | struct adm1275_data { | ||
46 | int id; | ||
47 | bool have_oc_fault; | ||
48 | struct pmbus_driver_info info; | ||
49 | }; | ||
50 | |||
51 | #define to_adm1275_data(x) container_of(x, struct adm1275_data, info) | ||
52 | |||
34 | static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) | 53 | static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) |
35 | { | 54 | { |
36 | int ret; | 55 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
56 | const struct adm1275_data *data = to_adm1275_data(info); | ||
57 | int ret = 0; | ||
37 | 58 | ||
38 | if (page) | 59 | if (page) |
39 | return -EINVAL; | 60 | return -ENXIO; |
40 | 61 | ||
41 | switch (reg) { | 62 | switch (reg) { |
63 | case PMBUS_IOUT_UC_FAULT_LIMIT: | ||
64 | if (data->have_oc_fault) { | ||
65 | ret = -ENXIO; | ||
66 | break; | ||
67 | } | ||
68 | ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); | ||
69 | break; | ||
70 | case PMBUS_IOUT_OC_FAULT_LIMIT: | ||
71 | if (!data->have_oc_fault) { | ||
72 | ret = -ENXIO; | ||
73 | break; | ||
74 | } | ||
75 | ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT); | ||
76 | break; | ||
42 | case PMBUS_VIRT_READ_IOUT_MAX: | 77 | case PMBUS_VIRT_READ_IOUT_MAX: |
43 | ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); | 78 | ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT); |
44 | break; | 79 | break; |
@@ -48,10 +83,20 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg) | |||
48 | case PMBUS_VIRT_READ_VIN_MAX: | 83 | case PMBUS_VIRT_READ_VIN_MAX: |
49 | ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); | 84 | ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN); |
50 | break; | 85 | break; |
86 | case PMBUS_VIRT_READ_PIN_MAX: | ||
87 | if (data->id != adm1276) { | ||
88 | ret = -ENXIO; | ||
89 | break; | ||
90 | } | ||
91 | ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN); | ||
92 | break; | ||
51 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | 93 | case PMBUS_VIRT_RESET_IOUT_HISTORY: |
52 | case PMBUS_VIRT_RESET_VOUT_HISTORY: | 94 | case PMBUS_VIRT_RESET_VOUT_HISTORY: |
53 | case PMBUS_VIRT_RESET_VIN_HISTORY: | 95 | case PMBUS_VIRT_RESET_VIN_HISTORY: |
54 | ret = 0; | 96 | break; |
97 | case PMBUS_VIRT_RESET_PIN_HISTORY: | ||
98 | if (data->id != adm1276) | ||
99 | ret = -ENXIO; | ||
55 | break; | 100 | break; |
56 | default: | 101 | default: |
57 | ret = -ENODATA; | 102 | ret = -ENODATA; |
@@ -66,9 +111,14 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, | |||
66 | int ret; | 111 | int ret; |
67 | 112 | ||
68 | if (page) | 113 | if (page) |
69 | return -EINVAL; | 114 | return -ENXIO; |
70 | 115 | ||
71 | switch (reg) { | 116 | switch (reg) { |
117 | case PMBUS_IOUT_UC_FAULT_LIMIT: | ||
118 | case PMBUS_IOUT_OC_FAULT_LIMIT: | ||
119 | ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT, | ||
120 | word); | ||
121 | break; | ||
72 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | 122 | case PMBUS_VIRT_RESET_IOUT_HISTORY: |
73 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); | 123 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0); |
74 | break; | 124 | break; |
@@ -78,6 +128,41 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, | |||
78 | case PMBUS_VIRT_RESET_VIN_HISTORY: | 128 | case PMBUS_VIRT_RESET_VIN_HISTORY: |
79 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); | 129 | ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0); |
80 | break; | 130 | break; |
131 | case PMBUS_VIRT_RESET_PIN_HISTORY: | ||
132 | ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0); | ||
133 | break; | ||
134 | default: | ||
135 | ret = -ENODATA; | ||
136 | break; | ||
137 | } | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg) | ||
142 | { | ||
143 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
144 | const struct adm1275_data *data = to_adm1275_data(info); | ||
145 | int mfr_status, ret; | ||
146 | |||
147 | if (page > 0) | ||
148 | return -ENXIO; | ||
149 | |||
150 | switch (reg) { | ||
151 | case PMBUS_STATUS_IOUT: | ||
152 | ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT); | ||
153 | if (ret < 0) | ||
154 | break; | ||
155 | mfr_status = pmbus_read_byte_data(client, page, | ||
156 | PMBUS_STATUS_MFR_SPECIFIC); | ||
157 | if (mfr_status < 0) { | ||
158 | ret = mfr_status; | ||
159 | break; | ||
160 | } | ||
161 | if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) { | ||
162 | ret |= data->have_oc_fault ? | ||
163 | PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT; | ||
164 | } | ||
165 | break; | ||
81 | default: | 166 | default: |
82 | ret = -ENODATA; | 167 | ret = -ENODATA; |
83 | break; | 168 | break; |
@@ -88,16 +173,17 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg, | |||
88 | static int adm1275_probe(struct i2c_client *client, | 173 | static int adm1275_probe(struct i2c_client *client, |
89 | const struct i2c_device_id *id) | 174 | const struct i2c_device_id *id) |
90 | { | 175 | { |
91 | int config; | 176 | int config, device_config; |
92 | int ret; | 177 | int ret; |
93 | struct pmbus_driver_info *info; | 178 | struct pmbus_driver_info *info; |
179 | struct adm1275_data *data; | ||
94 | 180 | ||
95 | if (!i2c_check_functionality(client->adapter, | 181 | if (!i2c_check_functionality(client->adapter, |
96 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) | 182 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) |
97 | return -ENODEV; | 183 | return -ENODEV; |
98 | 184 | ||
99 | info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); | 185 | data = kzalloc(sizeof(struct adm1275_data), GFP_KERNEL); |
100 | if (!info) | 186 | if (!data) |
101 | return -ENOMEM; | 187 | return -ENOMEM; |
102 | 188 | ||
103 | config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | 189 | config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); |
@@ -106,6 +192,15 @@ static int adm1275_probe(struct i2c_client *client, | |||
106 | goto err_mem; | 192 | goto err_mem; |
107 | } | 193 | } |
108 | 194 | ||
195 | device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG); | ||
196 | if (device_config < 0) { | ||
197 | ret = device_config; | ||
198 | goto err_mem; | ||
199 | } | ||
200 | |||
201 | data->id = id->driver_data; | ||
202 | info = &data->info; | ||
203 | |||
109 | info->pages = 1; | 204 | info->pages = 1; |
110 | info->format[PSC_VOLTAGE_IN] = direct; | 205 | info->format[PSC_VOLTAGE_IN] = direct; |
111 | info->format[PSC_VOLTAGE_OUT] = direct; | 206 | info->format[PSC_VOLTAGE_OUT] = direct; |
@@ -116,6 +211,7 @@ static int adm1275_probe(struct i2c_client *client, | |||
116 | info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; | 211 | info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; |
117 | 212 | ||
118 | info->read_word_data = adm1275_read_word_data; | 213 | info->read_word_data = adm1275_read_word_data; |
214 | info->read_byte_data = adm1275_read_byte_data; | ||
119 | info->write_word_data = adm1275_write_word_data; | 215 | info->write_word_data = adm1275_write_word_data; |
120 | 216 | ||
121 | if (config & ADM1275_VRANGE) { | 217 | if (config & ADM1275_VRANGE) { |
@@ -134,10 +230,36 @@ static int adm1275_probe(struct i2c_client *client, | |||
134 | info->R[PSC_VOLTAGE_OUT] = -1; | 230 | info->R[PSC_VOLTAGE_OUT] = -1; |
135 | } | 231 | } |
136 | 232 | ||
137 | if (config & ADM1275_VIN_VOUT_SELECT) | 233 | if (device_config & ADM1275_IOUT_WARN2_SELECT) |
138 | info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | 234 | data->have_oc_fault = true; |
139 | else | 235 | |
140 | info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; | 236 | switch (id->driver_data) { |
237 | case adm1275: | ||
238 | if (config & ADM1275_VIN_VOUT_SELECT) | ||
239 | info->func[0] |= | ||
240 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | ||
241 | else | ||
242 | info->func[0] |= | ||
243 | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; | ||
244 | break; | ||
245 | case adm1276: | ||
246 | info->format[PSC_POWER] = direct; | ||
247 | info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN | ||
248 | | PMBUS_HAVE_STATUS_INPUT; | ||
249 | if (config & ADM1275_VIN_VOUT_SELECT) | ||
250 | info->func[0] |= | ||
251 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | ||
252 | if (config & ADM1275_VRANGE) { | ||
253 | info->m[PSC_POWER] = 6043; | ||
254 | info->b[PSC_POWER] = 0; | ||
255 | info->R[PSC_POWER] = -2; | ||
256 | } else { | ||
257 | info->m[PSC_POWER] = 2115; | ||
258 | info->b[PSC_POWER] = 0; | ||
259 | info->R[PSC_POWER] = -1; | ||
260 | } | ||
261 | break; | ||
262 | } | ||
141 | 263 | ||
142 | ret = pmbus_do_probe(client, id, info); | 264 | ret = pmbus_do_probe(client, id, info); |
143 | if (ret) | 265 | if (ret) |
@@ -145,22 +267,23 @@ static int adm1275_probe(struct i2c_client *client, | |||
145 | return 0; | 267 | return 0; |
146 | 268 | ||
147 | err_mem: | 269 | err_mem: |
148 | kfree(info); | 270 | kfree(data); |
149 | return ret; | 271 | return ret; |
150 | } | 272 | } |
151 | 273 | ||
152 | static int adm1275_remove(struct i2c_client *client) | 274 | static int adm1275_remove(struct i2c_client *client) |
153 | { | 275 | { |
154 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | 276 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
155 | int ret; | 277 | const struct adm1275_data *data = to_adm1275_data(info); |
156 | 278 | ||
157 | ret = pmbus_do_remove(client); | 279 | pmbus_do_remove(client); |
158 | kfree(info); | 280 | kfree(data); |
159 | return ret; | 281 | return 0; |
160 | } | 282 | } |
161 | 283 | ||
162 | static const struct i2c_device_id adm1275_id[] = { | 284 | static const struct i2c_device_id adm1275_id[] = { |
163 | {"adm1275", 0}, | 285 | { "adm1275", adm1275 }, |
286 | { "adm1276", adm1276 }, | ||
164 | { } | 287 | { } |
165 | }; | 288 | }; |
166 | MODULE_DEVICE_TABLE(i2c, adm1275_id); | 289 | MODULE_DEVICE_TABLE(i2c, adm1275_id); |
@@ -185,7 +308,7 @@ static void __exit adm1275_exit(void) | |||
185 | } | 308 | } |
186 | 309 | ||
187 | MODULE_AUTHOR("Guenter Roeck"); | 310 | MODULE_AUTHOR("Guenter Roeck"); |
188 | MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275"); | 311 | MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles"); |
189 | MODULE_LICENSE("GPL"); | 312 | MODULE_LICENSE("GPL"); |
190 | module_init(adm1275_init); | 313 | module_init(adm1275_init); |
191 | module_exit(adm1275_exit); | 314 | module_exit(adm1275_exit); |
diff --git a/drivers/hwmon/pmbus/lm25066.c b/drivers/hwmon/pmbus/lm25066.c index ac254fba551b..84a37f0c8db6 100644 --- a/drivers/hwmon/pmbus/lm25066.c +++ b/drivers/hwmon/pmbus/lm25066.c | |||
@@ -57,7 +57,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) | |||
57 | int ret; | 57 | int ret; |
58 | 58 | ||
59 | if (page > 1) | 59 | if (page > 1) |
60 | return -EINVAL; | 60 | return -ENXIO; |
61 | 61 | ||
62 | /* Map READ_VAUX into READ_VOUT register on page 1 */ | 62 | /* Map READ_VAUX into READ_VOUT register on page 1 */ |
63 | if (page == 1) { | 63 | if (page == 1) { |
@@ -85,7 +85,7 @@ static int lm25066_read_word_data(struct i2c_client *client, int page, int reg) | |||
85 | break; | 85 | break; |
86 | default: | 86 | default: |
87 | /* No other valid registers on page 1 */ | 87 | /* No other valid registers on page 1 */ |
88 | ret = -EINVAL; | 88 | ret = -ENXIO; |
89 | break; | 89 | break; |
90 | } | 90 | } |
91 | goto done; | 91 | goto done; |
@@ -138,7 +138,7 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, | |||
138 | int ret; | 138 | int ret; |
139 | 139 | ||
140 | if (page > 1) | 140 | if (page > 1) |
141 | return -EINVAL; | 141 | return -ENXIO; |
142 | 142 | ||
143 | switch (reg) { | 143 | switch (reg) { |
144 | case PMBUS_IIN_OC_WARN_LIMIT: | 144 | case PMBUS_IIN_OC_WARN_LIMIT: |
@@ -164,10 +164,10 @@ static int lm25066_write_word_data(struct i2c_client *client, int page, int reg, | |||
164 | static int lm25066_write_byte(struct i2c_client *client, int page, u8 value) | 164 | static int lm25066_write_byte(struct i2c_client *client, int page, u8 value) |
165 | { | 165 | { |
166 | if (page > 1) | 166 | if (page > 1) |
167 | return -EINVAL; | 167 | return -ENXIO; |
168 | 168 | ||
169 | if (page == 0) | 169 | if (page <= 0) |
170 | return pmbus_write_byte(client, 0, value); | 170 | return pmbus_write_byte(client, page, value); |
171 | 171 | ||
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
@@ -309,11 +309,10 @@ static int lm25066_remove(struct i2c_client *client) | |||
309 | { | 309 | { |
310 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | 310 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); |
311 | const struct lm25066_data *data = to_lm25066_data(info); | 311 | const struct lm25066_data *data = to_lm25066_data(info); |
312 | int ret; | ||
313 | 312 | ||
314 | ret = pmbus_do_remove(client); | 313 | pmbus_do_remove(client); |
315 | kfree(data); | 314 | kfree(data); |
316 | return ret; | 315 | return 0; |
317 | } | 316 | } |
318 | 317 | ||
319 | static const struct i2c_device_id lm25066_id[] = { | 318 | static const struct i2c_device_id lm25066_id[] = { |
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c new file mode 100644 index 000000000000..820fff48910b --- /dev/null +++ b/drivers/hwmon/pmbus/ltc2978.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for LTC2978 and LTC3880 | ||
3 | * | ||
4 | * Copyright (c) 2011 Ericsson AB. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include "pmbus.h" | ||
28 | |||
29 | enum chips { ltc2978, ltc3880 }; | ||
30 | |||
31 | /* LTC2978 and LTC3880 */ | ||
32 | #define LTC2978_MFR_VOUT_PEAK 0xdd | ||
33 | #define LTC2978_MFR_VIN_PEAK 0xde | ||
34 | #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf | ||
35 | #define LTC2978_MFR_SPECIAL_ID 0xe7 | ||
36 | |||
37 | /* LTC2978 only */ | ||
38 | #define LTC2978_MFR_VOUT_MIN 0xfb | ||
39 | #define LTC2978_MFR_VIN_MIN 0xfc | ||
40 | #define LTC2978_MFR_TEMPERATURE_MIN 0xfd | ||
41 | |||
42 | /* LTC3880 only */ | ||
43 | #define LTC3880_MFR_IOUT_PEAK 0xd7 | ||
44 | #define LTC3880_MFR_CLEAR_PEAKS 0xe3 | ||
45 | #define LTC3880_MFR_TEMPERATURE2_PEAK 0xf4 | ||
46 | |||
47 | #define LTC2978_ID_REV1 0x0121 | ||
48 | #define LTC2978_ID_REV2 0x0122 | ||
49 | #define LTC3880_ID 0x4000 | ||
50 | #define LTC3880_ID_MASK 0xff00 | ||
51 | |||
52 | /* | ||
53 | * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which | ||
54 | * happens pretty much each time chip data is updated. Raw peak data therefore | ||
55 | * does not provide much value. To be able to provide useful peak data, keep an | ||
56 | * internal cache of measured peak data, which is only cleared if an explicit | ||
57 | * "clear peak" command is executed for the sensor in question. | ||
58 | */ | ||
59 | struct ltc2978_data { | ||
60 | enum chips id; | ||
61 | int vin_min, vin_max; | ||
62 | int temp_min, temp_max; | ||
63 | int vout_min[8], vout_max[8]; | ||
64 | int iout_max[2]; | ||
65 | int temp2_max[2]; | ||
66 | struct pmbus_driver_info info; | ||
67 | }; | ||
68 | |||
69 | #define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info) | ||
70 | |||
71 | static inline int lin11_to_val(int data) | ||
72 | { | ||
73 | s16 e = ((s16)data) >> 11; | ||
74 | s32 m = (((s16)(data << 5)) >> 5); | ||
75 | |||
76 | /* | ||
77 | * mantissa is 10 bit + sign, exponent adds up to 15 bit. | ||
78 | * Add 6 bit to exponent for maximum accuracy (10 + 15 + 6 = 31). | ||
79 | */ | ||
80 | e += 6; | ||
81 | return (e < 0 ? m >> -e : m << e); | ||
82 | } | ||
83 | |||
84 | static int ltc2978_read_word_data_common(struct i2c_client *client, int page, | ||
85 | int reg) | ||
86 | { | ||
87 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
88 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
89 | int ret; | ||
90 | |||
91 | switch (reg) { | ||
92 | case PMBUS_VIRT_READ_VIN_MAX: | ||
93 | ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_PEAK); | ||
94 | if (ret >= 0) { | ||
95 | if (lin11_to_val(ret) > lin11_to_val(data->vin_max)) | ||
96 | data->vin_max = ret; | ||
97 | ret = data->vin_max; | ||
98 | } | ||
99 | break; | ||
100 | case PMBUS_VIRT_READ_VOUT_MAX: | ||
101 | ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); | ||
102 | if (ret >= 0) { | ||
103 | /* | ||
104 | * VOUT is 16 bit unsigned with fixed exponent, | ||
105 | * so we can compare it directly | ||
106 | */ | ||
107 | if (ret > data->vout_max[page]) | ||
108 | data->vout_max[page] = ret; | ||
109 | ret = data->vout_max[page]; | ||
110 | } | ||
111 | break; | ||
112 | case PMBUS_VIRT_READ_TEMP_MAX: | ||
113 | ret = pmbus_read_word_data(client, page, | ||
114 | LTC2978_MFR_TEMPERATURE_PEAK); | ||
115 | if (ret >= 0) { | ||
116 | if (lin11_to_val(ret) > lin11_to_val(data->temp_max)) | ||
117 | data->temp_max = ret; | ||
118 | ret = data->temp_max; | ||
119 | } | ||
120 | break; | ||
121 | case PMBUS_VIRT_RESET_VOUT_HISTORY: | ||
122 | case PMBUS_VIRT_RESET_VIN_HISTORY: | ||
123 | case PMBUS_VIRT_RESET_TEMP_HISTORY: | ||
124 | ret = 0; | ||
125 | break; | ||
126 | default: | ||
127 | ret = -ENODATA; | ||
128 | break; | ||
129 | } | ||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) | ||
134 | { | ||
135 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
136 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
137 | int ret; | ||
138 | |||
139 | switch (reg) { | ||
140 | case PMBUS_VIRT_READ_VIN_MIN: | ||
141 | ret = pmbus_read_word_data(client, page, LTC2978_MFR_VIN_MIN); | ||
142 | if (ret >= 0) { | ||
143 | if (lin11_to_val(ret) < lin11_to_val(data->vin_min)) | ||
144 | data->vin_min = ret; | ||
145 | ret = data->vin_min; | ||
146 | } | ||
147 | break; | ||
148 | case PMBUS_VIRT_READ_VOUT_MIN: | ||
149 | ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); | ||
150 | if (ret >= 0) { | ||
151 | /* | ||
152 | * VOUT_MIN is known to not be supported on some lots | ||
153 | * of LTC2978 revision 1, and will return the maximum | ||
154 | * possible voltage if read. If VOUT_MAX is valid and | ||
155 | * lower than the reading of VOUT_MIN, use it instead. | ||
156 | */ | ||
157 | if (data->vout_max[page] && ret > data->vout_max[page]) | ||
158 | ret = data->vout_max[page]; | ||
159 | if (ret < data->vout_min[page]) | ||
160 | data->vout_min[page] = ret; | ||
161 | ret = data->vout_min[page]; | ||
162 | } | ||
163 | break; | ||
164 | case PMBUS_VIRT_READ_TEMP_MIN: | ||
165 | ret = pmbus_read_word_data(client, page, | ||
166 | LTC2978_MFR_TEMPERATURE_MIN); | ||
167 | if (ret >= 0) { | ||
168 | if (lin11_to_val(ret) | ||
169 | < lin11_to_val(data->temp_min)) | ||
170 | data->temp_min = ret; | ||
171 | ret = data->temp_min; | ||
172 | } | ||
173 | break; | ||
174 | case PMBUS_VIRT_READ_IOUT_MAX: | ||
175 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||
176 | case PMBUS_VIRT_READ_TEMP2_MAX: | ||
177 | case PMBUS_VIRT_RESET_TEMP2_HISTORY: | ||
178 | ret = -ENXIO; | ||
179 | break; | ||
180 | default: | ||
181 | ret = ltc2978_read_word_data_common(client, page, reg); | ||
182 | break; | ||
183 | } | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static int ltc3880_read_word_data(struct i2c_client *client, int page, int reg) | ||
188 | { | ||
189 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
190 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
191 | int ret; | ||
192 | |||
193 | switch (reg) { | ||
194 | case PMBUS_VIRT_READ_IOUT_MAX: | ||
195 | ret = pmbus_read_word_data(client, page, LTC3880_MFR_IOUT_PEAK); | ||
196 | if (ret >= 0) { | ||
197 | if (lin11_to_val(ret) | ||
198 | > lin11_to_val(data->iout_max[page])) | ||
199 | data->iout_max[page] = ret; | ||
200 | ret = data->iout_max[page]; | ||
201 | } | ||
202 | break; | ||
203 | case PMBUS_VIRT_READ_TEMP2_MAX: | ||
204 | ret = pmbus_read_word_data(client, page, | ||
205 | LTC3880_MFR_TEMPERATURE2_PEAK); | ||
206 | if (ret >= 0) { | ||
207 | if (lin11_to_val(ret) | ||
208 | > lin11_to_val(data->temp2_max[page])) | ||
209 | data->temp2_max[page] = ret; | ||
210 | ret = data->temp2_max[page]; | ||
211 | } | ||
212 | break; | ||
213 | case PMBUS_VIRT_READ_VIN_MIN: | ||
214 | case PMBUS_VIRT_READ_VOUT_MIN: | ||
215 | case PMBUS_VIRT_READ_TEMP_MIN: | ||
216 | ret = -ENXIO; | ||
217 | break; | ||
218 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||
219 | case PMBUS_VIRT_RESET_TEMP2_HISTORY: | ||
220 | ret = 0; | ||
221 | break; | ||
222 | default: | ||
223 | ret = ltc2978_read_word_data_common(client, page, reg); | ||
224 | break; | ||
225 | } | ||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static int ltc2978_clear_peaks(struct i2c_client *client, int page, | ||
230 | enum chips id) | ||
231 | { | ||
232 | int ret; | ||
233 | |||
234 | if (id == ltc2978) | ||
235 | ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); | ||
236 | else | ||
237 | ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); | ||
238 | |||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int ltc2978_write_word_data(struct i2c_client *client, int page, | ||
243 | int reg, u16 word) | ||
244 | { | ||
245 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
246 | struct ltc2978_data *data = to_ltc2978_data(info); | ||
247 | int ret; | ||
248 | |||
249 | switch (reg) { | ||
250 | case PMBUS_VIRT_RESET_IOUT_HISTORY: | ||
251 | data->iout_max[page] = 0x7fff; | ||
252 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
253 | break; | ||
254 | case PMBUS_VIRT_RESET_TEMP2_HISTORY: | ||
255 | data->temp2_max[page] = 0x7fff; | ||
256 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
257 | break; | ||
258 | case PMBUS_VIRT_RESET_VOUT_HISTORY: | ||
259 | data->vout_min[page] = 0xffff; | ||
260 | data->vout_max[page] = 0; | ||
261 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
262 | break; | ||
263 | case PMBUS_VIRT_RESET_VIN_HISTORY: | ||
264 | data->vin_min = 0x7bff; | ||
265 | data->vin_max = 0; | ||
266 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
267 | break; | ||
268 | case PMBUS_VIRT_RESET_TEMP_HISTORY: | ||
269 | data->temp_min = 0x7bff; | ||
270 | data->temp_max = 0x7fff; | ||
271 | ret = ltc2978_clear_peaks(client, page, data->id); | ||
272 | break; | ||
273 | default: | ||
274 | ret = -ENODATA; | ||
275 | break; | ||
276 | } | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | static const struct i2c_device_id ltc2978_id[] = { | ||
281 | {"ltc2978", ltc2978}, | ||
282 | {"ltc3880", ltc3880}, | ||
283 | {} | ||
284 | }; | ||
285 | MODULE_DEVICE_TABLE(i2c, ltc2978_id); | ||
286 | |||
287 | static int ltc2978_probe(struct i2c_client *client, | ||
288 | const struct i2c_device_id *id) | ||
289 | { | ||
290 | int chip_id, ret, i; | ||
291 | struct ltc2978_data *data; | ||
292 | struct pmbus_driver_info *info; | ||
293 | |||
294 | if (!i2c_check_functionality(client->adapter, | ||
295 | I2C_FUNC_SMBUS_READ_WORD_DATA)) | ||
296 | return -ENODEV; | ||
297 | |||
298 | data = kzalloc(sizeof(struct ltc2978_data), GFP_KERNEL); | ||
299 | if (!data) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | chip_id = i2c_smbus_read_word_data(client, LTC2978_MFR_SPECIAL_ID); | ||
303 | if (chip_id < 0) { | ||
304 | ret = chip_id; | ||
305 | goto err_mem; | ||
306 | } | ||
307 | |||
308 | if (chip_id == LTC2978_ID_REV1 || chip_id == LTC2978_ID_REV2) { | ||
309 | data->id = ltc2978; | ||
310 | } else if ((chip_id & LTC3880_ID_MASK) == LTC3880_ID) { | ||
311 | data->id = ltc3880; | ||
312 | } else { | ||
313 | dev_err(&client->dev, "Unsupported chip ID 0x%x\n", chip_id); | ||
314 | ret = -ENODEV; | ||
315 | goto err_mem; | ||
316 | } | ||
317 | if (data->id != id->driver_data) | ||
318 | dev_warn(&client->dev, | ||
319 | "Device mismatch: Configured %s, detected %s\n", | ||
320 | id->name, | ||
321 | ltc2978_id[data->id].name); | ||
322 | |||
323 | info = &data->info; | ||
324 | info->write_word_data = ltc2978_write_word_data; | ||
325 | |||
326 | data->vout_min[0] = 0xffff; | ||
327 | data->vin_min = 0x7bff; | ||
328 | data->temp_min = 0x7bff; | ||
329 | data->temp_max = 0x7fff; | ||
330 | |||
331 | switch (id->driver_data) { | ||
332 | case ltc2978: | ||
333 | info->read_word_data = ltc2978_read_word_data; | ||
334 | info->pages = 8; | ||
335 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | ||
336 | | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
337 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | ||
338 | for (i = 1; i < 8; i++) { | ||
339 | info->func[i] = PMBUS_HAVE_VOUT | ||
340 | | PMBUS_HAVE_STATUS_VOUT; | ||
341 | data->vout_min[i] = 0xffff; | ||
342 | } | ||
343 | break; | ||
344 | case ltc3880: | ||
345 | info->read_word_data = ltc3880_read_word_data; | ||
346 | info->pages = 2; | ||
347 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | ||
348 | | PMBUS_HAVE_STATUS_INPUT | ||
349 | | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
350 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ||
351 | | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | ||
352 | | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | ||
353 | info->func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
354 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ||
355 | | PMBUS_HAVE_POUT | ||
356 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | ||
357 | data->vout_min[1] = 0xffff; | ||
358 | break; | ||
359 | default: | ||
360 | ret = -ENODEV; | ||
361 | goto err_mem; | ||
362 | } | ||
363 | |||
364 | ret = pmbus_do_probe(client, id, info); | ||
365 | if (ret) | ||
366 | goto err_mem; | ||
367 | return 0; | ||
368 | |||
369 | err_mem: | ||
370 | kfree(data); | ||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | static int ltc2978_remove(struct i2c_client *client) | ||
375 | { | ||
376 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
377 | const struct ltc2978_data *data = to_ltc2978_data(info); | ||
378 | |||
379 | pmbus_do_remove(client); | ||
380 | kfree(data); | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* This is the driver that will be inserted */ | ||
385 | static struct i2c_driver ltc2978_driver = { | ||
386 | .driver = { | ||
387 | .name = "ltc2978", | ||
388 | }, | ||
389 | .probe = ltc2978_probe, | ||
390 | .remove = ltc2978_remove, | ||
391 | .id_table = ltc2978_id, | ||
392 | }; | ||
393 | |||
394 | static int __init ltc2978_init(void) | ||
395 | { | ||
396 | return i2c_add_driver(<c2978_driver); | ||
397 | } | ||
398 | |||
399 | static void __exit ltc2978_exit(void) | ||
400 | { | ||
401 | i2c_del_driver(<c2978_driver); | ||
402 | } | ||
403 | |||
404 | MODULE_AUTHOR("Guenter Roeck"); | ||
405 | MODULE_DESCRIPTION("PMBus driver for LTC2978 and LTC3880"); | ||
406 | MODULE_LICENSE("GPL"); | ||
407 | module_init(ltc2978_init); | ||
408 | module_exit(ltc2978_exit); | ||
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c index e50b296e8db4..1d77cf4d2d44 100644 --- a/drivers/hwmon/pmbus/max16064.c +++ b/drivers/hwmon/pmbus/max16064.c | |||
@@ -105,7 +105,8 @@ static int max16064_probe(struct i2c_client *client, | |||
105 | 105 | ||
106 | static int max16064_remove(struct i2c_client *client) | 106 | static int max16064_remove(struct i2c_client *client) |
107 | { | 107 | { |
108 | return pmbus_do_remove(client); | 108 | pmbus_do_remove(client); |
109 | return 0; | ||
109 | } | 110 | } |
110 | 111 | ||
111 | static const struct i2c_device_id max16064_id[] = { | 112 | static const struct i2c_device_id max16064_id[] = { |
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c index fda621d2e458..beaf5a8d9c45 100644 --- a/drivers/hwmon/pmbus/max34440.c +++ b/drivers/hwmon/pmbus/max34440.c | |||
@@ -93,12 +93,14 @@ static int max34440_write_word_data(struct i2c_client *client, int page, | |||
93 | 93 | ||
94 | static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) | 94 | static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) |
95 | { | 95 | { |
96 | int ret; | 96 | int ret = 0; |
97 | int mfg_status; | 97 | int mfg_status; |
98 | 98 | ||
99 | ret = pmbus_set_page(client, page); | 99 | if (page >= 0) { |
100 | if (ret < 0) | 100 | ret = pmbus_set_page(client, page); |
101 | return ret; | 101 | if (ret < 0) |
102 | return ret; | ||
103 | } | ||
102 | 104 | ||
103 | switch (reg) { | 105 | switch (reg) { |
104 | case PMBUS_STATUS_IOUT: | 106 | case PMBUS_STATUS_IOUT: |
@@ -224,7 +226,8 @@ static int max34440_probe(struct i2c_client *client, | |||
224 | 226 | ||
225 | static int max34440_remove(struct i2c_client *client) | 227 | static int max34440_remove(struct i2c_client *client) |
226 | { | 228 | { |
227 | return pmbus_do_remove(client); | 229 | pmbus_do_remove(client); |
230 | return 0; | ||
228 | } | 231 | } |
229 | 232 | ||
230 | static const struct i2c_device_id max34440_id[] = { | 233 | static const struct i2c_device_id max34440_id[] = { |
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c index c3e72f1a3cfb..e2b74bb399ba 100644 --- a/drivers/hwmon/pmbus/max8688.c +++ b/drivers/hwmon/pmbus/max8688.c | |||
@@ -45,7 +45,7 @@ static int max8688_read_word_data(struct i2c_client *client, int page, int reg) | |||
45 | int ret; | 45 | int ret; |
46 | 46 | ||
47 | if (page) | 47 | if (page) |
48 | return -EINVAL; | 48 | return -ENXIO; |
49 | 49 | ||
50 | switch (reg) { | 50 | switch (reg) { |
51 | case PMBUS_VIRT_READ_VOUT_MAX: | 51 | case PMBUS_VIRT_READ_VOUT_MAX: |
@@ -101,8 +101,8 @@ static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) | |||
101 | int ret = 0; | 101 | int ret = 0; |
102 | int mfg_status; | 102 | int mfg_status; |
103 | 103 | ||
104 | if (page) | 104 | if (page > 0) |
105 | return -EINVAL; | 105 | return -ENXIO; |
106 | 106 | ||
107 | switch (reg) { | 107 | switch (reg) { |
108 | case PMBUS_STATUS_VOUT: | 108 | case PMBUS_STATUS_VOUT: |
@@ -182,7 +182,8 @@ static int max8688_probe(struct i2c_client *client, | |||
182 | 182 | ||
183 | static int max8688_remove(struct i2c_client *client) | 183 | static int max8688_remove(struct i2c_client *client) |
184 | { | 184 | { |
185 | return pmbus_do_remove(client); | 185 | pmbus_do_remove(client); |
186 | return 0; | ||
186 | } | 187 | } |
187 | 188 | ||
188 | static const struct i2c_device_id max8688_id[] = { | 189 | static const struct i2c_device_id max8688_id[] = { |
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 73de9f1f3194..995e873197e3 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c | |||
@@ -187,13 +187,12 @@ out: | |||
187 | 187 | ||
188 | static int pmbus_remove(struct i2c_client *client) | 188 | static int pmbus_remove(struct i2c_client *client) |
189 | { | 189 | { |
190 | int ret; | ||
191 | const struct pmbus_driver_info *info; | 190 | const struct pmbus_driver_info *info; |
192 | 191 | ||
193 | info = pmbus_get_driver_info(client); | 192 | info = pmbus_get_driver_info(client); |
194 | ret = pmbus_do_remove(client); | 193 | pmbus_do_remove(client); |
195 | kfree(info); | 194 | kfree(info); |
196 | return ret; | 195 | return 0; |
197 | } | 196 | } |
198 | 197 | ||
199 | /* | 198 | /* |
@@ -205,10 +204,13 @@ static const struct i2c_device_id pmbus_id[] = { | |||
205 | {"bmr451", 1}, | 204 | {"bmr451", 1}, |
206 | {"bmr453", 1}, | 205 | {"bmr453", 1}, |
207 | {"bmr454", 1}, | 206 | {"bmr454", 1}, |
208 | {"ltc2978", 8}, | ||
209 | {"ncp4200", 1}, | 207 | {"ncp4200", 1}, |
210 | {"ncp4208", 1}, | 208 | {"ncp4208", 1}, |
209 | {"pdt003", 1}, | ||
210 | {"pdt006", 1}, | ||
211 | {"pdt012", 1}, | ||
211 | {"pmbus", 0}, | 212 | {"pmbus", 0}, |
213 | {"udt020", 1}, | ||
212 | {} | 214 | {} |
213 | }; | 215 | }; |
214 | 216 | ||
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index a6ae20ffef6b..5d31d1c2c0f5 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h | |||
@@ -134,8 +134,16 @@ | |||
134 | * Semantics: | 134 | * Semantics: |
135 | * Virtual registers are all word size. | 135 | * Virtual registers are all word size. |
136 | * READ registers are read-only; writes are either ignored or return an error. | 136 | * READ registers are read-only; writes are either ignored or return an error. |
137 | * RESET registers are read/write. Reading returns zero (used for detection), | 137 | * RESET registers are read/write. Reading reset registers returns zero |
138 | * writing any value causes the associated history to be reset. | 138 | * (used for detection), writing any value causes the associated history to be |
139 | * reset. | ||
140 | * Virtual registers have to be handled in device specific driver code. Chip | ||
141 | * driver code returns non-negative register values if a virtual register is | ||
142 | * supported, or a negative error code if not. The chip driver may return | ||
143 | * -ENODATA or any other error code in this case, though an error code other | ||
144 | * than -ENODATA is handled more efficiently and thus preferred. Either case, | ||
145 | * the calling PMBus core code will abort if the chip driver returns an error | ||
146 | * code when reading or writing virtual registers. | ||
139 | */ | 147 | */ |
140 | #define PMBUS_VIRT_BASE 0x100 | 148 | #define PMBUS_VIRT_BASE 0x100 |
141 | #define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0) | 149 | #define PMBUS_VIRT_READ_TEMP_MIN (PMBUS_VIRT_BASE + 0) |
@@ -160,6 +168,9 @@ | |||
160 | #define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19) | 168 | #define PMBUS_VIRT_READ_IOUT_MIN (PMBUS_VIRT_BASE + 19) |
161 | #define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20) | 169 | #define PMBUS_VIRT_READ_IOUT_MAX (PMBUS_VIRT_BASE + 20) |
162 | #define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21) | 170 | #define PMBUS_VIRT_RESET_IOUT_HISTORY (PMBUS_VIRT_BASE + 21) |
171 | #define PMBUS_VIRT_READ_TEMP2_MIN (PMBUS_VIRT_BASE + 22) | ||
172 | #define PMBUS_VIRT_READ_TEMP2_MAX (PMBUS_VIRT_BASE + 23) | ||
173 | #define PMBUS_VIRT_RESET_TEMP2_HISTORY (PMBUS_VIRT_BASE + 24) | ||
163 | 174 | ||
164 | /* | 175 | /* |
165 | * CAPABILITY | 176 | * CAPABILITY |
@@ -320,6 +331,12 @@ struct pmbus_driver_info { | |||
320 | * The following functions map manufacturing specific register values | 331 | * The following functions map manufacturing specific register values |
321 | * to PMBus standard register values. Specify only if mapping is | 332 | * to PMBus standard register values. Specify only if mapping is |
322 | * necessary. | 333 | * necessary. |
334 | * Functions return the register value (read) or zero (write) if | ||
335 | * successful. A return value of -ENODATA indicates that there is no | ||
336 | * manufacturer specific register, but that a standard PMBus register | ||
337 | * may exist. Any other negative return value indicates that the | ||
338 | * register does not exist, and that no attempt should be made to read | ||
339 | * the standard register. | ||
323 | */ | 340 | */ |
324 | int (*read_byte_data)(struct i2c_client *client, int page, int reg); | 341 | int (*read_byte_data)(struct i2c_client *client, int page, int reg); |
325 | int (*read_word_data)(struct i2c_client *client, int page, int reg); | 342 | int (*read_word_data)(struct i2c_client *client, int page, int reg); |
@@ -347,7 +364,7 @@ bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); | |||
347 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); | 364 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); |
348 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | 365 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, |
349 | struct pmbus_driver_info *info); | 366 | struct pmbus_driver_info *info); |
350 | int pmbus_do_remove(struct i2c_client *client); | 367 | void pmbus_do_remove(struct i2c_client *client); |
351 | const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client | 368 | const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client |
352 | *client); | 369 | *client); |
353 | 370 | ||
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 397fc59b5682..00460d8d8423 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c | |||
@@ -160,7 +160,7 @@ int pmbus_set_page(struct i2c_client *client, u8 page) | |||
160 | rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); | 160 | rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); |
161 | newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE); | 161 | newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE); |
162 | if (newpage != page) | 162 | if (newpage != page) |
163 | rv = -EINVAL; | 163 | rv = -EIO; |
164 | else | 164 | else |
165 | data->currpage = page; | 165 | data->currpage = page; |
166 | } | 166 | } |
@@ -229,7 +229,7 @@ static int _pmbus_write_word_data(struct i2c_client *client, int page, int reg, | |||
229 | return status; | 229 | return status; |
230 | } | 230 | } |
231 | if (reg >= PMBUS_VIRT_BASE) | 231 | if (reg >= PMBUS_VIRT_BASE) |
232 | return -EINVAL; | 232 | return -ENXIO; |
233 | return pmbus_write_word_data(client, page, reg, word); | 233 | return pmbus_write_word_data(client, page, reg, word); |
234 | } | 234 | } |
235 | 235 | ||
@@ -261,7 +261,7 @@ static int _pmbus_read_word_data(struct i2c_client *client, int page, int reg) | |||
261 | return status; | 261 | return status; |
262 | } | 262 | } |
263 | if (reg >= PMBUS_VIRT_BASE) | 263 | if (reg >= PMBUS_VIRT_BASE) |
264 | return -EINVAL; | 264 | return -ENXIO; |
265 | return pmbus_read_word_data(client, page, reg); | 265 | return pmbus_read_word_data(client, page, reg); |
266 | } | 266 | } |
267 | 267 | ||
@@ -316,11 +316,11 @@ static int pmbus_check_status_cml(struct i2c_client *client) | |||
316 | { | 316 | { |
317 | int status, status2; | 317 | int status, status2; |
318 | 318 | ||
319 | status = pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE); | 319 | status = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_BYTE); |
320 | if (status < 0 || (status & PB_STATUS_CML)) { | 320 | if (status < 0 || (status & PB_STATUS_CML)) { |
321 | status2 = pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); | 321 | status2 = _pmbus_read_byte_data(client, -1, PMBUS_STATUS_CML); |
322 | if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) | 322 | if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) |
323 | return -EINVAL; | 323 | return -EIO; |
324 | } | 324 | } |
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
@@ -371,8 +371,8 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) | |||
371 | 371 | ||
372 | for (i = 0; i < info->pages; i++) | 372 | for (i = 0; i < info->pages; i++) |
373 | data->status[PB_STATUS_BASE + i] | 373 | data->status[PB_STATUS_BASE + i] |
374 | = pmbus_read_byte_data(client, i, | 374 | = _pmbus_read_byte_data(client, i, |
375 | PMBUS_STATUS_BYTE); | 375 | PMBUS_STATUS_BYTE); |
376 | for (i = 0; i < info->pages; i++) { | 376 | for (i = 0; i < info->pages; i++) { |
377 | if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT)) | 377 | if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT)) |
378 | continue; | 378 | continue; |
@@ -445,13 +445,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, | |||
445 | exponent = data->exponent; | 445 | exponent = data->exponent; |
446 | mantissa = (u16) sensor->data; | 446 | mantissa = (u16) sensor->data; |
447 | } else { /* LINEAR11 */ | 447 | } else { /* LINEAR11 */ |
448 | exponent = (sensor->data >> 11) & 0x001f; | 448 | exponent = ((s16)sensor->data) >> 11; |
449 | mantissa = sensor->data & 0x07ff; | 449 | mantissa = ((s16)((sensor->data & 0x7ff) << 5)) >> 5; |
450 | |||
451 | if (exponent > 0x0f) | ||
452 | exponent |= 0xffe0; /* sign extend exponent */ | ||
453 | if (mantissa > 0x03ff) | ||
454 | mantissa |= 0xfffff800; /* sign extend mantissa */ | ||
455 | } | 450 | } |
456 | 451 | ||
457 | val = mantissa; | 452 | val = mantissa; |
@@ -1401,7 +1396,42 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { | |||
1401 | } | 1396 | } |
1402 | }; | 1397 | }; |
1403 | 1398 | ||
1404 | static const struct pmbus_limit_attr temp_limit_attrs23[] = { | 1399 | static const struct pmbus_limit_attr temp_limit_attrs2[] = { |
1400 | { | ||
1401 | .reg = PMBUS_UT_WARN_LIMIT, | ||
1402 | .low = true, | ||
1403 | .attr = "min", | ||
1404 | .alarm = "min_alarm", | ||
1405 | .sbit = PB_TEMP_UT_WARNING, | ||
1406 | }, { | ||
1407 | .reg = PMBUS_UT_FAULT_LIMIT, | ||
1408 | .low = true, | ||
1409 | .attr = "lcrit", | ||
1410 | .alarm = "lcrit_alarm", | ||
1411 | .sbit = PB_TEMP_UT_FAULT, | ||
1412 | }, { | ||
1413 | .reg = PMBUS_OT_WARN_LIMIT, | ||
1414 | .attr = "max", | ||
1415 | .alarm = "max_alarm", | ||
1416 | .sbit = PB_TEMP_OT_WARNING, | ||
1417 | }, { | ||
1418 | .reg = PMBUS_OT_FAULT_LIMIT, | ||
1419 | .attr = "crit", | ||
1420 | .alarm = "crit_alarm", | ||
1421 | .sbit = PB_TEMP_OT_FAULT, | ||
1422 | }, { | ||
1423 | .reg = PMBUS_VIRT_READ_TEMP2_MIN, | ||
1424 | .attr = "lowest", | ||
1425 | }, { | ||
1426 | .reg = PMBUS_VIRT_READ_TEMP2_MAX, | ||
1427 | .attr = "highest", | ||
1428 | }, { | ||
1429 | .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, | ||
1430 | .attr = "reset_history", | ||
1431 | } | ||
1432 | }; | ||
1433 | |||
1434 | static const struct pmbus_limit_attr temp_limit_attrs3[] = { | ||
1405 | { | 1435 | { |
1406 | .reg = PMBUS_UT_WARN_LIMIT, | 1436 | .reg = PMBUS_UT_WARN_LIMIT, |
1407 | .low = true, | 1437 | .low = true, |
@@ -1450,8 +1480,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = { | |||
1450 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | 1480 | .sfunc = PMBUS_HAVE_STATUS_TEMP, |
1451 | .sbase = PB_STATUS_TEMP_BASE, | 1481 | .sbase = PB_STATUS_TEMP_BASE, |
1452 | .gbit = PB_STATUS_TEMPERATURE, | 1482 | .gbit = PB_STATUS_TEMPERATURE, |
1453 | .limit = temp_limit_attrs23, | 1483 | .limit = temp_limit_attrs2, |
1454 | .nlimit = ARRAY_SIZE(temp_limit_attrs23), | 1484 | .nlimit = ARRAY_SIZE(temp_limit_attrs2), |
1455 | }, { | 1485 | }, { |
1456 | .reg = PMBUS_READ_TEMPERATURE_3, | 1486 | .reg = PMBUS_READ_TEMPERATURE_3, |
1457 | .class = PSC_TEMPERATURE, | 1487 | .class = PSC_TEMPERATURE, |
@@ -1462,8 +1492,8 @@ static const struct pmbus_sensor_attr temp_attributes[] = { | |||
1462 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | 1492 | .sfunc = PMBUS_HAVE_STATUS_TEMP, |
1463 | .sbase = PB_STATUS_TEMP_BASE, | 1493 | .sbase = PB_STATUS_TEMP_BASE, |
1464 | .gbit = PB_STATUS_TEMPERATURE, | 1494 | .gbit = PB_STATUS_TEMPERATURE, |
1465 | .limit = temp_limit_attrs23, | 1495 | .limit = temp_limit_attrs3, |
1466 | .nlimit = ARRAY_SIZE(temp_limit_attrs23), | 1496 | .nlimit = ARRAY_SIZE(temp_limit_attrs3), |
1467 | } | 1497 | } |
1468 | }; | 1498 | }; |
1469 | 1499 | ||
@@ -1593,10 +1623,10 @@ static void pmbus_find_attributes(struct i2c_client *client, | |||
1593 | static int pmbus_identify_common(struct i2c_client *client, | 1623 | static int pmbus_identify_common(struct i2c_client *client, |
1594 | struct pmbus_data *data) | 1624 | struct pmbus_data *data) |
1595 | { | 1625 | { |
1596 | int vout_mode = -1, exponent; | 1626 | int vout_mode = -1; |
1597 | 1627 | ||
1598 | if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) | 1628 | if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) |
1599 | vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); | 1629 | vout_mode = _pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); |
1600 | if (vout_mode >= 0 && vout_mode != 0xff) { | 1630 | if (vout_mode >= 0 && vout_mode != 0xff) { |
1601 | /* | 1631 | /* |
1602 | * Not all chips support the VOUT_MODE command, | 1632 | * Not all chips support the VOUT_MODE command, |
@@ -1607,11 +1637,7 @@ static int pmbus_identify_common(struct i2c_client *client, | |||
1607 | if (data->info->format[PSC_VOLTAGE_OUT] != linear) | 1637 | if (data->info->format[PSC_VOLTAGE_OUT] != linear) |
1608 | return -ENODEV; | 1638 | return -ENODEV; |
1609 | 1639 | ||
1610 | exponent = vout_mode & 0x1f; | 1640 | data->exponent = ((s8)(vout_mode << 3)) >> 3; |
1611 | /* and sign-extend it */ | ||
1612 | if (exponent & 0x10) | ||
1613 | exponent |= ~0x1f; | ||
1614 | data->exponent = exponent; | ||
1615 | break; | 1641 | break; |
1616 | case 1: /* VID mode */ | 1642 | case 1: /* VID mode */ |
1617 | if (data->info->format[PSC_VOLTAGE_OUT] != vid) | 1643 | if (data->info->format[PSC_VOLTAGE_OUT] != vid) |
@@ -1682,7 +1708,7 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | |||
1682 | if (info->pages <= 0 || info->pages > PMBUS_PAGES) { | 1708 | if (info->pages <= 0 || info->pages > PMBUS_PAGES) { |
1683 | dev_err(&client->dev, "Bad number of PMBus pages: %d\n", | 1709 | dev_err(&client->dev, "Bad number of PMBus pages: %d\n", |
1684 | info->pages); | 1710 | info->pages); |
1685 | ret = -EINVAL; | 1711 | ret = -ENODEV; |
1686 | goto out_data; | 1712 | goto out_data; |
1687 | } | 1713 | } |
1688 | 1714 | ||
@@ -1764,7 +1790,7 @@ out_data: | |||
1764 | } | 1790 | } |
1765 | EXPORT_SYMBOL_GPL(pmbus_do_probe); | 1791 | EXPORT_SYMBOL_GPL(pmbus_do_probe); |
1766 | 1792 | ||
1767 | int pmbus_do_remove(struct i2c_client *client) | 1793 | void pmbus_do_remove(struct i2c_client *client) |
1768 | { | 1794 | { |
1769 | struct pmbus_data *data = i2c_get_clientdata(client); | 1795 | struct pmbus_data *data = i2c_get_clientdata(client); |
1770 | hwmon_device_unregister(data->hwmon_dev); | 1796 | hwmon_device_unregister(data->hwmon_dev); |
@@ -1774,7 +1800,6 @@ int pmbus_do_remove(struct i2c_client *client) | |||
1774 | kfree(data->booleans); | 1800 | kfree(data->booleans); |
1775 | kfree(data->sensors); | 1801 | kfree(data->sensors); |
1776 | kfree(data); | 1802 | kfree(data); |
1777 | return 0; | ||
1778 | } | 1803 | } |
1779 | EXPORT_SYMBOL_GPL(pmbus_do_remove); | 1804 | EXPORT_SYMBOL_GPL(pmbus_do_remove); |
1780 | 1805 | ||
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index d0ddb60155c9..4ff6cf289f85 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c | |||
@@ -74,8 +74,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) | |||
74 | 74 | ||
75 | switch (reg) { | 75 | switch (reg) { |
76 | case PMBUS_FAN_CONFIG_12: | 76 | case PMBUS_FAN_CONFIG_12: |
77 | if (page) | 77 | if (page > 0) |
78 | return -EINVAL; | 78 | return -ENXIO; |
79 | 79 | ||
80 | ret = ucd9000_get_fan_config(client, 0); | 80 | ret = ucd9000_get_fan_config(client, 0); |
81 | if (ret < 0) | 81 | if (ret < 0) |
@@ -88,8 +88,8 @@ static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) | |||
88 | ret = fan_config; | 88 | ret = fan_config; |
89 | break; | 89 | break; |
90 | case PMBUS_FAN_CONFIG_34: | 90 | case PMBUS_FAN_CONFIG_34: |
91 | if (page) | 91 | if (page > 0) |
92 | return -EINVAL; | 92 | return -ENXIO; |
93 | 93 | ||
94 | ret = ucd9000_get_fan_config(client, 2); | 94 | ret = ucd9000_get_fan_config(client, 2); |
95 | if (ret < 0) | 95 | if (ret < 0) |
@@ -239,13 +239,12 @@ out: | |||
239 | 239 | ||
240 | static int ucd9000_remove(struct i2c_client *client) | 240 | static int ucd9000_remove(struct i2c_client *client) |
241 | { | 241 | { |
242 | int ret; | ||
243 | struct ucd9000_data *data; | 242 | struct ucd9000_data *data; |
244 | 243 | ||
245 | data = to_ucd9000_data(pmbus_get_driver_info(client)); | 244 | data = to_ucd9000_data(pmbus_get_driver_info(client)); |
246 | ret = pmbus_do_remove(client); | 245 | pmbus_do_remove(client); |
247 | kfree(data); | 246 | kfree(data); |
248 | return ret; | 247 | return 0; |
249 | } | 248 | } |
250 | 249 | ||
251 | 250 | ||
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index c65e9da707cc..6e1c1a80ab85 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c | |||
@@ -171,13 +171,12 @@ out: | |||
171 | 171 | ||
172 | static int ucd9200_remove(struct i2c_client *client) | 172 | static int ucd9200_remove(struct i2c_client *client) |
173 | { | 173 | { |
174 | int ret; | ||
175 | const struct pmbus_driver_info *info; | 174 | const struct pmbus_driver_info *info; |
176 | 175 | ||
177 | info = pmbus_get_driver_info(client); | 176 | info = pmbus_get_driver_info(client); |
178 | ret = pmbus_do_remove(client); | 177 | pmbus_do_remove(client); |
179 | kfree(info); | 178 | kfree(info); |
180 | return ret; | 179 | return 0; |
181 | } | 180 | } |
182 | 181 | ||
183 | 182 | ||
diff --git a/drivers/hwmon/pmbus/zl6100.c b/drivers/hwmon/pmbus/zl6100.c new file mode 100644 index 000000000000..2bc980006f83 --- /dev/null +++ b/drivers/hwmon/pmbus/zl6100.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for ZL6100 and compatibles | ||
3 | * | ||
4 | * Copyright (c) 2011 Ericsson AB. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/ktime.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include "pmbus.h" | ||
30 | |||
31 | enum chips { zl2004, zl2006, zl2008, zl2105, zl2106, zl6100, zl6105 }; | ||
32 | |||
33 | struct zl6100_data { | ||
34 | int id; | ||
35 | ktime_t access; /* chip access time */ | ||
36 | struct pmbus_driver_info info; | ||
37 | }; | ||
38 | |||
39 | #define to_zl6100_data(x) container_of(x, struct zl6100_data, info) | ||
40 | |||
41 | #define ZL6100_DEVICE_ID 0xe4 | ||
42 | |||
43 | #define ZL6100_WAIT_TIME 1000 /* uS */ | ||
44 | |||
45 | static ushort delay = ZL6100_WAIT_TIME; | ||
46 | module_param(delay, ushort, 0644); | ||
47 | MODULE_PARM_DESC(delay, "Delay between chip accesses in uS"); | ||
48 | |||
49 | /* Some chips need a delay between accesses */ | ||
50 | static inline void zl6100_wait(const struct zl6100_data *data) | ||
51 | { | ||
52 | if (delay) { | ||
53 | s64 delta = ktime_us_delta(ktime_get(), data->access); | ||
54 | if (delta < delay) | ||
55 | udelay(delay - delta); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | static int zl6100_read_word_data(struct i2c_client *client, int page, int reg) | ||
60 | { | ||
61 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
62 | struct zl6100_data *data = to_zl6100_data(info); | ||
63 | int ret; | ||
64 | |||
65 | if (page || reg >= PMBUS_VIRT_BASE) | ||
66 | return -ENXIO; | ||
67 | |||
68 | zl6100_wait(data); | ||
69 | ret = pmbus_read_word_data(client, page, reg); | ||
70 | data->access = ktime_get(); | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static int zl6100_read_byte_data(struct i2c_client *client, int page, int reg) | ||
76 | { | ||
77 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
78 | struct zl6100_data *data = to_zl6100_data(info); | ||
79 | int ret; | ||
80 | |||
81 | if (page > 0) | ||
82 | return -ENXIO; | ||
83 | |||
84 | zl6100_wait(data); | ||
85 | ret = pmbus_read_byte_data(client, page, reg); | ||
86 | data->access = ktime_get(); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | static int zl6100_write_word_data(struct i2c_client *client, int page, int reg, | ||
92 | u16 word) | ||
93 | { | ||
94 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
95 | struct zl6100_data *data = to_zl6100_data(info); | ||
96 | int ret; | ||
97 | |||
98 | if (page || reg >= PMBUS_VIRT_BASE) | ||
99 | return -ENXIO; | ||
100 | |||
101 | zl6100_wait(data); | ||
102 | ret = pmbus_write_word_data(client, page, reg, word); | ||
103 | data->access = ktime_get(); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | static int zl6100_write_byte(struct i2c_client *client, int page, u8 value) | ||
109 | { | ||
110 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
111 | struct zl6100_data *data = to_zl6100_data(info); | ||
112 | int ret; | ||
113 | |||
114 | if (page > 0) | ||
115 | return -ENXIO; | ||
116 | |||
117 | zl6100_wait(data); | ||
118 | ret = pmbus_write_byte(client, page, value); | ||
119 | data->access = ktime_get(); | ||
120 | |||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | static const struct i2c_device_id zl6100_id[] = { | ||
125 | {"zl2004", zl2004}, | ||
126 | {"zl2006", zl2006}, | ||
127 | {"zl2008", zl2008}, | ||
128 | {"zl2105", zl2105}, | ||
129 | {"zl2106", zl2106}, | ||
130 | {"zl6100", zl6100}, | ||
131 | {"zl6105", zl6105}, | ||
132 | { } | ||
133 | }; | ||
134 | MODULE_DEVICE_TABLE(i2c, zl6100_id); | ||
135 | |||
136 | static int zl6100_probe(struct i2c_client *client, | ||
137 | const struct i2c_device_id *id) | ||
138 | { | ||
139 | int ret; | ||
140 | struct zl6100_data *data; | ||
141 | struct pmbus_driver_info *info; | ||
142 | u8 device_id[I2C_SMBUS_BLOCK_MAX + 1]; | ||
143 | const struct i2c_device_id *mid; | ||
144 | |||
145 | if (!i2c_check_functionality(client->adapter, | ||
146 | I2C_FUNC_SMBUS_READ_BYTE_DATA | ||
147 | | I2C_FUNC_SMBUS_READ_BLOCK_DATA)) | ||
148 | return -ENODEV; | ||
149 | |||
150 | ret = i2c_smbus_read_block_data(client, ZL6100_DEVICE_ID, | ||
151 | device_id); | ||
152 | if (ret < 0) { | ||
153 | dev_err(&client->dev, "Failed to read device ID\n"); | ||
154 | return ret; | ||
155 | } | ||
156 | device_id[ret] = '\0'; | ||
157 | dev_info(&client->dev, "Device ID %s\n", device_id); | ||
158 | |||
159 | mid = NULL; | ||
160 | for (mid = zl6100_id; mid->name[0]; mid++) { | ||
161 | if (!strncasecmp(mid->name, device_id, strlen(mid->name))) | ||
162 | break; | ||
163 | } | ||
164 | if (!mid->name[0]) { | ||
165 | dev_err(&client->dev, "Unsupported device\n"); | ||
166 | return -ENODEV; | ||
167 | } | ||
168 | if (id->driver_data != mid->driver_data) | ||
169 | dev_notice(&client->dev, | ||
170 | "Device mismatch: Configured %s, detected %s\n", | ||
171 | id->name, mid->name); | ||
172 | |||
173 | data = kzalloc(sizeof(struct zl6100_data), GFP_KERNEL); | ||
174 | if (!data) | ||
175 | return -ENOMEM; | ||
176 | |||
177 | data->id = mid->driver_data; | ||
178 | |||
179 | /* | ||
180 | * ZL2008, ZL2105, and ZL6100 are known to require a wait time | ||
181 | * between I2C accesses. ZL2004 and ZL6105 are known to be safe. | ||
182 | * | ||
183 | * Only clear the wait time for chips known to be safe. The wait time | ||
184 | * can be cleared later for additional chips if tests show that it | ||
185 | * is not needed (in other words, better be safe than sorry). | ||
186 | */ | ||
187 | if (data->id == zl2004 || data->id == zl6105) | ||
188 | delay = 0; | ||
189 | |||
190 | /* | ||
191 | * Since there was a direct I2C device access above, wait before | ||
192 | * accessing the chip again. | ||
193 | * Set the timestamp, wait, then set it again. This should provide | ||
194 | * enough buffer time to be safe. | ||
195 | */ | ||
196 | data->access = ktime_get(); | ||
197 | zl6100_wait(data); | ||
198 | data->access = ktime_get(); | ||
199 | |||
200 | info = &data->info; | ||
201 | |||
202 | info->pages = 1; | ||
203 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | ||
204 | | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
205 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | ||
206 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | ||
207 | |||
208 | info->read_word_data = zl6100_read_word_data; | ||
209 | info->read_byte_data = zl6100_read_byte_data; | ||
210 | info->write_word_data = zl6100_write_word_data; | ||
211 | info->write_byte = zl6100_write_byte; | ||
212 | |||
213 | ret = pmbus_do_probe(client, mid, info); | ||
214 | if (ret) | ||
215 | goto err_mem; | ||
216 | return 0; | ||
217 | |||
218 | err_mem: | ||
219 | kfree(data); | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static int zl6100_remove(struct i2c_client *client) | ||
224 | { | ||
225 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
226 | const struct zl6100_data *data = to_zl6100_data(info); | ||
227 | |||
228 | pmbus_do_remove(client); | ||
229 | kfree(data); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static struct i2c_driver zl6100_driver = { | ||
234 | .driver = { | ||
235 | .name = "zl6100", | ||
236 | }, | ||
237 | .probe = zl6100_probe, | ||
238 | .remove = zl6100_remove, | ||
239 | .id_table = zl6100_id, | ||
240 | }; | ||
241 | |||
242 | static int __init zl6100_init(void) | ||
243 | { | ||
244 | return i2c_add_driver(&zl6100_driver); | ||
245 | } | ||
246 | |||
247 | static void __exit zl6100_exit(void) | ||
248 | { | ||
249 | i2c_del_driver(&zl6100_driver); | ||
250 | } | ||
251 | |||
252 | MODULE_AUTHOR("Guenter Roeck"); | ||
253 | MODULE_DESCRIPTION("PMBus driver for ZL6100 and compatibles"); | ||
254 | MODULE_LICENSE("GPL"); | ||
255 | module_init(zl6100_init); | ||
256 | module_exit(zl6100_exit); | ||
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 36d7f270b14d..98aab4bea342 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -197,6 +197,9 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 }; | |||
197 | #define W83627EHF_REG_ALARM2 0x45A | 197 | #define W83627EHF_REG_ALARM2 0x45A |
198 | #define W83627EHF_REG_ALARM3 0x45B | 198 | #define W83627EHF_REG_ALARM3 0x45B |
199 | 199 | ||
200 | #define W83627EHF_REG_CASEOPEN_DET 0x42 /* SMI STATUS #2 */ | ||
201 | #define W83627EHF_REG_CASEOPEN_CLR 0x46 /* SMI MASK #3 */ | ||
202 | |||
200 | /* SmartFan registers */ | 203 | /* SmartFan registers */ |
201 | #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f | 204 | #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f |
202 | #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e | 205 | #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e |
@@ -316,7 +319,7 @@ static const char *const nct6776_temp_label[] = { | |||
316 | 319 | ||
317 | #define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP) | 320 | #define NUM_REG_TEMP ARRAY_SIZE(NCT6775_REG_TEMP) |
318 | 321 | ||
319 | static inline int is_word_sized(u16 reg) | 322 | static int is_word_sized(u16 reg) |
320 | { | 323 | { |
321 | return ((((reg & 0xff00) == 0x100 | 324 | return ((((reg & 0xff00) == 0x100 |
322 | || (reg & 0xff00) == 0x200) | 325 | || (reg & 0xff00) == 0x200) |
@@ -385,23 +388,6 @@ div_from_reg(u8 reg) | |||
385 | return 1 << reg; | 388 | return 1 << reg; |
386 | } | 389 | } |
387 | 390 | ||
388 | static inline int | ||
389 | temp_from_reg(u16 reg, s16 regval) | ||
390 | { | ||
391 | if (is_word_sized(reg)) | ||
392 | return LM75_TEMP_FROM_REG(regval); | ||
393 | return ((s8)regval) * 1000; | ||
394 | } | ||
395 | |||
396 | static inline u16 | ||
397 | temp_to_reg(u16 reg, long temp) | ||
398 | { | ||
399 | if (is_word_sized(reg)) | ||
400 | return LM75_TEMP_TO_REG(temp); | ||
401 | return (s8)DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), | ||
402 | 1000); | ||
403 | } | ||
404 | |||
405 | /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ | 391 | /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */ |
406 | 392 | ||
407 | static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; | 393 | static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 }; |
@@ -469,6 +455,7 @@ struct w83627ehf_data { | |||
469 | s16 temp_max[9]; | 455 | s16 temp_max[9]; |
470 | s16 temp_max_hyst[9]; | 456 | s16 temp_max_hyst[9]; |
471 | u32 alarms; | 457 | u32 alarms; |
458 | u8 caseopen; | ||
472 | 459 | ||
473 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ | 460 | u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */ |
474 | u8 pwm_enable[4]; /* 1->manual | 461 | u8 pwm_enable[4]; /* 1->manual |
@@ -557,6 +544,26 @@ static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, | |||
557 | return 0; | 544 | return 0; |
558 | } | 545 | } |
559 | 546 | ||
547 | /* We left-align 8-bit temperature values to make the code simpler */ | ||
548 | static u16 w83627ehf_read_temp(struct w83627ehf_data *data, u16 reg) | ||
549 | { | ||
550 | u16 res; | ||
551 | |||
552 | res = w83627ehf_read_value(data, reg); | ||
553 | if (!is_word_sized(reg)) | ||
554 | res <<= 8; | ||
555 | |||
556 | return res; | ||
557 | } | ||
558 | |||
559 | static int w83627ehf_write_temp(struct w83627ehf_data *data, u16 reg, | ||
560 | u16 value) | ||
561 | { | ||
562 | if (!is_word_sized(reg)) | ||
563 | value >>= 8; | ||
564 | return w83627ehf_write_value(data, reg, value); | ||
565 | } | ||
566 | |||
560 | /* This function assumes that the caller holds data->update_lock */ | 567 | /* This function assumes that the caller holds data->update_lock */ |
561 | static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr) | 568 | static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr) |
562 | { | 569 | { |
@@ -771,6 +778,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
771 | 778 | ||
772 | /* Measured voltages and limits */ | 779 | /* Measured voltages and limits */ |
773 | for (i = 0; i < data->in_num; i++) { | 780 | for (i = 0; i < data->in_num; i++) { |
781 | if ((i == 6) && data->in6_skip) | ||
782 | continue; | ||
783 | |||
774 | data->in[i] = w83627ehf_read_value(data, | 784 | data->in[i] = w83627ehf_read_value(data, |
775 | W83627EHF_REG_IN(i)); | 785 | W83627EHF_REG_IN(i)); |
776 | data->in_min[i] = w83627ehf_read_value(data, | 786 | data->in_min[i] = w83627ehf_read_value(data, |
@@ -855,15 +865,15 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
855 | for (i = 0; i < NUM_REG_TEMP; i++) { | 865 | for (i = 0; i < NUM_REG_TEMP; i++) { |
856 | if (!(data->have_temp & (1 << i))) | 866 | if (!(data->have_temp & (1 << i))) |
857 | continue; | 867 | continue; |
858 | data->temp[i] = w83627ehf_read_value(data, | 868 | data->temp[i] = w83627ehf_read_temp(data, |
859 | data->reg_temp[i]); | 869 | data->reg_temp[i]); |
860 | if (data->reg_temp_over[i]) | 870 | if (data->reg_temp_over[i]) |
861 | data->temp_max[i] | 871 | data->temp_max[i] |
862 | = w83627ehf_read_value(data, | 872 | = w83627ehf_read_temp(data, |
863 | data->reg_temp_over[i]); | 873 | data->reg_temp_over[i]); |
864 | if (data->reg_temp_hyst[i]) | 874 | if (data->reg_temp_hyst[i]) |
865 | data->temp_max_hyst[i] | 875 | data->temp_max_hyst[i] |
866 | = w83627ehf_read_value(data, | 876 | = w83627ehf_read_temp(data, |
867 | data->reg_temp_hyst[i]); | 877 | data->reg_temp_hyst[i]); |
868 | } | 878 | } |
869 | 879 | ||
@@ -874,6 +884,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) | |||
874 | (w83627ehf_read_value(data, | 884 | (w83627ehf_read_value(data, |
875 | W83627EHF_REG_ALARM3) << 16); | 885 | W83627EHF_REG_ALARM3) << 16); |
876 | 886 | ||
887 | data->caseopen = w83627ehf_read_value(data, | ||
888 | W83627EHF_REG_CASEOPEN_DET); | ||
889 | |||
877 | data->last_updated = jiffies; | 890 | data->last_updated = jiffies; |
878 | data->valid = 1; | 891 | data->valid = 1; |
879 | } | 892 | } |
@@ -1156,8 +1169,7 @@ show_##reg(struct device *dev, struct device_attribute *attr, \ | |||
1156 | struct sensor_device_attribute *sensor_attr = \ | 1169 | struct sensor_device_attribute *sensor_attr = \ |
1157 | to_sensor_dev_attr(attr); \ | 1170 | to_sensor_dev_attr(attr); \ |
1158 | int nr = sensor_attr->index; \ | 1171 | int nr = sensor_attr->index; \ |
1159 | return sprintf(buf, "%d\n", \ | 1172 | return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->reg[nr])); \ |
1160 | temp_from_reg(data->addr[nr], data->reg[nr])); \ | ||
1161 | } | 1173 | } |
1162 | show_temp_reg(reg_temp, temp); | 1174 | show_temp_reg(reg_temp, temp); |
1163 | show_temp_reg(reg_temp_over, temp_max); | 1175 | show_temp_reg(reg_temp_over, temp_max); |
@@ -1178,9 +1190,8 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ | |||
1178 | if (err < 0) \ | 1190 | if (err < 0) \ |
1179 | return err; \ | 1191 | return err; \ |
1180 | mutex_lock(&data->update_lock); \ | 1192 | mutex_lock(&data->update_lock); \ |
1181 | data->reg[nr] = temp_to_reg(data->addr[nr], val); \ | 1193 | data->reg[nr] = LM75_TEMP_TO_REG(val); \ |
1182 | w83627ehf_write_value(data, data->addr[nr], \ | 1194 | w83627ehf_write_temp(data, data->addr[nr], data->reg[nr]); \ |
1183 | data->reg[nr]); \ | ||
1184 | mutex_unlock(&data->update_lock); \ | 1195 | mutex_unlock(&data->update_lock); \ |
1185 | return count; \ | 1196 | return count; \ |
1186 | } | 1197 | } |
@@ -1655,6 +1666,48 @@ show_vid(struct device *dev, struct device_attribute *attr, char *buf) | |||
1655 | } | 1666 | } |
1656 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | 1667 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); |
1657 | 1668 | ||
1669 | |||
1670 | /* Case open detection */ | ||
1671 | |||
1672 | static ssize_t | ||
1673 | show_caseopen(struct device *dev, struct device_attribute *attr, char *buf) | ||
1674 | { | ||
1675 | struct w83627ehf_data *data = w83627ehf_update_device(dev); | ||
1676 | |||
1677 | return sprintf(buf, "%d\n", | ||
1678 | !!(data->caseopen & to_sensor_dev_attr_2(attr)->index)); | ||
1679 | } | ||
1680 | |||
1681 | static ssize_t | ||
1682 | clear_caseopen(struct device *dev, struct device_attribute *attr, | ||
1683 | const char *buf, size_t count) | ||
1684 | { | ||
1685 | struct w83627ehf_data *data = dev_get_drvdata(dev); | ||
1686 | unsigned long val; | ||
1687 | u16 reg, mask; | ||
1688 | |||
1689 | if (strict_strtoul(buf, 10, &val) || val != 0) | ||
1690 | return -EINVAL; | ||
1691 | |||
1692 | mask = to_sensor_dev_attr_2(attr)->nr; | ||
1693 | |||
1694 | mutex_lock(&data->update_lock); | ||
1695 | reg = w83627ehf_read_value(data, W83627EHF_REG_CASEOPEN_CLR); | ||
1696 | w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg | mask); | ||
1697 | w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg & ~mask); | ||
1698 | data->valid = 0; /* Force cache refresh */ | ||
1699 | mutex_unlock(&data->update_lock); | ||
1700 | |||
1701 | return count; | ||
1702 | } | ||
1703 | |||
1704 | static struct sensor_device_attribute_2 sda_caseopen[] = { | ||
1705 | SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen, | ||
1706 | clear_caseopen, 0x80, 0x10), | ||
1707 | SENSOR_ATTR_2(intrusion1_alarm, S_IWUSR | S_IRUGO, show_caseopen, | ||
1708 | clear_caseopen, 0x40, 0x40), | ||
1709 | }; | ||
1710 | |||
1658 | /* | 1711 | /* |
1659 | * Driver and device management | 1712 | * Driver and device management |
1660 | */ | 1713 | */ |
@@ -1711,6 +1764,9 @@ static void w83627ehf_device_remove_files(struct device *dev) | |||
1711 | device_remove_file(dev, &sda_temp_type[i].dev_attr); | 1764 | device_remove_file(dev, &sda_temp_type[i].dev_attr); |
1712 | } | 1765 | } |
1713 | 1766 | ||
1767 | device_remove_file(dev, &sda_caseopen[0].dev_attr); | ||
1768 | device_remove_file(dev, &sda_caseopen[1].dev_attr); | ||
1769 | |||
1714 | device_remove_file(dev, &dev_attr_name); | 1770 | device_remove_file(dev, &dev_attr_name); |
1715 | device_remove_file(dev, &dev_attr_cpu0_vid); | 1771 | device_remove_file(dev, &dev_attr_cpu0_vid); |
1716 | } | 1772 | } |
@@ -1789,13 +1845,78 @@ static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, | |||
1789 | data->reg_temp_config[r2] = tmp; | 1845 | data->reg_temp_config[r2] = tmp; |
1790 | } | 1846 | } |
1791 | 1847 | ||
1848 | static void __devinit | ||
1849 | w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, | ||
1850 | struct w83627ehf_data *data) | ||
1851 | { | ||
1852 | int fan3pin, fan4pin, fan4min, fan5pin, regval; | ||
1853 | |||
1854 | superio_enter(sio_data->sioreg); | ||
1855 | |||
1856 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | ||
1857 | if (sio_data->kind == nct6775) { | ||
1858 | /* On NCT6775, fan4 shares pins with the fdc interface */ | ||
1859 | fan3pin = 1; | ||
1860 | fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); | ||
1861 | fan4min = 0; | ||
1862 | fan5pin = 0; | ||
1863 | } else if (sio_data->kind == nct6776) { | ||
1864 | fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); | ||
1865 | fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); | ||
1866 | fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); | ||
1867 | fan4min = fan4pin; | ||
1868 | } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | ||
1869 | fan3pin = 1; | ||
1870 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; | ||
1871 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; | ||
1872 | fan4min = fan4pin; | ||
1873 | } else { | ||
1874 | fan3pin = 1; | ||
1875 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); | ||
1876 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | ||
1877 | fan4min = fan4pin; | ||
1878 | } | ||
1879 | |||
1880 | superio_exit(sio_data->sioreg); | ||
1881 | |||
1882 | data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */ | ||
1883 | data->has_fan |= (fan3pin << 2); | ||
1884 | data->has_fan_min |= (fan3pin << 2); | ||
1885 | |||
1886 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { | ||
1887 | /* | ||
1888 | * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 | ||
1889 | * register | ||
1890 | */ | ||
1891 | data->has_fan |= (fan4pin << 3) | (fan5pin << 4); | ||
1892 | data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); | ||
1893 | } else { | ||
1894 | /* | ||
1895 | * It looks like fan4 and fan5 pins can be alternatively used | ||
1896 | * as fan on/off switches, but fan5 control is write only :/ | ||
1897 | * We assume that if the serial interface is disabled, designers | ||
1898 | * connected fan5 as input unless they are emitting log 1, which | ||
1899 | * is not the default. | ||
1900 | */ | ||
1901 | regval = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | ||
1902 | if ((regval & (1 << 2)) && fan4pin) { | ||
1903 | data->has_fan |= (1 << 3); | ||
1904 | data->has_fan_min |= (1 << 3); | ||
1905 | } | ||
1906 | if (!(regval & (1 << 1)) && fan5pin) { | ||
1907 | data->has_fan |= (1 << 4); | ||
1908 | data->has_fan_min |= (1 << 4); | ||
1909 | } | ||
1910 | } | ||
1911 | } | ||
1912 | |||
1792 | static int __devinit w83627ehf_probe(struct platform_device *pdev) | 1913 | static int __devinit w83627ehf_probe(struct platform_device *pdev) |
1793 | { | 1914 | { |
1794 | struct device *dev = &pdev->dev; | 1915 | struct device *dev = &pdev->dev; |
1795 | struct w83627ehf_sio_data *sio_data = dev->platform_data; | 1916 | struct w83627ehf_sio_data *sio_data = dev->platform_data; |
1796 | struct w83627ehf_data *data; | 1917 | struct w83627ehf_data *data; |
1797 | struct resource *res; | 1918 | struct resource *res; |
1798 | u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10; | 1919 | u8 en_vrm10; |
1799 | int i, err = 0; | 1920 | int i, err = 0; |
1800 | 1921 | ||
1801 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | 1922 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
@@ -2080,30 +2201,6 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
2080 | } | 2201 | } |
2081 | } | 2202 | } |
2082 | 2203 | ||
2083 | /* fan4 and fan5 share some pins with the GPIO and serial flash */ | ||
2084 | if (sio_data->kind == nct6775) { | ||
2085 | /* On NCT6775, fan4 shares pins with the fdc interface */ | ||
2086 | fan3pin = 1; | ||
2087 | fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80); | ||
2088 | fan4min = 0; | ||
2089 | fan5pin = 0; | ||
2090 | } else if (sio_data->kind == nct6776) { | ||
2091 | fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); | ||
2092 | fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); | ||
2093 | fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); | ||
2094 | fan4min = fan4pin; | ||
2095 | } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { | ||
2096 | fan3pin = 1; | ||
2097 | fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40; | ||
2098 | fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20; | ||
2099 | fan4min = fan4pin; | ||
2100 | } else { | ||
2101 | fan3pin = 1; | ||
2102 | fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06); | ||
2103 | fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02); | ||
2104 | fan4min = fan4pin; | ||
2105 | } | ||
2106 | |||
2107 | if (fan_debounce && | 2204 | if (fan_debounce && |
2108 | (sio_data->kind == nct6775 || sio_data->kind == nct6776)) { | 2205 | (sio_data->kind == nct6775 || sio_data->kind == nct6776)) { |
2109 | u8 tmp; | 2206 | u8 tmp; |
@@ -2121,34 +2218,7 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
2121 | 2218 | ||
2122 | superio_exit(sio_data->sioreg); | 2219 | superio_exit(sio_data->sioreg); |
2123 | 2220 | ||
2124 | /* It looks like fan4 and fan5 pins can be alternatively used | 2221 | w83627ehf_check_fan_inputs(sio_data, data); |
2125 | as fan on/off switches, but fan5 control is write only :/ | ||
2126 | We assume that if the serial interface is disabled, designers | ||
2127 | connected fan5 as input unless they are emitting log 1, which | ||
2128 | is not the default. */ | ||
2129 | |||
2130 | data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */ | ||
2131 | |||
2132 | data->has_fan |= (fan3pin << 2); | ||
2133 | data->has_fan_min |= (fan3pin << 2); | ||
2134 | |||
2135 | /* | ||
2136 | * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register | ||
2137 | */ | ||
2138 | if (sio_data->kind == nct6775 || sio_data->kind == nct6776) { | ||
2139 | data->has_fan |= (fan4pin << 3) | (fan5pin << 4); | ||
2140 | data->has_fan_min |= (fan4min << 3) | (fan5pin << 4); | ||
2141 | } else { | ||
2142 | i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1); | ||
2143 | if ((i & (1 << 2)) && fan4pin) { | ||
2144 | data->has_fan |= (1 << 3); | ||
2145 | data->has_fan_min |= (1 << 3); | ||
2146 | } | ||
2147 | if (!(i & (1 << 1)) && fan5pin) { | ||
2148 | data->has_fan |= (1 << 4); | ||
2149 | data->has_fan_min |= (1 << 4); | ||
2150 | } | ||
2151 | } | ||
2152 | 2222 | ||
2153 | /* Read fan clock dividers immediately */ | 2223 | /* Read fan clock dividers immediately */ |
2154 | w83627ehf_update_fan_div_common(dev, data); | 2224 | w83627ehf_update_fan_div_common(dev, data); |
@@ -2269,6 +2339,16 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) | |||
2269 | goto exit_remove; | 2339 | goto exit_remove; |
2270 | } | 2340 | } |
2271 | 2341 | ||
2342 | err = device_create_file(dev, &sda_caseopen[0].dev_attr); | ||
2343 | if (err) | ||
2344 | goto exit_remove; | ||
2345 | |||
2346 | if (sio_data->kind == nct6776) { | ||
2347 | err = device_create_file(dev, &sda_caseopen[1].dev_attr); | ||
2348 | if (err) | ||
2349 | goto exit_remove; | ||
2350 | } | ||
2351 | |||
2272 | err = device_create_file(dev, &dev_attr_name); | 2352 | err = device_create_file(dev, &dev_attr_name); |
2273 | if (err) | 2353 | if (err) |
2274 | goto exit_remove; | 2354 | goto exit_remove; |
diff --git a/include/linux/platform_data/exynos4_tmu.h b/include/linux/platform_data/exynos4_tmu.h new file mode 100644 index 000000000000..39e038cca590 --- /dev/null +++ b/include/linux/platform_data/exynos4_tmu.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * exynos4_tmu.h - Samsung EXYNOS4 TMU (Thermal Management Unit) | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics | ||
5 | * Donggeun Kim <dg77.kim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #ifndef _LINUX_EXYNOS4_TMU_H | ||
23 | #define _LINUX_EXYNOS4_TMU_H | ||
24 | |||
25 | enum calibration_type { | ||
26 | TYPE_ONE_POINT_TRIMMING, | ||
27 | TYPE_TWO_POINT_TRIMMING, | ||
28 | TYPE_NONE, | ||
29 | }; | ||
30 | |||
31 | /** | ||
32 | * struct exynos4_tmu_platform_data | ||
33 | * @threshold: basic temperature for generating interrupt | ||
34 | * 25 <= threshold <= 125 [unit: degree Celsius] | ||
35 | * @trigger_levels: array for each interrupt levels | ||
36 | * [unit: degree Celsius] | ||
37 | * 0: temperature for trigger_level0 interrupt | ||
38 | * condition for trigger_level0 interrupt: | ||
39 | * current temperature > threshold + trigger_levels[0] | ||
40 | * 1: temperature for trigger_level1 interrupt | ||
41 | * condition for trigger_level1 interrupt: | ||
42 | * current temperature > threshold + trigger_levels[1] | ||
43 | * 2: temperature for trigger_level2 interrupt | ||
44 | * condition for trigger_level2 interrupt: | ||
45 | * current temperature > threshold + trigger_levels[2] | ||
46 | * 3: temperature for trigger_level3 interrupt | ||
47 | * condition for trigger_level3 interrupt: | ||
48 | * current temperature > threshold + trigger_levels[3] | ||
49 | * @trigger_level0_en: | ||
50 | * 1 = enable trigger_level0 interrupt, | ||
51 | * 0 = disable trigger_level0 interrupt | ||
52 | * @trigger_level1_en: | ||
53 | * 1 = enable trigger_level1 interrupt, | ||
54 | * 0 = disable trigger_level1 interrupt | ||
55 | * @trigger_level2_en: | ||
56 | * 1 = enable trigger_level2 interrupt, | ||
57 | * 0 = disable trigger_level2 interrupt | ||
58 | * @trigger_level3_en: | ||
59 | * 1 = enable trigger_level3 interrupt, | ||
60 | * 0 = disable trigger_level3 interrupt | ||
61 | * @gain: gain of amplifier in the positive-TC generator block | ||
62 | * 0 <= gain <= 15 | ||
63 | * @reference_voltage: reference voltage of amplifier | ||
64 | * in the positive-TC generator block | ||
65 | * 0 <= reference_voltage <= 31 | ||
66 | * @cal_type: calibration type for temperature | ||
67 | * | ||
68 | * This structure is required for configuration of exynos4_tmu driver. | ||
69 | */ | ||
70 | struct exynos4_tmu_platform_data { | ||
71 | u8 threshold; | ||
72 | u8 trigger_levels[4]; | ||
73 | bool trigger_level0_en; | ||
74 | bool trigger_level1_en; | ||
75 | bool trigger_level2_en; | ||
76 | bool trigger_level3_en; | ||
77 | |||
78 | u8 gain; | ||
79 | u8 reference_voltage; | ||
80 | |||
81 | enum calibration_type cal_type; | ||
82 | }; | ||
83 | #endif /* _LINUX_EXYNOS4_TMU_H */ | ||