diff options
author | Hans de Goede <hdegoede@redhat.com> | 2009-03-30 15:46:45 -0400 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2009-03-30 15:46:45 -0400 |
commit | c69ab2b78efbe388bb0fc5d885b718ff4668cceb (patch) | |
tree | a970ddcc436d1e80cc37e2937f8e32883afe73ba | |
parent | fa5bfab7128e58c31448fca83a288a86e7d476cc (diff) |
hwmon: (fschmd) Add support for the FSC Syleus IC
Many thanks to Fujitsu Siemens Computers for providing docs and a
machine to test the driver on.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | drivers/hwmon/Kconfig | 7 | ||||
-rw-r--r-- | drivers/hwmon/fschmd.c | 214 |
2 files changed, 161 insertions, 60 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9a22816b37dd..41e3f861c472 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -343,11 +343,12 @@ config SENSORS_FSCPOS | |||
343 | will be called fscpos. | 343 | will be called fscpos. |
344 | 344 | ||
345 | config SENSORS_FSCHMD | 345 | config SENSORS_FSCHMD |
346 | tristate "FSC Poseidon, Scylla, Hermes, Heimdall and Heracles" | 346 | tristate "Fujitsu Siemens Computers sensor chips" |
347 | depends on X86 && I2C | 347 | depends on X86 && I2C |
348 | help | 348 | help |
349 | If you say yes here you get support for various Fujitsu Siemens | 349 | If you say yes here you get support for the following Fujitsu |
350 | Computers sensor chips, including support for the integrated | 350 | Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, |
351 | Heimdall, Heracles and Syleus including support for the integrated | ||
351 | watchdog. | 352 | watchdog. |
352 | 353 | ||
353 | This is a merged driver for FSC sensor chips replacing the fscpos, | 354 | This is a merged driver for FSC sensor chips replacing the fscpos, |
diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index b557f2ebd9ae..ac515bd6b1e7 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* fschmd.c | 1 | /* fschmd.c |
2 | * | 2 | * |
3 | * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> | 3 | * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | /* | 20 | /* |
21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, | 21 | * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes, |
22 | * Scylla, Heracles and Heimdall chips | 22 | * Scylla, Heracles, Heimdall and Syleus chips |
23 | * | 23 | * |
24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 | 24 | * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6 |
25 | * (candidate) fschmd drivers: | 25 | * (candidate) fschmd drivers: |
@@ -56,7 +56,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
56 | module_param(nowayout, int, 0); | 56 | module_param(nowayout, int, 0); |
57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 57 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 58 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
59 | I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | 59 | I2C_CLIENT_INSMOD_6(fscpos, fscher, fscscy, fschrc, fschmd, fscsyl); |
60 | 60 | ||
61 | /* | 61 | /* |
62 | * The FSCHMD registers and other defines | 62 | * The FSCHMD registers and other defines |
@@ -75,9 +75,12 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 | 75 | #define FSCHMD_CONTROL_ALERT_LED 0x01 |
76 | 76 | ||
77 | /* watchdog */ | 77 | /* watchdog */ |
78 | #define FSCHMD_REG_WDOG_PRESET 0x28 | 78 | static const u8 FSCHMD_REG_WDOG_CONTROL[6] = |
79 | #define FSCHMD_REG_WDOG_STATE 0x23 | 79 | { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28 }; |
80 | #define FSCHMD_REG_WDOG_CONTROL 0x21 | 80 | static const u8 FSCHMD_REG_WDOG_STATE[6] = |
81 | { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29 }; | ||
82 | static const u8 FSCHMD_REG_WDOG_PRESET[6] = | ||
83 | { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a }; | ||
81 | 84 | ||
82 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 | 85 | #define FSCHMD_WDOG_CONTROL_TRIGGER 0x10 |
83 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ | 86 | #define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */ |
@@ -87,70 +90,88 @@ I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); | |||
87 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 | 90 | #define FSCHMD_WDOG_STATE_CARDRESET 0x02 |
88 | 91 | ||
89 | /* voltages, weird order is to keep the same order as the old drivers */ | 92 | /* voltages, weird order is to keep the same order as the old drivers */ |
90 | static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; | 93 | static const u8 FSCHMD_REG_VOLT[6][6] = { |
94 | { 0x45, 0x42, 0x48 }, /* pos */ | ||
95 | { 0x45, 0x42, 0x48 }, /* her */ | ||
96 | { 0x45, 0x42, 0x48 }, /* scy */ | ||
97 | { 0x45, 0x42, 0x48 }, /* hrc */ | ||
98 | { 0x45, 0x42, 0x48 }, /* hmd */ | ||
99 | { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */ | ||
100 | }; | ||
101 | |||
102 | static const int FSCHMD_NO_VOLT_SENSORS[6] = { 3, 3, 3, 3, 3, 6 }; | ||
91 | 103 | ||
92 | /* minimum pwm at which the fan is driven (pwm can by increased depending on | 104 | /* minimum pwm at which the fan is driven (pwm can by increased depending on |
93 | the temp. Notice that for the scy some fans share there minimum speed. | 105 | the temp. Notice that for the scy some fans share there minimum speed. |
94 | Also notice that with the scy the sensor order is different than with the | 106 | Also notice that with the scy the sensor order is different than with the |
95 | other chips, this order was in the 2.4 driver and kept for consistency. */ | 107 | other chips, this order was in the 2.4 driver and kept for consistency. */ |
96 | static const u8 FSCHMD_REG_FAN_MIN[5][6] = { | 108 | static const u8 FSCHMD_REG_FAN_MIN[6][7] = { |
97 | { 0x55, 0x65 }, /* pos */ | 109 | { 0x55, 0x65 }, /* pos */ |
98 | { 0x55, 0x65, 0xb5 }, /* her */ | 110 | { 0x55, 0x65, 0xb5 }, /* her */ |
99 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ | 111 | { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */ |
100 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ | 112 | { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */ |
101 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ | 113 | { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */ |
114 | { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */ | ||
102 | }; | 115 | }; |
103 | 116 | ||
104 | /* actual fan speed */ | 117 | /* actual fan speed */ |
105 | static const u8 FSCHMD_REG_FAN_ACT[5][6] = { | 118 | static const u8 FSCHMD_REG_FAN_ACT[6][7] = { |
106 | { 0x0e, 0x6b, 0xab }, /* pos */ | 119 | { 0x0e, 0x6b, 0xab }, /* pos */ |
107 | { 0x0e, 0x6b, 0xbb }, /* her */ | 120 | { 0x0e, 0x6b, 0xbb }, /* her */ |
108 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ | 121 | { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */ |
109 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ | 122 | { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */ |
110 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ | 123 | { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */ |
124 | { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */ | ||
111 | }; | 125 | }; |
112 | 126 | ||
113 | /* fan status registers */ | 127 | /* fan status registers */ |
114 | static const u8 FSCHMD_REG_FAN_STATE[5][6] = { | 128 | static const u8 FSCHMD_REG_FAN_STATE[6][7] = { |
115 | { 0x0d, 0x62, 0xa2 }, /* pos */ | 129 | { 0x0d, 0x62, 0xa2 }, /* pos */ |
116 | { 0x0d, 0x62, 0xb2 }, /* her */ | 130 | { 0x0d, 0x62, 0xb2 }, /* her */ |
117 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ | 131 | { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */ |
118 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ | 132 | { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */ |
119 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ | 133 | { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */ |
134 | { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */ | ||
120 | }; | 135 | }; |
121 | 136 | ||
122 | /* fan ripple / divider registers */ | 137 | /* fan ripple / divider registers */ |
123 | static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { | 138 | static const u8 FSCHMD_REG_FAN_RIPPLE[6][7] = { |
124 | { 0x0f, 0x6f, 0xaf }, /* pos */ | 139 | { 0x0f, 0x6f, 0xaf }, /* pos */ |
125 | { 0x0f, 0x6f, 0xbf }, /* her */ | 140 | { 0x0f, 0x6f, 0xbf }, /* her */ |
126 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ | 141 | { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */ |
127 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ | 142 | { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */ |
128 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ | 143 | { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */ |
144 | { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */ | ||
129 | }; | 145 | }; |
130 | 146 | ||
131 | static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; | 147 | static const int FSCHMD_NO_FAN_SENSORS[6] = { 3, 3, 6, 4, 5, 7 }; |
132 | 148 | ||
133 | /* Fan status register bitmasks */ | 149 | /* Fan status register bitmasks */ |
134 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ | 150 | #define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */ |
135 | #define FSCHMD_FAN_NOT_PRESENT 0x08 /* not documented */ | 151 | #define FSCHMD_FAN_NOT_PRESENT 0x08 |
152 | #define FSCHMD_FAN_DISABLED 0x80 | ||
136 | 153 | ||
137 | 154 | ||
138 | /* actual temperature registers */ | 155 | /* actual temperature registers */ |
139 | static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { | 156 | static const u8 FSCHMD_REG_TEMP_ACT[6][11] = { |
140 | { 0x64, 0x32, 0x35 }, /* pos */ | 157 | { 0x64, 0x32, 0x35 }, /* pos */ |
141 | { 0x64, 0x32, 0x35 }, /* her */ | 158 | { 0x64, 0x32, 0x35 }, /* her */ |
142 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ | 159 | { 0x64, 0xD0, 0x32, 0x35 }, /* scy */ |
143 | { 0x64, 0x32, 0x35 }, /* hrc */ | 160 | { 0x64, 0x32, 0x35 }, /* hrc */ |
144 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ | 161 | { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */ |
162 | { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */ | ||
163 | 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 }, | ||
145 | }; | 164 | }; |
146 | 165 | ||
147 | /* temperature state registers */ | 166 | /* temperature state registers */ |
148 | static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | 167 | static const u8 FSCHMD_REG_TEMP_STATE[6][11] = { |
149 | { 0x71, 0x81, 0x91 }, /* pos */ | 168 | { 0x71, 0x81, 0x91 }, /* pos */ |
150 | { 0x71, 0x81, 0x91 }, /* her */ | 169 | { 0x71, 0x81, 0x91 }, /* her */ |
151 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ | 170 | { 0x71, 0xd1, 0x81, 0x91 }, /* scy */ |
152 | { 0x71, 0x81, 0x91 }, /* hrc */ | 171 | { 0x71, 0x81, 0x91 }, /* hrc */ |
153 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ | 172 | { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */ |
173 | { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */ | ||
174 | 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 }, | ||
154 | }; | 175 | }; |
155 | 176 | ||
156 | /* temperature high limit registers, FSC does not document these. Proven to be | 177 | /* temperature high limit registers, FSC does not document these. Proven to be |
@@ -158,24 +179,30 @@ static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { | |||
158 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers | 179 | in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers |
159 | at these addresses, but doesn't want to confirm they are the same as with | 180 | at these addresses, but doesn't want to confirm they are the same as with |
160 | the fscher?? */ | 181 | the fscher?? */ |
161 | static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { | 182 | static const u8 FSCHMD_REG_TEMP_LIMIT[6][11] = { |
162 | { 0, 0, 0 }, /* pos */ | 183 | { 0, 0, 0 }, /* pos */ |
163 | { 0x76, 0x86, 0x96 }, /* her */ | 184 | { 0x76, 0x86, 0x96 }, /* her */ |
164 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ | 185 | { 0x76, 0xd6, 0x86, 0x96 }, /* scy */ |
165 | { 0x76, 0x86, 0x96 }, /* hrc */ | 186 | { 0x76, 0x86, 0x96 }, /* hrc */ |
166 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ | 187 | { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */ |
188 | { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */ | ||
189 | 0xba, 0xca, 0xda, 0xea, 0xfa }, | ||
167 | }; | 190 | }; |
168 | 191 | ||
169 | /* These were found through experimenting with an fscher, currently they are | 192 | /* These were found through experimenting with an fscher, currently they are |
170 | not used, but we keep them around for future reference. | 193 | not used, but we keep them around for future reference. |
194 | On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc), | ||
195 | AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence | ||
196 | the fan speed. | ||
171 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; | 197 | static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; |
172 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ | 198 | static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ |
173 | 199 | ||
174 | static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; | 200 | static const int FSCHMD_NO_TEMP_SENSORS[6] = { 3, 3, 4, 3, 5, 11 }; |
175 | 201 | ||
176 | /* temp status register bitmasks */ | 202 | /* temp status register bitmasks */ |
177 | #define FSCHMD_TEMP_WORKING 0x01 | 203 | #define FSCHMD_TEMP_WORKING 0x01 |
178 | #define FSCHMD_TEMP_ALERT 0x02 | 204 | #define FSCHMD_TEMP_ALERT 0x02 |
205 | #define FSCHMD_TEMP_DISABLED 0x80 | ||
179 | /* there only really is an alarm if the sensor is working and alert == 1 */ | 206 | /* there only really is an alarm if the sensor is working and alert == 1 */ |
180 | #define FSCHMD_TEMP_ALARM_MASK \ | 207 | #define FSCHMD_TEMP_ALARM_MASK \ |
181 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) | 208 | (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT) |
@@ -201,6 +228,7 @@ static const struct i2c_device_id fschmd_id[] = { | |||
201 | { "fscscy", fscscy }, | 228 | { "fscscy", fscscy }, |
202 | { "fschrc", fschrc }, | 229 | { "fschrc", fschrc }, |
203 | { "fschmd", fschmd }, | 230 | { "fschmd", fschmd }, |
231 | { "fscsyl", fscsyl }, | ||
204 | { } | 232 | { } |
205 | }; | 233 | }; |
206 | MODULE_DEVICE_TABLE(i2c, fschmd_id); | 234 | MODULE_DEVICE_TABLE(i2c, fschmd_id); |
@@ -242,14 +270,14 @@ struct fschmd_data { | |||
242 | u8 watchdog_control; /* watchdog control register */ | 270 | u8 watchdog_control; /* watchdog control register */ |
243 | u8 watchdog_state; /* watchdog status register */ | 271 | u8 watchdog_state; /* watchdog status register */ |
244 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ | 272 | u8 watchdog_preset; /* watchdog counter preset on trigger val */ |
245 | u8 volt[3]; /* 12, 5, battery voltage */ | 273 | u8 volt[6]; /* voltage */ |
246 | u8 temp_act[5]; /* temperature */ | 274 | u8 temp_act[11]; /* temperature */ |
247 | u8 temp_status[5]; /* status of sensor */ | 275 | u8 temp_status[11]; /* status of sensor */ |
248 | u8 temp_max[5]; /* high temp limit, notice: undocumented! */ | 276 | u8 temp_max[11]; /* high temp limit, notice: undocumented! */ |
249 | u8 fan_act[6]; /* fans revolutions per second */ | 277 | u8 fan_act[7]; /* fans revolutions per second */ |
250 | u8 fan_status[6]; /* fan status */ | 278 | u8 fan_status[7]; /* fan status */ |
251 | u8 fan_min[6]; /* fan min value for rps */ | 279 | u8 fan_min[7]; /* fan min value for rps */ |
252 | u8 fan_ripple[6]; /* divider for rps */ | 280 | u8 fan_ripple[7]; /* divider for rps */ |
253 | }; | 281 | }; |
254 | 282 | ||
255 | /* Global variables to hold information read from special DMI tables, which are | 283 | /* Global variables to hold information read from special DMI tables, which are |
@@ -257,8 +285,8 @@ struct fschmd_data { | |||
257 | protect these with a lock as they are only modified from our attach function | 285 | protect these with a lock as they are only modified from our attach function |
258 | which always gets called with the i2c-core lock held and never accessed | 286 | which always gets called with the i2c-core lock held and never accessed |
259 | before the attach function is done with them. */ | 287 | before the attach function is done with them. */ |
260 | static int dmi_mult[3] = { 490, 200, 100 }; | 288 | static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 }; |
261 | static int dmi_offset[3] = { 0, 0, 0 }; | 289 | static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 }; |
262 | static int dmi_vref = -1; | 290 | static int dmi_vref = -1; |
263 | 291 | ||
264 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that | 292 | /* Somewhat ugly :( global data pointer list with all fschmd devices, so that |
@@ -450,10 +478,11 @@ static ssize_t show_pwm_auto_point1_pwm(struct device *dev, | |||
450 | struct device_attribute *devattr, char *buf) | 478 | struct device_attribute *devattr, char *buf) |
451 | { | 479 | { |
452 | int index = to_sensor_dev_attr(devattr)->index; | 480 | int index = to_sensor_dev_attr(devattr)->index; |
453 | int val = fschmd_update_device(dev)->fan_min[index]; | 481 | struct fschmd_data *data = fschmd_update_device(dev); |
482 | int val = data->fan_min[index]; | ||
454 | 483 | ||
455 | /* 0 = allow turning off, 1-255 = 50-100% */ | 484 | /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
456 | if (val) | 485 | if (val || data->kind == fscsyl - 1) |
457 | val = val / 2 + 128; | 486 | val = val / 2 + 128; |
458 | 487 | ||
459 | return sprintf(buf, "%d\n", val); | 488 | return sprintf(buf, "%d\n", val); |
@@ -466,8 +495,8 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, | |||
466 | struct fschmd_data *data = dev_get_drvdata(dev); | 495 | struct fschmd_data *data = dev_get_drvdata(dev); |
467 | unsigned long v = simple_strtoul(buf, NULL, 10); | 496 | unsigned long v = simple_strtoul(buf, NULL, 10); |
468 | 497 | ||
469 | /* register: 0 = allow turning off, 1-255 = 50-100% */ | 498 | /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */ |
470 | if (v) { | 499 | if (v || data->kind == fscsyl - 1) { |
471 | v = SENSORS_LIMIT(v, 128, 255); | 500 | v = SENSORS_LIMIT(v, 128, 255); |
472 | v = (v - 128) * 2 + 1; | 501 | v = (v - 128) * 2 + 1; |
473 | } | 502 | } |
@@ -522,11 +551,15 @@ static ssize_t store_alert_led(struct device *dev, | |||
522 | return count; | 551 | return count; |
523 | } | 552 | } |
524 | 553 | ||
554 | static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); | ||
555 | |||
525 | static struct sensor_device_attribute fschmd_attr[] = { | 556 | static struct sensor_device_attribute fschmd_attr[] = { |
526 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), | 557 | SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), |
527 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), | 558 | SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1), |
528 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), | 559 | SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2), |
529 | SENSOR_ATTR(alert_led, 0644, show_alert_led, store_alert_led, 0), | 560 | SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3), |
561 | SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4), | ||
562 | SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5), | ||
530 | }; | 563 | }; |
531 | 564 | ||
532 | static struct sensor_device_attribute fschmd_temp_attr[] = { | 565 | static struct sensor_device_attribute fschmd_temp_attr[] = { |
@@ -550,6 +583,30 @@ static struct sensor_device_attribute fschmd_temp_attr[] = { | |||
550 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), | 583 | SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4), |
551 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), | 584 | SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4), |
552 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), | 585 | SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4), |
586 | SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5), | ||
587 | SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5), | ||
588 | SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5), | ||
589 | SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5), | ||
590 | SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6), | ||
591 | SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6), | ||
592 | SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6), | ||
593 | SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6), | ||
594 | SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7), | ||
595 | SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7), | ||
596 | SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7), | ||
597 | SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7), | ||
598 | SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8), | ||
599 | SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8), | ||
600 | SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8), | ||
601 | SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8), | ||
602 | SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9), | ||
603 | SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9), | ||
604 | SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9), | ||
605 | SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9), | ||
606 | SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10), | ||
607 | SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10), | ||
608 | SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10), | ||
609 | SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10), | ||
553 | }; | 610 | }; |
554 | 611 | ||
555 | static struct sensor_device_attribute fschmd_fan_attr[] = { | 612 | static struct sensor_device_attribute fschmd_fan_attr[] = { |
@@ -589,6 +646,12 @@ static struct sensor_device_attribute fschmd_fan_attr[] = { | |||
589 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), | 646 | SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5), |
590 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | 647 | SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, |
591 | store_pwm_auto_point1_pwm, 5), | 648 | store_pwm_auto_point1_pwm, 5), |
649 | SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6), | ||
650 | SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6), | ||
651 | SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6), | ||
652 | SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6), | ||
653 | SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm, | ||
654 | store_pwm_auto_point1_pwm, 6), | ||
592 | }; | 655 | }; |
593 | 656 | ||
594 | 657 | ||
@@ -624,10 +687,11 @@ static int watchdog_set_timeout(struct fschmd_data *data, int timeout) | |||
624 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); | 687 | data->watchdog_preset = DIV_ROUND_UP(timeout, resolution); |
625 | 688 | ||
626 | /* Write new timeout value */ | 689 | /* Write new timeout value */ |
627 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_PRESET, | 690 | i2c_smbus_write_byte_data(data->client, |
628 | data->watchdog_preset); | 691 | FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset); |
629 | /* Write new control register, do not trigger! */ | 692 | /* Write new control register, do not trigger! */ |
630 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 693 | i2c_smbus_write_byte_data(data->client, |
694 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
631 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); | 695 | data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER); |
632 | 696 | ||
633 | ret = data->watchdog_preset * resolution; | 697 | ret = data->watchdog_preset * resolution; |
@@ -662,8 +726,9 @@ static int watchdog_trigger(struct fschmd_data *data) | |||
662 | } | 726 | } |
663 | 727 | ||
664 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; | 728 | data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER; |
665 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 729 | i2c_smbus_write_byte_data(data->client, |
666 | data->watchdog_control); | 730 | FSCHMD_REG_WDOG_CONTROL[data->kind], |
731 | data->watchdog_control); | ||
667 | leave: | 732 | leave: |
668 | mutex_unlock(&data->watchdog_lock); | 733 | mutex_unlock(&data->watchdog_lock); |
669 | return ret; | 734 | return ret; |
@@ -682,7 +747,8 @@ static int watchdog_stop(struct fschmd_data *data) | |||
682 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; | 747 | data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED; |
683 | /* Don't store the stop flag in our watchdog control register copy, as | 748 | /* Don't store the stop flag in our watchdog control register copy, as |
684 | its a write only bit (read always returns 0) */ | 749 | its a write only bit (read always returns 0) */ |
685 | i2c_smbus_write_byte_data(data->client, FSCHMD_REG_WDOG_CONTROL, | 750 | i2c_smbus_write_byte_data(data->client, |
751 | FSCHMD_REG_WDOG_CONTROL[data->kind], | ||
686 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); | 752 | data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP); |
687 | leave: | 753 | leave: |
688 | mutex_unlock(&data->watchdog_lock); | 754 | mutex_unlock(&data->watchdog_lock); |
@@ -912,6 +978,15 @@ static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy) | |||
912 | dmi_mult[i] = mult[i] * 10; | 978 | dmi_mult[i] = mult[i] * 10; |
913 | dmi_offset[i] = offset[i] * 10; | 979 | dmi_offset[i] = offset[i] * 10; |
914 | } | 980 | } |
981 | /* According to the docs there should be separate dmi entries | ||
982 | for the mult's and offsets of in3-5 of the syl, but on | ||
983 | my test machine these are not present */ | ||
984 | dmi_mult[3] = dmi_mult[2]; | ||
985 | dmi_mult[4] = dmi_mult[1]; | ||
986 | dmi_mult[5] = dmi_mult[2]; | ||
987 | dmi_offset[3] = dmi_offset[2]; | ||
988 | dmi_offset[4] = dmi_offset[1]; | ||
989 | dmi_offset[5] = dmi_offset[2]; | ||
915 | dmi_vref = vref; | 990 | dmi_vref = vref; |
916 | } | 991 | } |
917 | } | 992 | } |
@@ -920,8 +995,6 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
920 | struct i2c_board_info *info) | 995 | struct i2c_board_info *info) |
921 | { | 996 | { |
922 | struct i2c_adapter *adapter = client->adapter; | 997 | struct i2c_adapter *adapter = client->adapter; |
923 | const char * const client_names[5] = { "fscpos", "fscher", "fscscy", | ||
924 | "fschrc", "fschmd" }; | ||
925 | 998 | ||
926 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 999 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
927 | return -ENODEV; | 1000 | return -ENODEV; |
@@ -948,11 +1021,13 @@ static int fschmd_detect(struct i2c_client *client, int kind, | |||
948 | kind = fschrc; | 1021 | kind = fschrc; |
949 | else if (!strcmp(id, "HMD")) | 1022 | else if (!strcmp(id, "HMD")) |
950 | kind = fschmd; | 1023 | kind = fschmd; |
1024 | else if (!strcmp(id, "SYL")) | ||
1025 | kind = fscsyl; | ||
951 | else | 1026 | else |
952 | return -ENODEV; | 1027 | return -ENODEV; |
953 | } | 1028 | } |
954 | 1029 | ||
955 | strlcpy(info->type, client_names[kind - 1], I2C_NAME_SIZE); | 1030 | strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE); |
956 | 1031 | ||
957 | return 0; | 1032 | return 0; |
958 | } | 1033 | } |
@@ -961,8 +1036,8 @@ static int fschmd_probe(struct i2c_client *client, | |||
961 | const struct i2c_device_id *id) | 1036 | const struct i2c_device_id *id) |
962 | { | 1037 | { |
963 | struct fschmd_data *data; | 1038 | struct fschmd_data *data; |
964 | const char * const names[5] = { "Poseidon", "Hermes", "Scylla", | 1039 | const char * const names[6] = { "Poseidon", "Hermes", "Scylla", |
965 | "Heracles", "Heimdall" }; | 1040 | "Heracles", "Heimdall", "Syleus" }; |
966 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; | 1041 | const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 }; |
967 | int i, err; | 1042 | int i, err; |
968 | enum chips kind = id->driver_data; | 1043 | enum chips kind = id->driver_data; |
@@ -1000,21 +1075,25 @@ static int fschmd_probe(struct i2c_client *client, | |||
1000 | } | 1075 | } |
1001 | } | 1076 | } |
1002 | 1077 | ||
1078 | /* i2c kind goes from 1-6, we want from 0-5 to address arrays */ | ||
1079 | data->kind = kind - 1; | ||
1080 | |||
1003 | /* Read in some never changing registers */ | 1081 | /* Read in some never changing registers */ |
1004 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); | 1082 | data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION); |
1005 | data->global_control = i2c_smbus_read_byte_data(client, | 1083 | data->global_control = i2c_smbus_read_byte_data(client, |
1006 | FSCHMD_REG_CONTROL); | 1084 | FSCHMD_REG_CONTROL); |
1007 | data->watchdog_control = i2c_smbus_read_byte_data(client, | 1085 | data->watchdog_control = i2c_smbus_read_byte_data(client, |
1008 | FSCHMD_REG_WDOG_CONTROL); | 1086 | FSCHMD_REG_WDOG_CONTROL[data->kind]); |
1009 | data->watchdog_state = i2c_smbus_read_byte_data(client, | 1087 | data->watchdog_state = i2c_smbus_read_byte_data(client, |
1010 | FSCHMD_REG_WDOG_STATE); | 1088 | FSCHMD_REG_WDOG_STATE[data->kind]); |
1011 | data->watchdog_preset = i2c_smbus_read_byte_data(client, | 1089 | data->watchdog_preset = i2c_smbus_read_byte_data(client, |
1012 | FSCHMD_REG_WDOG_PRESET); | 1090 | FSCHMD_REG_WDOG_PRESET[data->kind]); |
1013 | 1091 | ||
1014 | /* i2c kind goes from 1-5, we want from 0-4 to address arrays */ | 1092 | err = device_create_file(&client->dev, &dev_attr_alert_led); |
1015 | data->kind = kind - 1; | 1093 | if (err) |
1094 | goto exit_detach; | ||
1016 | 1095 | ||
1017 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) { | 1096 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) { |
1018 | err = device_create_file(&client->dev, | 1097 | err = device_create_file(&client->dev, |
1019 | &fschmd_attr[i].dev_attr); | 1098 | &fschmd_attr[i].dev_attr); |
1020 | if (err) | 1099 | if (err) |
@@ -1027,6 +1106,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1027 | show_temp_max) | 1106 | show_temp_max) |
1028 | continue; | 1107 | continue; |
1029 | 1108 | ||
1109 | if (kind == fscsyl) { | ||
1110 | if (i % 4 == 0) | ||
1111 | data->temp_status[i / 4] = | ||
1112 | i2c_smbus_read_byte_data(client, | ||
1113 | FSCHMD_REG_TEMP_STATE | ||
1114 | [data->kind][i / 4]); | ||
1115 | if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED) | ||
1116 | continue; | ||
1117 | } | ||
1118 | |||
1030 | err = device_create_file(&client->dev, | 1119 | err = device_create_file(&client->dev, |
1031 | &fschmd_temp_attr[i].dev_attr); | 1120 | &fschmd_temp_attr[i].dev_attr); |
1032 | if (err) | 1121 | if (err) |
@@ -1040,6 +1129,16 @@ static int fschmd_probe(struct i2c_client *client, | |||
1040 | "pwm3_auto_point1_pwm")) | 1129 | "pwm3_auto_point1_pwm")) |
1041 | continue; | 1130 | continue; |
1042 | 1131 | ||
1132 | if (kind == fscsyl) { | ||
1133 | if (i % 5 == 0) | ||
1134 | data->fan_status[i / 5] = | ||
1135 | i2c_smbus_read_byte_data(client, | ||
1136 | FSCHMD_REG_FAN_STATE | ||
1137 | [data->kind][i / 5]); | ||
1138 | if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED) | ||
1139 | continue; | ||
1140 | } | ||
1141 | |||
1043 | err = device_create_file(&client->dev, | 1142 | err = device_create_file(&client->dev, |
1044 | &fschmd_fan_attr[i].dev_attr); | 1143 | &fschmd_fan_attr[i].dev_attr); |
1045 | if (err) | 1144 | if (err) |
@@ -1126,7 +1225,8 @@ static int fschmd_remove(struct i2c_client *client) | |||
1126 | if (data->hwmon_dev) | 1225 | if (data->hwmon_dev) |
1127 | hwmon_device_unregister(data->hwmon_dev); | 1226 | hwmon_device_unregister(data->hwmon_dev); |
1128 | 1227 | ||
1129 | for (i = 0; i < ARRAY_SIZE(fschmd_attr); i++) | 1228 | device_remove_file(&client->dev, &dev_attr_alert_led); |
1229 | for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++) | ||
1130 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); | 1230 | device_remove_file(&client->dev, &fschmd_attr[i].dev_attr); |
1131 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) | 1231 | for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) |
1132 | device_remove_file(&client->dev, | 1232 | device_remove_file(&client->dev, |
@@ -1171,7 +1271,7 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1171 | data->temp_act[i] < data->temp_max[i]) | 1271 | data->temp_act[i] < data->temp_max[i]) |
1172 | i2c_smbus_write_byte_data(client, | 1272 | i2c_smbus_write_byte_data(client, |
1173 | FSCHMD_REG_TEMP_STATE[data->kind][i], | 1273 | FSCHMD_REG_TEMP_STATE[data->kind][i], |
1174 | FSCHMD_TEMP_ALERT); | 1274 | data->temp_status[i]); |
1175 | } | 1275 | } |
1176 | 1276 | ||
1177 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { | 1277 | for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) { |
@@ -1193,12 +1293,12 @@ static struct fschmd_data *fschmd_update_device(struct device *dev) | |||
1193 | data->fan_act[i]) | 1293 | data->fan_act[i]) |
1194 | i2c_smbus_write_byte_data(client, | 1294 | i2c_smbus_write_byte_data(client, |
1195 | FSCHMD_REG_FAN_STATE[data->kind][i], | 1295 | FSCHMD_REG_FAN_STATE[data->kind][i], |
1196 | FSCHMD_FAN_ALARM); | 1296 | data->fan_status[i]); |
1197 | } | 1297 | } |
1198 | 1298 | ||
1199 | for (i = 0; i < 3; i++) | 1299 | for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) |
1200 | data->volt[i] = i2c_smbus_read_byte_data(client, | 1300 | data->volt[i] = i2c_smbus_read_byte_data(client, |
1201 | FSCHMD_REG_VOLT[i]); | 1301 | FSCHMD_REG_VOLT[data->kind][i]); |
1202 | 1302 | ||
1203 | data->last_updated = jiffies; | 1303 | data->last_updated = jiffies; |
1204 | data->valid = 1; | 1304 | data->valid = 1; |
@@ -1220,8 +1320,8 @@ static void __exit fschmd_exit(void) | |||
1220 | } | 1320 | } |
1221 | 1321 | ||
1222 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | 1322 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
1223 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " | 1323 | MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall and " |
1224 | "Heimdall driver"); | 1324 | "Syleus driver"); |
1225 | MODULE_LICENSE("GPL"); | 1325 | MODULE_LICENSE("GPL"); |
1226 | 1326 | ||
1227 | module_init(fschmd_init); | 1327 | module_init(fschmd_init); |