blob: ac515bd6b1e7f4cd9ee507c53a88ffbde27c7650 [file] [log] [blame]
Hans de Goede569ff102007-10-11 08:06:29 -04001/* fschmd.c
2 *
Hans de Goedec69ab2b2009-03-30 21:46:45 +02003 * Copyright (C) 2007 - 2009 Hans de Goede <hdegoede@redhat.com>
Hans de Goede569ff102007-10-11 08:06:29 -04004 *
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
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20/*
21 * Merged Fujitsu Siemens hwmon driver, supporting the Poseidon, Hermes,
Hans de Goedec69ab2b2009-03-30 21:46:45 +020022 * Scylla, Heracles, Heimdall and Syleus chips
Hans de Goede569ff102007-10-11 08:06:29 -040023 *
24 * Based on the original 2.4 fscscy, 2.6 fscpos, 2.6 fscher and 2.6
25 * (candidate) fschmd drivers:
26 * Copyright (C) 2006 Thilo Cestonaro
27 * <thilo.cestonaro.external@fujitsu-siemens.com>
28 * Copyright (C) 2004, 2005 Stefan Ott <stefan@desire.ch>
29 * Copyright (C) 2003, 2004 Reinhard Nissl <rnissl@gmx.de>
30 * Copyright (c) 2001 Martin Knoblauch <mkn@teraport.de, knobi@knobisoft.de>
31 * Copyright (C) 2000 Hermann Jung <hej@odn.de>
32 */
33
34#include <linux/module.h>
35#include <linux/init.h>
36#include <linux/slab.h>
37#include <linux/jiffies.h>
38#include <linux/i2c.h>
39#include <linux/hwmon.h>
40#include <linux/hwmon-sysfs.h>
41#include <linux/err.h>
42#include <linux/mutex.h>
43#include <linux/sysfs.h>
Hans de Goede7845cd72007-12-20 16:42:59 +010044#include <linux/dmi.h>
Hans de Goede97950c32009-01-07 16:37:33 +010045#include <linux/fs.h>
46#include <linux/watchdog.h>
47#include <linux/miscdevice.h>
48#include <linux/uaccess.h>
49#include <linux/kref.h>
Hans de Goede569ff102007-10-11 08:06:29 -040050
51/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050052static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
Hans de Goede569ff102007-10-11 08:06:29 -040053
54/* Insmod parameters */
Hans de Goede97950c32009-01-07 16:37:33 +010055static int nowayout = WATCHDOG_NOWAYOUT;
56module_param(nowayout, int, 0);
57MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
58 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
Hans de Goedec69ab2b2009-03-30 21:46:45 +020059I2C_CLIENT_INSMOD_6(fscpos, fscher, fscscy, fschrc, fschmd, fscsyl);
Hans de Goede569ff102007-10-11 08:06:29 -040060
61/*
62 * The FSCHMD registers and other defines
63 */
64
65/* chip identification */
66#define FSCHMD_REG_IDENT_0 0x00
67#define FSCHMD_REG_IDENT_1 0x01
68#define FSCHMD_REG_IDENT_2 0x02
69#define FSCHMD_REG_REVISION 0x03
70
71/* global control and status */
72#define FSCHMD_REG_EVENT_STATE 0x04
73#define FSCHMD_REG_CONTROL 0x05
74
Hans de Goede453e3082009-01-07 16:37:33 +010075#define FSCHMD_CONTROL_ALERT_LED 0x01
Hans de Goede569ff102007-10-11 08:06:29 -040076
Hans de Goede97950c32009-01-07 16:37:33 +010077/* watchdog */
Hans de Goedec69ab2b2009-03-30 21:46:45 +020078static const u8 FSCHMD_REG_WDOG_CONTROL[6] =
79 { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28 };
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 };
Hans de Goede569ff102007-10-11 08:06:29 -040084
Hans de Goede97950c32009-01-07 16:37:33 +010085#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
86#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
87#define FSCHMD_WDOG_CONTROL_STOP 0x20
88#define FSCHMD_WDOG_CONTROL_RESOLUTION 0x40
89
90#define FSCHMD_WDOG_STATE_CARDRESET 0x02
91
Hans de Goede569ff102007-10-11 08:06:29 -040092/* voltages, weird order is to keep the same order as the old drivers */
Hans de Goedec69ab2b2009-03-30 21:46:45 +020093static 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 };
Hans de Goede569ff102007-10-11 08:06:29 -0400103
104/* minimum pwm at which the fan is driven (pwm can by increased depending on
105 the temp. Notice that for the scy some fans share there minimum speed.
Frederik Schwarzer025dfda2008-10-16 19:02:37 +0200106 Also notice that with the scy the sensor order is different than with the
Hans de Goede569ff102007-10-11 08:06:29 -0400107 other chips, this order was in the 2.4 driver and kept for consistency. */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200108static const u8 FSCHMD_REG_FAN_MIN[6][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400109 { 0x55, 0x65 }, /* pos */
110 { 0x55, 0x65, 0xb5 }, /* her */
111 { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
112 { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
113 { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200114 { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400115};
116
117/* actual fan speed */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200118static const u8 FSCHMD_REG_FAN_ACT[6][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400119 { 0x0e, 0x6b, 0xab }, /* pos */
120 { 0x0e, 0x6b, 0xbb }, /* her */
121 { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
122 { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
123 { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200124 { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400125};
126
127/* fan status registers */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200128static const u8 FSCHMD_REG_FAN_STATE[6][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400129 { 0x0d, 0x62, 0xa2 }, /* pos */
130 { 0x0d, 0x62, 0xb2 }, /* her */
131 { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
132 { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
133 { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200134 { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400135};
136
137/* fan ripple / divider registers */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200138static const u8 FSCHMD_REG_FAN_RIPPLE[6][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400139 { 0x0f, 0x6f, 0xaf }, /* pos */
140 { 0x0f, 0x6f, 0xbf }, /* her */
141 { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
142 { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
143 { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200144 { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400145};
146
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200147static const int FSCHMD_NO_FAN_SENSORS[6] = { 3, 3, 6, 4, 5, 7 };
Hans de Goede569ff102007-10-11 08:06:29 -0400148
149/* Fan status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100150#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200151#define FSCHMD_FAN_NOT_PRESENT 0x08
152#define FSCHMD_FAN_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400153
154
155/* actual temperature registers */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200156static const u8 FSCHMD_REG_TEMP_ACT[6][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400157 { 0x64, 0x32, 0x35 }, /* pos */
158 { 0x64, 0x32, 0x35 }, /* her */
159 { 0x64, 0xD0, 0x32, 0x35 }, /* scy */
160 { 0x64, 0x32, 0x35 }, /* hrc */
161 { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200162 { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */
163 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
Hans de Goede569ff102007-10-11 08:06:29 -0400164};
165
166/* temperature state registers */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200167static const u8 FSCHMD_REG_TEMP_STATE[6][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400168 { 0x71, 0x81, 0x91 }, /* pos */
169 { 0x71, 0x81, 0x91 }, /* her */
170 { 0x71, 0xd1, 0x81, 0x91 }, /* scy */
171 { 0x71, 0x81, 0x91 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500172 { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200173 { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */
174 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
Hans de Goede569ff102007-10-11 08:06:29 -0400175};
176
177/* temperature high limit registers, FSC does not document these. Proven to be
178 there with field testing on the fscher and fschrc, already supported / used
179 in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
180 at these addresses, but doesn't want to confirm they are the same as with
181 the fscher?? */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200182static const u8 FSCHMD_REG_TEMP_LIMIT[6][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400183 { 0, 0, 0 }, /* pos */
184 { 0x76, 0x86, 0x96 }, /* her */
185 { 0x76, 0xd6, 0x86, 0x96 }, /* scy */
186 { 0x76, 0x86, 0x96 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500187 { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200188 { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */
189 0xba, 0xca, 0xda, 0xea, 0xfa },
Hans de Goede569ff102007-10-11 08:06:29 -0400190};
191
192/* These were found through experimenting with an fscher, currently they are
193 not used, but we keep them around for future reference.
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200194 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.
Hans de Goede569ff102007-10-11 08:06:29 -0400197static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
198static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
199
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200200static const int FSCHMD_NO_TEMP_SENSORS[6] = { 3, 3, 4, 3, 5, 11 };
Hans de Goede569ff102007-10-11 08:06:29 -0400201
202/* temp status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100203#define FSCHMD_TEMP_WORKING 0x01
204#define FSCHMD_TEMP_ALERT 0x02
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200205#define FSCHMD_TEMP_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400206/* there only really is an alarm if the sensor is working and alert == 1 */
207#define FSCHMD_TEMP_ALARM_MASK \
Hans de Goede453e3082009-01-07 16:37:33 +0100208 (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
Hans de Goede569ff102007-10-11 08:06:29 -0400209
210/*
211 * Functions declarations
212 */
213
Jean Delvare40ac1992008-07-16 19:30:12 +0200214static int fschmd_probe(struct i2c_client *client,
215 const struct i2c_device_id *id);
216static int fschmd_detect(struct i2c_client *client, int kind,
217 struct i2c_board_info *info);
218static int fschmd_remove(struct i2c_client *client);
Hans de Goede569ff102007-10-11 08:06:29 -0400219static struct fschmd_data *fschmd_update_device(struct device *dev);
220
221/*
222 * Driver data (common to all clients)
223 */
224
Jean Delvare40ac1992008-07-16 19:30:12 +0200225static const struct i2c_device_id fschmd_id[] = {
226 { "fscpos", fscpos },
227 { "fscher", fscher },
228 { "fscscy", fscscy },
229 { "fschrc", fschrc },
230 { "fschmd", fschmd },
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200231 { "fscsyl", fscsyl },
Jean Delvare40ac1992008-07-16 19:30:12 +0200232 { }
233};
234MODULE_DEVICE_TABLE(i2c, fschmd_id);
235
Hans de Goede569ff102007-10-11 08:06:29 -0400236static struct i2c_driver fschmd_driver = {
Jean Delvare40ac1992008-07-16 19:30:12 +0200237 .class = I2C_CLASS_HWMON,
Hans de Goede569ff102007-10-11 08:06:29 -0400238 .driver = {
Hans de Goede453e3082009-01-07 16:37:33 +0100239 .name = "fschmd",
Hans de Goede569ff102007-10-11 08:06:29 -0400240 },
Jean Delvare40ac1992008-07-16 19:30:12 +0200241 .probe = fschmd_probe,
242 .remove = fschmd_remove,
243 .id_table = fschmd_id,
244 .detect = fschmd_detect,
245 .address_data = &addr_data,
Hans de Goede569ff102007-10-11 08:06:29 -0400246};
247
248/*
249 * Client data (each client gets its own)
250 */
251
252struct fschmd_data {
Hans de Goede97950c32009-01-07 16:37:33 +0100253 struct i2c_client *client;
Hans de Goede569ff102007-10-11 08:06:29 -0400254 struct device *hwmon_dev;
255 struct mutex update_lock;
Hans de Goede97950c32009-01-07 16:37:33 +0100256 struct mutex watchdog_lock;
257 struct list_head list; /* member of the watchdog_data_list */
258 struct kref kref;
259 struct miscdevice watchdog_miscdev;
Hans de Goede569ff102007-10-11 08:06:29 -0400260 int kind;
Hans de Goede97950c32009-01-07 16:37:33 +0100261 unsigned long watchdog_is_open;
262 char watchdog_expect_close;
263 char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
Hans de Goede569ff102007-10-11 08:06:29 -0400264 char valid; /* zero until following fields are valid */
265 unsigned long last_updated; /* in jiffies */
266
267 /* register values */
Hans de Goede97950c32009-01-07 16:37:33 +0100268 u8 revision; /* chip revision */
Hans de Goede569ff102007-10-11 08:06:29 -0400269 u8 global_control; /* global control register */
Hans de Goede97950c32009-01-07 16:37:33 +0100270 u8 watchdog_control; /* watchdog control register */
271 u8 watchdog_state; /* watchdog status register */
272 u8 watchdog_preset; /* watchdog counter preset on trigger val */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200273 u8 volt[6]; /* voltage */
274 u8 temp_act[11]; /* temperature */
275 u8 temp_status[11]; /* status of sensor */
276 u8 temp_max[11]; /* high temp limit, notice: undocumented! */
277 u8 fan_act[7]; /* fans revolutions per second */
278 u8 fan_status[7]; /* fan status */
279 u8 fan_min[7]; /* fan min value for rps */
280 u8 fan_ripple[7]; /* divider for rps */
Hans de Goede569ff102007-10-11 08:06:29 -0400281};
282
Hans de Goede7845cd72007-12-20 16:42:59 +0100283/* Global variables to hold information read from special DMI tables, which are
Hans de Goede97950c32009-01-07 16:37:33 +0100284 available on FSC machines with an fscher or later chip. There is no need to
285 protect these with a lock as they are only modified from our attach function
286 which always gets called with the i2c-core lock held and never accessed
287 before the attach function is done with them. */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200288static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
289static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
Hans de Goede7845cd72007-12-20 16:42:59 +0100290static int dmi_vref = -1;
291
Hans de Goede97950c32009-01-07 16:37:33 +0100292/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
293 we can find our device data as when using misc_register there is no other
294 method to get to ones device data from the open fop. */
295static LIST_HEAD(watchdog_data_list);
296/* Note this lock not only protect list access, but also data.kref access */
297static DEFINE_MUTEX(watchdog_data_mutex);
298
299/* Release our data struct when we're detached from the i2c client *and* all
300 references to our watchdog device are released */
301static void fschmd_release_resources(struct kref *ref)
302{
303 struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
304 kfree(data);
305}
Hans de Goede7845cd72007-12-20 16:42:59 +0100306
Hans de Goede569ff102007-10-11 08:06:29 -0400307/*
308 * Sysfs attr show / store functions
309 */
310
311static ssize_t show_in_value(struct device *dev,
312 struct device_attribute *devattr, char *buf)
313{
314 const int max_reading[3] = { 14200, 6600, 3300 };
315 int index = to_sensor_dev_attr(devattr)->index;
316 struct fschmd_data *data = fschmd_update_device(dev);
317
Hans de Goede7845cd72007-12-20 16:42:59 +0100318 /* fscher / fschrc - 1 as data->kind is an array index, not a chips */
319 if (data->kind == (fscher - 1) || data->kind >= (fschrc - 1))
320 return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
321 dmi_mult[index]) / 255 + dmi_offset[index]);
322 else
323 return sprintf(buf, "%d\n", (data->volt[index] *
324 max_reading[index] + 128) / 255);
Hans de Goede569ff102007-10-11 08:06:29 -0400325}
326
327
328#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
329
330static ssize_t show_temp_value(struct device *dev,
331 struct device_attribute *devattr, char *buf)
332{
333 int index = to_sensor_dev_attr(devattr)->index;
334 struct fschmd_data *data = fschmd_update_device(dev);
335
336 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
337}
338
339static ssize_t show_temp_max(struct device *dev,
340 struct device_attribute *devattr, char *buf)
341{
342 int index = to_sensor_dev_attr(devattr)->index;
343 struct fschmd_data *data = fschmd_update_device(dev);
344
345 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
346}
347
348static ssize_t store_temp_max(struct device *dev, struct device_attribute
349 *devattr, const char *buf, size_t count)
350{
351 int index = to_sensor_dev_attr(devattr)->index;
352 struct fschmd_data *data = dev_get_drvdata(dev);
353 long v = simple_strtol(buf, NULL, 10) / 1000;
354
355 v = SENSORS_LIMIT(v, -128, 127) + 128;
356
357 mutex_lock(&data->update_lock);
Jean Delvare40ac1992008-07-16 19:30:12 +0200358 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400359 FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
360 data->temp_max[index] = v;
361 mutex_unlock(&data->update_lock);
362
363 return count;
364}
365
366static ssize_t show_temp_fault(struct device *dev,
367 struct device_attribute *devattr, char *buf)
368{
369 int index = to_sensor_dev_attr(devattr)->index;
370 struct fschmd_data *data = fschmd_update_device(dev);
371
372 /* bit 0 set means sensor working ok, so no fault! */
Hans de Goede453e3082009-01-07 16:37:33 +0100373 if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
Hans de Goede569ff102007-10-11 08:06:29 -0400374 return sprintf(buf, "0\n");
375 else
376 return sprintf(buf, "1\n");
377}
378
379static ssize_t show_temp_alarm(struct device *dev,
380 struct device_attribute *devattr, char *buf)
381{
382 int index = to_sensor_dev_attr(devattr)->index;
383 struct fschmd_data *data = fschmd_update_device(dev);
384
385 if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
386 FSCHMD_TEMP_ALARM_MASK)
387 return sprintf(buf, "1\n");
388 else
389 return sprintf(buf, "0\n");
390}
391
392
393#define RPM_FROM_REG(val) ((val) * 60)
394
395static ssize_t show_fan_value(struct device *dev,
396 struct device_attribute *devattr, char *buf)
397{
398 int index = to_sensor_dev_attr(devattr)->index;
399 struct fschmd_data *data = fschmd_update_device(dev);
400
401 return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
402}
403
404static ssize_t show_fan_div(struct device *dev,
405 struct device_attribute *devattr, char *buf)
406{
407 int index = to_sensor_dev_attr(devattr)->index;
408 struct fschmd_data *data = fschmd_update_device(dev);
409
410 /* bits 2..7 reserved => mask with 3 */
411 return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
412}
413
414static ssize_t store_fan_div(struct device *dev, struct device_attribute
415 *devattr, const char *buf, size_t count)
416{
417 u8 reg;
418 int index = to_sensor_dev_attr(devattr)->index;
419 struct fschmd_data *data = dev_get_drvdata(dev);
420 /* supported values: 2, 4, 8 */
421 unsigned long v = simple_strtoul(buf, NULL, 10);
422
423 switch (v) {
424 case 2: v = 1; break;
425 case 4: v = 2; break;
426 case 8: v = 3; break;
427 default:
428 dev_err(dev, "fan_div value %lu not supported. "
429 "Choose one of 2, 4 or 8!\n", v);
430 return -EINVAL;
431 }
432
433 mutex_lock(&data->update_lock);
434
Jean Delvare40ac1992008-07-16 19:30:12 +0200435 reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400436 FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
437
438 /* bits 2..7 reserved => mask with 0x03 */
439 reg &= ~0x03;
440 reg |= v;
441
Jean Delvare40ac1992008-07-16 19:30:12 +0200442 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400443 FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
444
445 data->fan_ripple[index] = reg;
446
447 mutex_unlock(&data->update_lock);
448
449 return count;
450}
451
452static ssize_t show_fan_alarm(struct device *dev,
453 struct device_attribute *devattr, char *buf)
454{
455 int index = to_sensor_dev_attr(devattr)->index;
456 struct fschmd_data *data = fschmd_update_device(dev);
457
Hans de Goede453e3082009-01-07 16:37:33 +0100458 if (data->fan_status[index] & FSCHMD_FAN_ALARM)
Hans de Goede569ff102007-10-11 08:06:29 -0400459 return sprintf(buf, "1\n");
460 else
461 return sprintf(buf, "0\n");
462}
463
464static ssize_t show_fan_fault(struct device *dev,
465 struct device_attribute *devattr, char *buf)
466{
467 int index = to_sensor_dev_attr(devattr)->index;
468 struct fschmd_data *data = fschmd_update_device(dev);
469
Hans de Goede453e3082009-01-07 16:37:33 +0100470 if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
Hans de Goede569ff102007-10-11 08:06:29 -0400471 return sprintf(buf, "1\n");
472 else
473 return sprintf(buf, "0\n");
474}
475
476
477static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
478 struct device_attribute *devattr, char *buf)
479{
480 int index = to_sensor_dev_attr(devattr)->index;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200481 struct fschmd_data *data = fschmd_update_device(dev);
482 int val = data->fan_min[index];
Hans de Goede569ff102007-10-11 08:06:29 -0400483
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200484 /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
485 if (val || data->kind == fscsyl - 1)
Hans de Goede569ff102007-10-11 08:06:29 -0400486 val = val / 2 + 128;
487
488 return sprintf(buf, "%d\n", val);
489}
490
491static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
492 struct device_attribute *devattr, const char *buf, size_t count)
493{
494 int index = to_sensor_dev_attr(devattr)->index;
495 struct fschmd_data *data = dev_get_drvdata(dev);
496 unsigned long v = simple_strtoul(buf, NULL, 10);
497
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200498 /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
499 if (v || data->kind == fscsyl - 1) {
Hans de Goede569ff102007-10-11 08:06:29 -0400500 v = SENSORS_LIMIT(v, 128, 255);
501 v = (v - 128) * 2 + 1;
502 }
503
504 mutex_lock(&data->update_lock);
505
Jean Delvare40ac1992008-07-16 19:30:12 +0200506 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400507 FSCHMD_REG_FAN_MIN[data->kind][index], v);
508 data->fan_min[index] = v;
509
510 mutex_unlock(&data->update_lock);
511
512 return count;
513}
514
515
516/* The FSC hwmon family has the ability to force an attached alert led to flash
517 from software, we export this as an alert_led sysfs attr */
518static ssize_t show_alert_led(struct device *dev,
519 struct device_attribute *devattr, char *buf)
520{
521 struct fschmd_data *data = fschmd_update_device(dev);
522
Hans de Goede453e3082009-01-07 16:37:33 +0100523 if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
Hans de Goede569ff102007-10-11 08:06:29 -0400524 return sprintf(buf, "1\n");
525 else
526 return sprintf(buf, "0\n");
527}
528
529static ssize_t store_alert_led(struct device *dev,
530 struct device_attribute *devattr, const char *buf, size_t count)
531{
532 u8 reg;
533 struct fschmd_data *data = dev_get_drvdata(dev);
534 unsigned long v = simple_strtoul(buf, NULL, 10);
535
536 mutex_lock(&data->update_lock);
537
Jean Delvare40ac1992008-07-16 19:30:12 +0200538 reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
Hans de Goede569ff102007-10-11 08:06:29 -0400539
540 if (v)
Hans de Goede453e3082009-01-07 16:37:33 +0100541 reg |= FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400542 else
Hans de Goede453e3082009-01-07 16:37:33 +0100543 reg &= ~FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400544
Jean Delvare40ac1992008-07-16 19:30:12 +0200545 i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
Hans de Goede569ff102007-10-11 08:06:29 -0400546
547 data->global_control = reg;
548
549 mutex_unlock(&data->update_lock);
550
551 return count;
552}
553
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200554static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
555
Hans de Goede569ff102007-10-11 08:06:29 -0400556static struct sensor_device_attribute fschmd_attr[] = {
557 SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
558 SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
559 SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200560 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),
Hans de Goede569ff102007-10-11 08:06:29 -0400563};
564
565static struct sensor_device_attribute fschmd_temp_attr[] = {
566 SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
567 SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
568 SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
569 SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
570 SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
571 SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
572 SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
573 SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
574 SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
575 SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
576 SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
577 SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
578 SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
579 SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
580 SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
581 SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
582 SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
583 SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
584 SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
585 SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200586 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),
Hans de Goede569ff102007-10-11 08:06:29 -0400610};
611
612static struct sensor_device_attribute fschmd_fan_attr[] = {
613 SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
614 SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
615 SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
616 SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
617 SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
618 store_pwm_auto_point1_pwm, 0),
619 SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
620 SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
621 SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
622 SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
623 SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
624 store_pwm_auto_point1_pwm, 1),
625 SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
626 SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
627 SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
628 SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
629 SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
630 store_pwm_auto_point1_pwm, 2),
631 SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
632 SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
633 SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
634 SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
635 SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
636 store_pwm_auto_point1_pwm, 3),
637 SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
638 SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
639 SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
640 SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
641 SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
642 store_pwm_auto_point1_pwm, 4),
643 SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
644 SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
645 SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
646 SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
647 SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
648 store_pwm_auto_point1_pwm, 5),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200649 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),
Hans de Goede569ff102007-10-11 08:06:29 -0400655};
656
657
658/*
Hans de Goede97950c32009-01-07 16:37:33 +0100659 * Watchdog routines
660 */
661
662static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
663{
664 int ret, resolution;
665 int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
666
667 /* 2 second or 60 second resolution? */
668 if (timeout <= 510 || kind == fscpos || kind == fscscy)
669 resolution = 2;
670 else
671 resolution = 60;
672
673 if (timeout < resolution || timeout > (resolution * 255))
674 return -EINVAL;
675
676 mutex_lock(&data->watchdog_lock);
677 if (!data->client) {
678 ret = -ENODEV;
679 goto leave;
680 }
681
682 if (resolution == 2)
683 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
684 else
685 data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
686
687 data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
688
689 /* Write new timeout value */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200690 i2c_smbus_write_byte_data(data->client,
691 FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
Hans de Goede97950c32009-01-07 16:37:33 +0100692 /* Write new control register, do not trigger! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200693 i2c_smbus_write_byte_data(data->client,
694 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100695 data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
696
697 ret = data->watchdog_preset * resolution;
698
699leave:
700 mutex_unlock(&data->watchdog_lock);
701 return ret;
702}
703
704static int watchdog_get_timeout(struct fschmd_data *data)
705{
706 int timeout;
707
708 mutex_lock(&data->watchdog_lock);
709 if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
710 timeout = data->watchdog_preset * 60;
711 else
712 timeout = data->watchdog_preset * 2;
713 mutex_unlock(&data->watchdog_lock);
714
715 return timeout;
716}
717
718static int watchdog_trigger(struct fschmd_data *data)
719{
720 int ret = 0;
721
722 mutex_lock(&data->watchdog_lock);
723 if (!data->client) {
724 ret = -ENODEV;
725 goto leave;
726 }
727
728 data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200729 i2c_smbus_write_byte_data(data->client,
730 FSCHMD_REG_WDOG_CONTROL[data->kind],
731 data->watchdog_control);
Hans de Goede97950c32009-01-07 16:37:33 +0100732leave:
733 mutex_unlock(&data->watchdog_lock);
734 return ret;
735}
736
737static int watchdog_stop(struct fschmd_data *data)
738{
739 int ret = 0;
740
741 mutex_lock(&data->watchdog_lock);
742 if (!data->client) {
743 ret = -ENODEV;
744 goto leave;
745 }
746
747 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
748 /* Don't store the stop flag in our watchdog control register copy, as
749 its a write only bit (read always returns 0) */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200750 i2c_smbus_write_byte_data(data->client,
751 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100752 data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
753leave:
754 mutex_unlock(&data->watchdog_lock);
755 return ret;
756}
757
758static int watchdog_open(struct inode *inode, struct file *filp)
759{
760 struct fschmd_data *pos, *data = NULL;
761
762 /* We get called from drivers/char/misc.c with misc_mtx hold, and we
763 call misc_register() from fschmd_probe() with watchdog_data_mutex
764 hold, as misc_register() takes the misc_mtx lock, this is a possible
765 deadlock, so we use mutex_trylock here. */
766 if (!mutex_trylock(&watchdog_data_mutex))
767 return -ERESTARTSYS;
768 list_for_each_entry(pos, &watchdog_data_list, list) {
769 if (pos->watchdog_miscdev.minor == iminor(inode)) {
770 data = pos;
771 break;
772 }
773 }
774 /* Note we can never not have found data, so we don't check for this */
775 kref_get(&data->kref);
776 mutex_unlock(&watchdog_data_mutex);
777
778 if (test_and_set_bit(0, &data->watchdog_is_open))
779 return -EBUSY;
780
781 /* Start the watchdog */
782 watchdog_trigger(data);
783 filp->private_data = data;
784
785 return nonseekable_open(inode, filp);
786}
787
788static int watchdog_release(struct inode *inode, struct file *filp)
789{
790 struct fschmd_data *data = filp->private_data;
791
792 if (data->watchdog_expect_close) {
793 watchdog_stop(data);
794 data->watchdog_expect_close = 0;
795 } else {
796 watchdog_trigger(data);
797 dev_crit(&data->client->dev,
798 "unexpected close, not stopping watchdog!\n");
799 }
800
801 clear_bit(0, &data->watchdog_is_open);
802
803 mutex_lock(&watchdog_data_mutex);
804 kref_put(&data->kref, fschmd_release_resources);
805 mutex_unlock(&watchdog_data_mutex);
806
807 return 0;
808}
809
810static ssize_t watchdog_write(struct file *filp, const char __user *buf,
811 size_t count, loff_t *offset)
812{
813 size_t ret;
814 struct fschmd_data *data = filp->private_data;
815
816 if (count) {
817 if (!nowayout) {
818 size_t i;
819
820 /* Clear it in case it was set with a previous write */
821 data->watchdog_expect_close = 0;
822
823 for (i = 0; i != count; i++) {
824 char c;
825 if (get_user(c, buf + i))
826 return -EFAULT;
827 if (c == 'V')
828 data->watchdog_expect_close = 1;
829 }
830 }
831 ret = watchdog_trigger(data);
832 if (ret < 0)
833 return ret;
834 }
835 return count;
836}
837
838static int watchdog_ioctl(struct inode *inode, struct file *filp,
839 unsigned int cmd, unsigned long arg)
840{
841 static struct watchdog_info ident = {
842 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
843 WDIOF_CARDRESET,
844 .identity = "FSC watchdog"
845 };
846 int i, ret = 0;
847 struct fschmd_data *data = filp->private_data;
848
849 switch (cmd) {
850 case WDIOC_GETSUPPORT:
851 ident.firmware_version = data->revision;
852 if (!nowayout)
853 ident.options |= WDIOF_MAGICCLOSE;
854 if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
855 ret = -EFAULT;
856 break;
857
858 case WDIOC_GETSTATUS:
859 ret = put_user(0, (int __user *)arg);
860 break;
861
862 case WDIOC_GETBOOTSTATUS:
863 if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
864 ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
865 else
866 ret = put_user(0, (int __user *)arg);
867 break;
868
869 case WDIOC_KEEPALIVE:
870 ret = watchdog_trigger(data);
871 break;
872
873 case WDIOC_GETTIMEOUT:
874 i = watchdog_get_timeout(data);
875 ret = put_user(i, (int __user *)arg);
876 break;
877
878 case WDIOC_SETTIMEOUT:
879 if (get_user(i, (int __user *)arg)) {
880 ret = -EFAULT;
881 break;
882 }
883 ret = watchdog_set_timeout(data, i);
884 if (ret > 0)
885 ret = put_user(ret, (int __user *)arg);
886 break;
887
888 case WDIOC_SETOPTIONS:
889 if (get_user(i, (int __user *)arg)) {
890 ret = -EFAULT;
891 break;
892 }
893
894 if (i & WDIOS_DISABLECARD)
895 ret = watchdog_stop(data);
896 else if (i & WDIOS_ENABLECARD)
897 ret = watchdog_trigger(data);
898 else
899 ret = -EINVAL;
900
901 break;
902 default:
903 ret = -ENOTTY;
904 }
905
906 return ret;
907}
908
909static struct file_operations watchdog_fops = {
910 .owner = THIS_MODULE,
911 .llseek = no_llseek,
912 .open = watchdog_open,
913 .release = watchdog_release,
914 .write = watchdog_write,
915 .ioctl = watchdog_ioctl,
916};
917
918
919/*
920 * Detect, register, unregister and update device functions
Hans de Goede569ff102007-10-11 08:06:29 -0400921 */
922
Hans de Goede7845cd72007-12-20 16:42:59 +0100923/* DMI decode routine to read voltage scaling factors from special DMI tables,
924 which are available on FSC machines with an fscher or later chip. */
Jean Delvaree7a19c562009-03-30 21:46:44 +0200925static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
Hans de Goede7845cd72007-12-20 16:42:59 +0100926{
927 int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
928
929 /* dmi code ugliness, we get passed the address of the contents of
930 a complete DMI record, but in the form of a dmi_header pointer, in
931 reality this address holds header->length bytes of which the header
932 are the first 4 bytes */
933 u8 *dmi_data = (u8 *)header;
934
935 /* We are looking for OEM-specific type 185 */
936 if (header->type != 185)
937 return;
938
939 /* we are looking for what Siemens calls "subtype" 19, the subtype
940 is stored in byte 5 of the dmi block */
941 if (header->length < 5 || dmi_data[4] != 19)
942 return;
943
944 /* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
945 consisting of what Siemens calls an "Entity" number, followed by
946 2 16-bit words in LSB first order */
947 for (i = 6; (i + 4) < header->length; i += 5) {
948 /* entity 1 - 3: voltage multiplier and offset */
949 if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
950 /* Our in sensors order and the DMI order differ */
951 const int shuffle[3] = { 1, 0, 2 };
952 int in = shuffle[dmi_data[i] - 1];
953
954 /* Check for twice the same entity */
955 if (found & (1 << in))
956 return;
957
958 mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
959 offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
960
961 found |= 1 << in;
962 }
963
964 /* entity 7: reference voltage */
965 if (dmi_data[i] == 7) {
966 /* Check for twice the same entity */
967 if (found & 0x08)
968 return;
969
970 vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
971
972 found |= 0x08;
973 }
974 }
975
976 if (found == 0x0F) {
977 for (i = 0; i < 3; i++) {
978 dmi_mult[i] = mult[i] * 10;
979 dmi_offset[i] = offset[i] * 10;
980 }
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200981 /* 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];
Hans de Goede7845cd72007-12-20 16:42:59 +0100990 dmi_vref = vref;
991 }
992}
993
Jean Delvare40ac1992008-07-16 19:30:12 +0200994static int fschmd_detect(struct i2c_client *client, int kind,
995 struct i2c_board_info *info)
Hans de Goede569ff102007-10-11 08:06:29 -0400996{
Jean Delvare40ac1992008-07-16 19:30:12 +0200997 struct i2c_adapter *adapter = client->adapter;
Hans de Goede569ff102007-10-11 08:06:29 -0400998
999 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Jean Delvare40ac1992008-07-16 19:30:12 +02001000 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001001
1002 /* Detect & Identify the chip */
1003 if (kind <= 0) {
1004 char id[4];
1005
1006 id[0] = i2c_smbus_read_byte_data(client,
1007 FSCHMD_REG_IDENT_0);
1008 id[1] = i2c_smbus_read_byte_data(client,
1009 FSCHMD_REG_IDENT_1);
1010 id[2] = i2c_smbus_read_byte_data(client,
1011 FSCHMD_REG_IDENT_2);
1012 id[3] = '\0';
1013
1014 if (!strcmp(id, "PEG"))
1015 kind = fscpos;
1016 else if (!strcmp(id, "HER"))
1017 kind = fscher;
1018 else if (!strcmp(id, "SCY"))
1019 kind = fscscy;
1020 else if (!strcmp(id, "HRC"))
1021 kind = fschrc;
1022 else if (!strcmp(id, "HMD"))
1023 kind = fschmd;
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001024 else if (!strcmp(id, "SYL"))
1025 kind = fscsyl;
Hans de Goede569ff102007-10-11 08:06:29 -04001026 else
Jean Delvare40ac1992008-07-16 19:30:12 +02001027 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001028 }
1029
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001030 strlcpy(info->type, fschmd_id[kind - 1].name, I2C_NAME_SIZE);
Jean Delvare40ac1992008-07-16 19:30:12 +02001031
1032 return 0;
1033}
1034
1035static int fschmd_probe(struct i2c_client *client,
1036 const struct i2c_device_id *id)
1037{
1038 struct fschmd_data *data;
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001039 const char * const names[6] = { "Poseidon", "Hermes", "Scylla",
1040 "Heracles", "Heimdall", "Syleus" };
Hans de Goede97950c32009-01-07 16:37:33 +01001041 const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
Jean Delvare40ac1992008-07-16 19:30:12 +02001042 int i, err;
1043 enum chips kind = id->driver_data;
1044
1045 data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
1046 if (!data)
1047 return -ENOMEM;
1048
1049 i2c_set_clientdata(client, data);
1050 mutex_init(&data->update_lock);
Hans de Goede97950c32009-01-07 16:37:33 +01001051 mutex_init(&data->watchdog_lock);
1052 INIT_LIST_HEAD(&data->list);
1053 kref_init(&data->kref);
1054 /* Store client pointer in our data struct for watchdog usage
1055 (where the client is found through a data ptr instead of the
1056 otherway around) */
1057 data->client = client;
Jean Delvare40ac1992008-07-16 19:30:12 +02001058
Hans de Goede569ff102007-10-11 08:06:29 -04001059 if (kind == fscpos) {
1060 /* The Poseidon has hardwired temp limits, fill these
1061 in for the alarm resetting code */
1062 data->temp_max[0] = 70 + 128;
1063 data->temp_max[1] = 50 + 128;
1064 data->temp_max[2] = 50 + 128;
1065 }
1066
Hans de Goede7845cd72007-12-20 16:42:59 +01001067 /* Read the special DMI table for fscher and newer chips */
Hans de Goede453e3082009-01-07 16:37:33 +01001068 if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
Jean Delvaree7a19c562009-03-30 21:46:44 +02001069 dmi_walk(fschmd_dmi_decode, NULL);
Hans de Goede7845cd72007-12-20 16:42:59 +01001070 if (dmi_vref == -1) {
Hans de Goede453e3082009-01-07 16:37:33 +01001071 dev_warn(&client->dev,
1072 "Couldn't get voltage scaling factors from "
Hans de Goede7845cd72007-12-20 16:42:59 +01001073 "BIOS DMI table, using builtin defaults\n");
1074 dmi_vref = 33;
1075 }
1076 }
1077
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001078 /* i2c kind goes from 1-6, we want from 0-5 to address arrays */
1079 data->kind = kind - 1;
1080
Hans de Goede97950c32009-01-07 16:37:33 +01001081 /* Read in some never changing registers */
1082 data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
1083 data->global_control = i2c_smbus_read_byte_data(client,
1084 FSCHMD_REG_CONTROL);
1085 data->watchdog_control = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001086 FSCHMD_REG_WDOG_CONTROL[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001087 data->watchdog_state = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001088 FSCHMD_REG_WDOG_STATE[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001089 data->watchdog_preset = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001090 FSCHMD_REG_WDOG_PRESET[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001091
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001092 err = device_create_file(&client->dev, &dev_attr_alert_led);
1093 if (err)
1094 goto exit_detach;
Hans de Goede569ff102007-10-11 08:06:29 -04001095
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001096 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
Hans de Goede569ff102007-10-11 08:06:29 -04001097 err = device_create_file(&client->dev,
1098 &fschmd_attr[i].dev_attr);
1099 if (err)
1100 goto exit_detach;
1101 }
1102
1103 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
1104 /* Poseidon doesn't have TEMP_LIMIT registers */
1105 if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
1106 show_temp_max)
1107 continue;
1108
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001109 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
Hans de Goede569ff102007-10-11 08:06:29 -04001119 err = device_create_file(&client->dev,
1120 &fschmd_temp_attr[i].dev_attr);
1121 if (err)
1122 goto exit_detach;
1123 }
1124
1125 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
1126 /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
1127 if (kind == fscpos &&
1128 !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
1129 "pwm3_auto_point1_pwm"))
1130 continue;
1131
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001132 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
Hans de Goede569ff102007-10-11 08:06:29 -04001142 err = device_create_file(&client->dev,
1143 &fschmd_fan_attr[i].dev_attr);
1144 if (err)
1145 goto exit_detach;
1146 }
1147
1148 data->hwmon_dev = hwmon_device_register(&client->dev);
1149 if (IS_ERR(data->hwmon_dev)) {
1150 err = PTR_ERR(data->hwmon_dev);
1151 data->hwmon_dev = NULL;
1152 goto exit_detach;
1153 }
1154
Hans de Goede97950c32009-01-07 16:37:33 +01001155 /* We take the data_mutex lock early so that watchdog_open() cannot
1156 run when misc_register() has completed, but we've not yet added
1157 our data to the watchdog_data_list (and set the default timeout) */
1158 mutex_lock(&watchdog_data_mutex);
1159 for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
1160 /* Register our watchdog part */
1161 snprintf(data->watchdog_name, sizeof(data->watchdog_name),
1162 "watchdog%c", (i == 0) ? '\0' : ('0' + i));
1163 data->watchdog_miscdev.name = data->watchdog_name;
1164 data->watchdog_miscdev.fops = &watchdog_fops;
1165 data->watchdog_miscdev.minor = watchdog_minors[i];
1166 err = misc_register(&data->watchdog_miscdev);
1167 if (err == -EBUSY)
1168 continue;
1169 if (err) {
1170 data->watchdog_miscdev.minor = 0;
1171 dev_err(&client->dev,
1172 "Registering watchdog chardev: %d\n", err);
1173 break;
1174 }
1175
1176 list_add(&data->list, &watchdog_data_list);
1177 watchdog_set_timeout(data, 60);
1178 dev_info(&client->dev,
1179 "Registered watchdog chardev major 10, minor: %d\n",
1180 watchdog_minors[i]);
1181 break;
1182 }
1183 if (i == ARRAY_SIZE(watchdog_minors)) {
1184 data->watchdog_miscdev.minor = 0;
1185 dev_warn(&client->dev, "Couldn't register watchdog chardev "
1186 "(due to no free minor)\n");
1187 }
1188 mutex_unlock(&watchdog_data_mutex);
1189
Hans de Goede453e3082009-01-07 16:37:33 +01001190 dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
Hans de Goede97950c32009-01-07 16:37:33 +01001191 names[data->kind], (int) data->revision);
Hans de Goede569ff102007-10-11 08:06:29 -04001192
1193 return 0;
1194
1195exit_detach:
Jean Delvare40ac1992008-07-16 19:30:12 +02001196 fschmd_remove(client); /* will also free data for us */
Hans de Goede569ff102007-10-11 08:06:29 -04001197 return err;
1198}
1199
Jean Delvare40ac1992008-07-16 19:30:12 +02001200static int fschmd_remove(struct i2c_client *client)
Hans de Goede569ff102007-10-11 08:06:29 -04001201{
1202 struct fschmd_data *data = i2c_get_clientdata(client);
Jean Delvare40ac1992008-07-16 19:30:12 +02001203 int i;
Hans de Goede569ff102007-10-11 08:06:29 -04001204
Hans de Goede97950c32009-01-07 16:37:33 +01001205 /* Unregister the watchdog (if registered) */
1206 if (data->watchdog_miscdev.minor) {
1207 misc_deregister(&data->watchdog_miscdev);
1208 if (data->watchdog_is_open) {
1209 dev_warn(&client->dev,
1210 "i2c client detached with watchdog open! "
1211 "Stopping watchdog.\n");
1212 watchdog_stop(data);
1213 }
1214 mutex_lock(&watchdog_data_mutex);
1215 list_del(&data->list);
1216 mutex_unlock(&watchdog_data_mutex);
1217 /* Tell the watchdog code the client is gone */
1218 mutex_lock(&data->watchdog_lock);
1219 data->client = NULL;
1220 mutex_unlock(&data->watchdog_lock);
1221 }
1222
Hans de Goede569ff102007-10-11 08:06:29 -04001223 /* Check if registered in case we're called from fschmd_detect
1224 to cleanup after an error */
1225 if (data->hwmon_dev)
1226 hwmon_device_unregister(data->hwmon_dev);
1227
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001228 device_remove_file(&client->dev, &dev_attr_alert_led);
1229 for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001230 device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
1231 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
1232 device_remove_file(&client->dev,
1233 &fschmd_temp_attr[i].dev_attr);
1234 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
1235 device_remove_file(&client->dev,
1236 &fschmd_fan_attr[i].dev_attr);
1237
Hans de Goede97950c32009-01-07 16:37:33 +01001238 mutex_lock(&watchdog_data_mutex);
1239 kref_put(&data->kref, fschmd_release_resources);
1240 mutex_unlock(&watchdog_data_mutex);
1241
Hans de Goede569ff102007-10-11 08:06:29 -04001242 return 0;
1243}
1244
1245static struct fschmd_data *fschmd_update_device(struct device *dev)
1246{
1247 struct i2c_client *client = to_i2c_client(dev);
1248 struct fschmd_data *data = i2c_get_clientdata(client);
1249 int i;
1250
1251 mutex_lock(&data->update_lock);
1252
1253 if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
1254
1255 for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
1256 data->temp_act[i] = i2c_smbus_read_byte_data(client,
1257 FSCHMD_REG_TEMP_ACT[data->kind][i]);
1258 data->temp_status[i] = i2c_smbus_read_byte_data(client,
1259 FSCHMD_REG_TEMP_STATE[data->kind][i]);
1260
1261 /* The fscpos doesn't have TEMP_LIMIT registers */
1262 if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
1263 data->temp_max[i] = i2c_smbus_read_byte_data(
1264 client,
1265 FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
1266
1267 /* reset alarm if the alarm condition is gone,
1268 the chip doesn't do this itself */
1269 if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
1270 FSCHMD_TEMP_ALARM_MASK &&
1271 data->temp_act[i] < data->temp_max[i])
1272 i2c_smbus_write_byte_data(client,
1273 FSCHMD_REG_TEMP_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001274 data->temp_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001275 }
1276
1277 for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
1278 data->fan_act[i] = i2c_smbus_read_byte_data(client,
1279 FSCHMD_REG_FAN_ACT[data->kind][i]);
1280 data->fan_status[i] = i2c_smbus_read_byte_data(client,
1281 FSCHMD_REG_FAN_STATE[data->kind][i]);
1282 data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
1283 FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
1284
1285 /* The fscpos third fan doesn't have a fan_min */
1286 if (FSCHMD_REG_FAN_MIN[data->kind][i])
1287 data->fan_min[i] = i2c_smbus_read_byte_data(
1288 client,
1289 FSCHMD_REG_FAN_MIN[data->kind][i]);
1290
1291 /* reset fan status if speed is back to > 0 */
Hans de Goede453e3082009-01-07 16:37:33 +01001292 if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
Hans de Goede569ff102007-10-11 08:06:29 -04001293 data->fan_act[i])
1294 i2c_smbus_write_byte_data(client,
1295 FSCHMD_REG_FAN_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001296 data->fan_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001297 }
1298
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001299 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001300 data->volt[i] = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001301 FSCHMD_REG_VOLT[data->kind][i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001302
Hans de Goede569ff102007-10-11 08:06:29 -04001303 data->last_updated = jiffies;
1304 data->valid = 1;
1305 }
1306
1307 mutex_unlock(&data->update_lock);
1308
1309 return data;
1310}
1311
1312static int __init fschmd_init(void)
1313{
1314 return i2c_add_driver(&fschmd_driver);
1315}
1316
1317static void __exit fschmd_exit(void)
1318{
1319 i2c_del_driver(&fschmd_driver);
1320}
1321
Hans de Goede453e3082009-01-07 16:37:33 +01001322MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001323MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall and "
1324 "Syleus driver");
Hans de Goede569ff102007-10-11 08:06:29 -04001325MODULE_LICENSE("GPL");
1326
1327module_init(fschmd_init);
1328module_exit(fschmd_exit);