aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2009-03-30 15:46:45 -0400
committerJean Delvare <khali@linux-fr.org>2009-03-30 15:46:45 -0400
commitc69ab2b78efbe388bb0fc5d885b718ff4668cceb (patch)
treea970ddcc436d1e80cc37e2937f8e32883afe73ba
parentfa5bfab7128e58c31448fca83a288a86e7d476cc (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/Kconfig7
-rw-r--r--drivers/hwmon/fschmd.c214
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
345config SENSORS_FSCHMD 345config 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;
56module_param(nowayout, int, 0); 56module_param(nowayout, int, 0);
57MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 57MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
58 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 58 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
59I2C_CLIENT_INSMOD_5(fscpos, fscher, fscscy, fschrc, fschmd); 59I2C_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 78static 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 80static const u8 FSCHMD_REG_WDOG_STATE[6] =
81 { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29 };
82static 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 */
90static const u8 FSCHMD_REG_VOLT[3] = { 0x45, 0x42, 0x48 }; 93static 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
102static 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. */
96static const u8 FSCHMD_REG_FAN_MIN[5][6] = { 108static 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 */
105static const u8 FSCHMD_REG_FAN_ACT[5][6] = { 118static 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 */
114static const u8 FSCHMD_REG_FAN_STATE[5][6] = { 128static 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 */
123static const u8 FSCHMD_REG_FAN_RIPPLE[5][6] = { 138static 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
131static const int FSCHMD_NO_FAN_SENSORS[5] = { 3, 3, 6, 4, 5 }; 147static 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 */
139static const u8 FSCHMD_REG_TEMP_ACT[5][5] = { 156static 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 */
148static const u8 FSCHMD_REG_TEMP_STATE[5][5] = { 167static 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?? */
161static const u8 FSCHMD_REG_TEMP_LIMIT[5][5] = { 182static 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.
171static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 }; 197static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
172static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */ 198static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
173 199
174static const int FSCHMD_NO_TEMP_SENSORS[5] = { 3, 3, 4, 3, 5 }; 200static 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};
206MODULE_DEVICE_TABLE(i2c, fschmd_id); 234MODULE_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. */
260static int dmi_mult[3] = { 490, 200, 100 }; 288static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
261static int dmi_offset[3] = { 0, 0, 0 }; 289static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
262static int dmi_vref = -1; 290static 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
554static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
555
525static struct sensor_device_attribute fschmd_attr[] = { 556static 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
532static struct sensor_device_attribute fschmd_temp_attr[] = { 565static 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
555static struct sensor_device_attribute fschmd_fan_attr[] = { 612static 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);
667leave: 732leave:
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);
687leave: 753leave:
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
1222MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 1322MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
1223MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles and " 1323MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall and "
1224 "Heimdall driver"); 1324 "Syleus driver");
1225MODULE_LICENSE("GPL"); 1325MODULE_LICENSE("GPL");
1226 1326
1227module_init(fschmd_init); 1327module_init(fschmd_init);