blob: 0627f7a5b9b822462f36341d8889f6bfb33c1986 [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 Goedede15f092009-03-30 21:46:45 +020022 * Scylla, Heracles, Heimdall, Hades 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) ")");
Jean Delvaree5e9f442009-12-14 21:17:27 +010059
60enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
Hans de Goede569ff102007-10-11 08:06:29 -040061
62/*
63 * The FSCHMD registers and other defines
64 */
65
66/* chip identification */
67#define FSCHMD_REG_IDENT_0 0x00
68#define FSCHMD_REG_IDENT_1 0x01
69#define FSCHMD_REG_IDENT_2 0x02
70#define FSCHMD_REG_REVISION 0x03
71
72/* global control and status */
73#define FSCHMD_REG_EVENT_STATE 0x04
74#define FSCHMD_REG_CONTROL 0x05
75
Hans de Goede453e3082009-01-07 16:37:33 +010076#define FSCHMD_CONTROL_ALERT_LED 0x01
Hans de Goede569ff102007-10-11 08:06:29 -040077
Hans de Goede97950c32009-01-07 16:37:33 +010078/* watchdog */
Hans de Goedede15f092009-03-30 21:46:45 +020079static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
80 { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
81static const u8 FSCHMD_REG_WDOG_STATE[7] =
82 { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
83static const u8 FSCHMD_REG_WDOG_PRESET[7] =
84 { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
Hans de Goede569ff102007-10-11 08:06:29 -040085
Hans de Goede97950c32009-01-07 16:37:33 +010086#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
87#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
88#define FSCHMD_WDOG_CONTROL_STOP 0x20
89#define FSCHMD_WDOG_CONTROL_RESOLUTION 0x40
90
91#define FSCHMD_WDOG_STATE_CARDRESET 0x02
92
Hans de Goede569ff102007-10-11 08:06:29 -040093/* voltages, weird order is to keep the same order as the old drivers */
Hans de Goedede15f092009-03-30 21:46:45 +020094static const u8 FSCHMD_REG_VOLT[7][6] = {
Hans de Goedec69ab2b2009-03-30 21:46:45 +020095 { 0x45, 0x42, 0x48 }, /* pos */
96 { 0x45, 0x42, 0x48 }, /* her */
97 { 0x45, 0x42, 0x48 }, /* scy */
98 { 0x45, 0x42, 0x48 }, /* hrc */
99 { 0x45, 0x42, 0x48 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200100 { 0x21, 0x20, 0x22 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200101 { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */
102};
103
Hans de Goedede15f092009-03-30 21:46:45 +0200104static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
Hans de Goede569ff102007-10-11 08:06:29 -0400105
106/* minimum pwm at which the fan is driven (pwm can by increased depending on
107 the temp. Notice that for the scy some fans share there minimum speed.
Frederik Schwarzer025dfda2008-10-16 19:02:37 +0200108 Also notice that with the scy the sensor order is different than with the
Hans de Goede569ff102007-10-11 08:06:29 -0400109 other chips, this order was in the 2.4 driver and kept for consistency. */
Hans de Goedede15f092009-03-30 21:46:45 +0200110static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400111 { 0x55, 0x65 }, /* pos */
112 { 0x55, 0x65, 0xb5 }, /* her */
113 { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
114 { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
115 { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200116 { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200117 { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400118};
119
120/* actual fan speed */
Hans de Goedede15f092009-03-30 21:46:45 +0200121static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400122 { 0x0e, 0x6b, 0xab }, /* pos */
123 { 0x0e, 0x6b, 0xbb }, /* her */
124 { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
125 { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
126 { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200127 { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200128 { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400129};
130
131/* fan status registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200132static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400133 { 0x0d, 0x62, 0xa2 }, /* pos */
134 { 0x0d, 0x62, 0xb2 }, /* her */
135 { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
136 { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
137 { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200138 { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200139 { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400140};
141
142/* fan ripple / divider registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200143static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400144 { 0x0f, 0x6f, 0xaf }, /* pos */
145 { 0x0f, 0x6f, 0xbf }, /* her */
146 { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
147 { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
148 { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200149 { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200150 { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400151};
152
Hans de Goedede15f092009-03-30 21:46:45 +0200153static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
Hans de Goede569ff102007-10-11 08:06:29 -0400154
155/* Fan status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100156#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200157#define FSCHMD_FAN_NOT_PRESENT 0x08
158#define FSCHMD_FAN_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400159
160
161/* actual temperature registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200162static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400163 { 0x64, 0x32, 0x35 }, /* pos */
164 { 0x64, 0x32, 0x35 }, /* her */
165 { 0x64, 0xD0, 0x32, 0x35 }, /* scy */
166 { 0x64, 0x32, 0x35 }, /* hrc */
167 { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200168 { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200169 { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */
170 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
Hans de Goede569ff102007-10-11 08:06:29 -0400171};
172
173/* temperature state registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200174static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400175 { 0x71, 0x81, 0x91 }, /* pos */
176 { 0x71, 0x81, 0x91 }, /* her */
177 { 0x71, 0xd1, 0x81, 0x91 }, /* scy */
178 { 0x71, 0x81, 0x91 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500179 { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200180 { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200181 { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */
182 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
Hans de Goede569ff102007-10-11 08:06:29 -0400183};
184
185/* temperature high limit registers, FSC does not document these. Proven to be
186 there with field testing on the fscher and fschrc, already supported / used
187 in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
188 at these addresses, but doesn't want to confirm they are the same as with
189 the fscher?? */
Hans de Goedede15f092009-03-30 21:46:45 +0200190static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400191 { 0, 0, 0 }, /* pos */
192 { 0x76, 0x86, 0x96 }, /* her */
193 { 0x76, 0xd6, 0x86, 0x96 }, /* scy */
194 { 0x76, 0x86, 0x96 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500195 { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200196 { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200197 { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */
198 0xba, 0xca, 0xda, 0xea, 0xfa },
Hans de Goede569ff102007-10-11 08:06:29 -0400199};
200
201/* These were found through experimenting with an fscher, currently they are
202 not used, but we keep them around for future reference.
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200203 On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
204 AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
205 the fan speed.
Hans de Goede569ff102007-10-11 08:06:29 -0400206static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
207static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
208
Hans de Goedede15f092009-03-30 21:46:45 +0200209static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
Hans de Goede569ff102007-10-11 08:06:29 -0400210
211/* temp status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100212#define FSCHMD_TEMP_WORKING 0x01
213#define FSCHMD_TEMP_ALERT 0x02
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200214#define FSCHMD_TEMP_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400215/* there only really is an alarm if the sensor is working and alert == 1 */
216#define FSCHMD_TEMP_ALARM_MASK \
Hans de Goede453e3082009-01-07 16:37:33 +0100217 (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
Hans de Goede569ff102007-10-11 08:06:29 -0400218
219/*
220 * Functions declarations
221 */
222
Jean Delvare40ac1992008-07-16 19:30:12 +0200223static int fschmd_probe(struct i2c_client *client,
224 const struct i2c_device_id *id);
Jean Delvare310ec792009-12-14 21:17:23 +0100225static int fschmd_detect(struct i2c_client *client,
Jean Delvare40ac1992008-07-16 19:30:12 +0200226 struct i2c_board_info *info);
227static int fschmd_remove(struct i2c_client *client);
Hans de Goede569ff102007-10-11 08:06:29 -0400228static struct fschmd_data *fschmd_update_device(struct device *dev);
229
230/*
231 * Driver data (common to all clients)
232 */
233
Jean Delvare40ac1992008-07-16 19:30:12 +0200234static const struct i2c_device_id fschmd_id[] = {
235 { "fscpos", fscpos },
236 { "fscher", fscher },
237 { "fscscy", fscscy },
238 { "fschrc", fschrc },
239 { "fschmd", fschmd },
Hans de Goedede15f092009-03-30 21:46:45 +0200240 { "fschds", fschds },
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200241 { "fscsyl", fscsyl },
Jean Delvare40ac1992008-07-16 19:30:12 +0200242 { }
243};
244MODULE_DEVICE_TABLE(i2c, fschmd_id);
245
Hans de Goede569ff102007-10-11 08:06:29 -0400246static struct i2c_driver fschmd_driver = {
Jean Delvare40ac1992008-07-16 19:30:12 +0200247 .class = I2C_CLASS_HWMON,
Hans de Goede569ff102007-10-11 08:06:29 -0400248 .driver = {
Hans de Goede453e3082009-01-07 16:37:33 +0100249 .name = "fschmd",
Hans de Goede569ff102007-10-11 08:06:29 -0400250 },
Jean Delvare40ac1992008-07-16 19:30:12 +0200251 .probe = fschmd_probe,
252 .remove = fschmd_remove,
253 .id_table = fschmd_id,
254 .detect = fschmd_detect,
Jean Delvarec3813d62009-12-14 21:17:25 +0100255 .address_list = normal_i2c,
Hans de Goede569ff102007-10-11 08:06:29 -0400256};
257
258/*
259 * Client data (each client gets its own)
260 */
261
262struct fschmd_data {
Hans de Goede97950c32009-01-07 16:37:33 +0100263 struct i2c_client *client;
Hans de Goede569ff102007-10-11 08:06:29 -0400264 struct device *hwmon_dev;
265 struct mutex update_lock;
Hans de Goede97950c32009-01-07 16:37:33 +0100266 struct mutex watchdog_lock;
267 struct list_head list; /* member of the watchdog_data_list */
268 struct kref kref;
269 struct miscdevice watchdog_miscdev;
Jean Delvaredc71afe2010-03-05 22:17:26 +0100270 enum chips kind;
Hans de Goede97950c32009-01-07 16:37:33 +0100271 unsigned long watchdog_is_open;
272 char watchdog_expect_close;
273 char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
Hans de Goede569ff102007-10-11 08:06:29 -0400274 char valid; /* zero until following fields are valid */
275 unsigned long last_updated; /* in jiffies */
276
277 /* register values */
Hans de Goede97950c32009-01-07 16:37:33 +0100278 u8 revision; /* chip revision */
Hans de Goede569ff102007-10-11 08:06:29 -0400279 u8 global_control; /* global control register */
Hans de Goede97950c32009-01-07 16:37:33 +0100280 u8 watchdog_control; /* watchdog control register */
281 u8 watchdog_state; /* watchdog status register */
282 u8 watchdog_preset; /* watchdog counter preset on trigger val */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200283 u8 volt[6]; /* voltage */
284 u8 temp_act[11]; /* temperature */
285 u8 temp_status[11]; /* status of sensor */
286 u8 temp_max[11]; /* high temp limit, notice: undocumented! */
287 u8 fan_act[7]; /* fans revolutions per second */
288 u8 fan_status[7]; /* fan status */
289 u8 fan_min[7]; /* fan min value for rps */
290 u8 fan_ripple[7]; /* divider for rps */
Hans de Goede569ff102007-10-11 08:06:29 -0400291};
292
Hans de Goede7845cd72007-12-20 16:42:59 +0100293/* Global variables to hold information read from special DMI tables, which are
Hans de Goede97950c32009-01-07 16:37:33 +0100294 available on FSC machines with an fscher or later chip. There is no need to
295 protect these with a lock as they are only modified from our attach function
296 which always gets called with the i2c-core lock held and never accessed
297 before the attach function is done with them. */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200298static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
299static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
Hans de Goede7845cd72007-12-20 16:42:59 +0100300static int dmi_vref = -1;
301
Hans de Goede97950c32009-01-07 16:37:33 +0100302/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
303 we can find our device data as when using misc_register there is no other
304 method to get to ones device data from the open fop. */
305static LIST_HEAD(watchdog_data_list);
306/* Note this lock not only protect list access, but also data.kref access */
307static DEFINE_MUTEX(watchdog_data_mutex);
308
309/* Release our data struct when we're detached from the i2c client *and* all
310 references to our watchdog device are released */
311static void fschmd_release_resources(struct kref *ref)
312{
313 struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
314 kfree(data);
315}
Hans de Goede7845cd72007-12-20 16:42:59 +0100316
Hans de Goede569ff102007-10-11 08:06:29 -0400317/*
318 * Sysfs attr show / store functions
319 */
320
321static ssize_t show_in_value(struct device *dev,
322 struct device_attribute *devattr, char *buf)
323{
324 const int max_reading[3] = { 14200, 6600, 3300 };
325 int index = to_sensor_dev_attr(devattr)->index;
326 struct fschmd_data *data = fschmd_update_device(dev);
327
Jean Delvaredc71afe2010-03-05 22:17:26 +0100328 if (data->kind == fscher || data->kind >= fschrc)
Hans de Goede7845cd72007-12-20 16:42:59 +0100329 return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
330 dmi_mult[index]) / 255 + dmi_offset[index]);
331 else
332 return sprintf(buf, "%d\n", (data->volt[index] *
333 max_reading[index] + 128) / 255);
Hans de Goede569ff102007-10-11 08:06:29 -0400334}
335
336
337#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
338
339static ssize_t show_temp_value(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_act[index]));
346}
347
348static ssize_t show_temp_max(struct device *dev,
349 struct device_attribute *devattr, char *buf)
350{
351 int index = to_sensor_dev_attr(devattr)->index;
352 struct fschmd_data *data = fschmd_update_device(dev);
353
354 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
355}
356
357static ssize_t store_temp_max(struct device *dev, struct device_attribute
358 *devattr, const char *buf, size_t count)
359{
360 int index = to_sensor_dev_attr(devattr)->index;
361 struct fschmd_data *data = dev_get_drvdata(dev);
362 long v = simple_strtol(buf, NULL, 10) / 1000;
363
364 v = SENSORS_LIMIT(v, -128, 127) + 128;
365
366 mutex_lock(&data->update_lock);
Jean Delvare40ac1992008-07-16 19:30:12 +0200367 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400368 FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
369 data->temp_max[index] = v;
370 mutex_unlock(&data->update_lock);
371
372 return count;
373}
374
375static ssize_t show_temp_fault(struct device *dev,
376 struct device_attribute *devattr, char *buf)
377{
378 int index = to_sensor_dev_attr(devattr)->index;
379 struct fschmd_data *data = fschmd_update_device(dev);
380
381 /* bit 0 set means sensor working ok, so no fault! */
Hans de Goede453e3082009-01-07 16:37:33 +0100382 if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
Hans de Goede569ff102007-10-11 08:06:29 -0400383 return sprintf(buf, "0\n");
384 else
385 return sprintf(buf, "1\n");
386}
387
388static ssize_t show_temp_alarm(struct device *dev,
389 struct device_attribute *devattr, char *buf)
390{
391 int index = to_sensor_dev_attr(devattr)->index;
392 struct fschmd_data *data = fschmd_update_device(dev);
393
394 if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
395 FSCHMD_TEMP_ALARM_MASK)
396 return sprintf(buf, "1\n");
397 else
398 return sprintf(buf, "0\n");
399}
400
401
402#define RPM_FROM_REG(val) ((val) * 60)
403
404static ssize_t show_fan_value(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 return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
411}
412
413static ssize_t show_fan_div(struct device *dev,
414 struct device_attribute *devattr, char *buf)
415{
416 int index = to_sensor_dev_attr(devattr)->index;
417 struct fschmd_data *data = fschmd_update_device(dev);
418
419 /* bits 2..7 reserved => mask with 3 */
420 return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
421}
422
423static ssize_t store_fan_div(struct device *dev, struct device_attribute
424 *devattr, const char *buf, size_t count)
425{
426 u8 reg;
427 int index = to_sensor_dev_attr(devattr)->index;
428 struct fschmd_data *data = dev_get_drvdata(dev);
429 /* supported values: 2, 4, 8 */
430 unsigned long v = simple_strtoul(buf, NULL, 10);
431
432 switch (v) {
433 case 2: v = 1; break;
434 case 4: v = 2; break;
435 case 8: v = 3; break;
436 default:
437 dev_err(dev, "fan_div value %lu not supported. "
438 "Choose one of 2, 4 or 8!\n", v);
439 return -EINVAL;
440 }
441
442 mutex_lock(&data->update_lock);
443
Jean Delvare40ac1992008-07-16 19:30:12 +0200444 reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400445 FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
446
447 /* bits 2..7 reserved => mask with 0x03 */
448 reg &= ~0x03;
449 reg |= v;
450
Jean Delvare40ac1992008-07-16 19:30:12 +0200451 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400452 FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
453
454 data->fan_ripple[index] = reg;
455
456 mutex_unlock(&data->update_lock);
457
458 return count;
459}
460
461static ssize_t show_fan_alarm(struct device *dev,
462 struct device_attribute *devattr, char *buf)
463{
464 int index = to_sensor_dev_attr(devattr)->index;
465 struct fschmd_data *data = fschmd_update_device(dev);
466
Hans de Goede453e3082009-01-07 16:37:33 +0100467 if (data->fan_status[index] & FSCHMD_FAN_ALARM)
Hans de Goede569ff102007-10-11 08:06:29 -0400468 return sprintf(buf, "1\n");
469 else
470 return sprintf(buf, "0\n");
471}
472
473static ssize_t show_fan_fault(struct device *dev,
474 struct device_attribute *devattr, char *buf)
475{
476 int index = to_sensor_dev_attr(devattr)->index;
477 struct fschmd_data *data = fschmd_update_device(dev);
478
Hans de Goede453e3082009-01-07 16:37:33 +0100479 if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
Hans de Goede569ff102007-10-11 08:06:29 -0400480 return sprintf(buf, "1\n");
481 else
482 return sprintf(buf, "0\n");
483}
484
485
486static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
487 struct device_attribute *devattr, char *buf)
488{
489 int index = to_sensor_dev_attr(devattr)->index;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200490 struct fschmd_data *data = fschmd_update_device(dev);
491 int val = data->fan_min[index];
Hans de Goede569ff102007-10-11 08:06:29 -0400492
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200493 /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
Jean Delvaredc71afe2010-03-05 22:17:26 +0100494 if (val || data->kind == fscsyl)
Hans de Goede569ff102007-10-11 08:06:29 -0400495 val = val / 2 + 128;
496
497 return sprintf(buf, "%d\n", val);
498}
499
500static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
501 struct device_attribute *devattr, const char *buf, size_t count)
502{
503 int index = to_sensor_dev_attr(devattr)->index;
504 struct fschmd_data *data = dev_get_drvdata(dev);
505 unsigned long v = simple_strtoul(buf, NULL, 10);
506
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200507 /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
Jean Delvaredc71afe2010-03-05 22:17:26 +0100508 if (v || data->kind == fscsyl) {
Hans de Goede569ff102007-10-11 08:06:29 -0400509 v = SENSORS_LIMIT(v, 128, 255);
510 v = (v - 128) * 2 + 1;
511 }
512
513 mutex_lock(&data->update_lock);
514
Jean Delvare40ac1992008-07-16 19:30:12 +0200515 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400516 FSCHMD_REG_FAN_MIN[data->kind][index], v);
517 data->fan_min[index] = v;
518
519 mutex_unlock(&data->update_lock);
520
521 return count;
522}
523
524
525/* The FSC hwmon family has the ability to force an attached alert led to flash
526 from software, we export this as an alert_led sysfs attr */
527static ssize_t show_alert_led(struct device *dev,
528 struct device_attribute *devattr, char *buf)
529{
530 struct fschmd_data *data = fschmd_update_device(dev);
531
Hans de Goede453e3082009-01-07 16:37:33 +0100532 if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
Hans de Goede569ff102007-10-11 08:06:29 -0400533 return sprintf(buf, "1\n");
534 else
535 return sprintf(buf, "0\n");
536}
537
538static ssize_t store_alert_led(struct device *dev,
539 struct device_attribute *devattr, const char *buf, size_t count)
540{
541 u8 reg;
542 struct fschmd_data *data = dev_get_drvdata(dev);
543 unsigned long v = simple_strtoul(buf, NULL, 10);
544
545 mutex_lock(&data->update_lock);
546
Jean Delvare40ac1992008-07-16 19:30:12 +0200547 reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
Hans de Goede569ff102007-10-11 08:06:29 -0400548
549 if (v)
Hans de Goede453e3082009-01-07 16:37:33 +0100550 reg |= FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400551 else
Hans de Goede453e3082009-01-07 16:37:33 +0100552 reg &= ~FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400553
Jean Delvare40ac1992008-07-16 19:30:12 +0200554 i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
Hans de Goede569ff102007-10-11 08:06:29 -0400555
556 data->global_control = reg;
557
558 mutex_unlock(&data->update_lock);
559
560 return count;
561}
562
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200563static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
564
Hans de Goede569ff102007-10-11 08:06:29 -0400565static struct sensor_device_attribute fschmd_attr[] = {
566 SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
567 SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
568 SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200569 SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
570 SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
571 SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
Hans de Goede569ff102007-10-11 08:06:29 -0400572};
573
574static struct sensor_device_attribute fschmd_temp_attr[] = {
575 SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
576 SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
577 SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
578 SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
579 SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
580 SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
581 SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
582 SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
583 SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
584 SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
585 SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
586 SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
587 SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
588 SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
589 SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
590 SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
591 SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
592 SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
593 SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
594 SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200595 SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
596 SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5),
597 SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
598 SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
599 SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
600 SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6),
601 SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
602 SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
603 SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
604 SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7),
605 SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
606 SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
607 SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
608 SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8),
609 SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
610 SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
611 SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
612 SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9),
613 SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
614 SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
615 SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
616 SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10),
617 SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
618 SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
Hans de Goede569ff102007-10-11 08:06:29 -0400619};
620
621static struct sensor_device_attribute fschmd_fan_attr[] = {
622 SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
623 SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
624 SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
625 SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
626 SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
627 store_pwm_auto_point1_pwm, 0),
628 SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
629 SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
630 SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
631 SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
632 SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
633 store_pwm_auto_point1_pwm, 1),
634 SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
635 SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
636 SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
637 SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
638 SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
639 store_pwm_auto_point1_pwm, 2),
640 SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
641 SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
642 SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
643 SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
644 SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
645 store_pwm_auto_point1_pwm, 3),
646 SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
647 SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
648 SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
649 SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
650 SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
651 store_pwm_auto_point1_pwm, 4),
652 SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
653 SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
654 SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
655 SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
656 SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
657 store_pwm_auto_point1_pwm, 5),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200658 SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
659 SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6),
660 SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
661 SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
662 SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
663 store_pwm_auto_point1_pwm, 6),
Hans de Goede569ff102007-10-11 08:06:29 -0400664};
665
666
667/*
Hans de Goede97950c32009-01-07 16:37:33 +0100668 * Watchdog routines
669 */
670
671static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
672{
673 int ret, resolution;
674 int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
675
676 /* 2 second or 60 second resolution? */
677 if (timeout <= 510 || kind == fscpos || kind == fscscy)
678 resolution = 2;
679 else
680 resolution = 60;
681
682 if (timeout < resolution || timeout > (resolution * 255))
683 return -EINVAL;
684
685 mutex_lock(&data->watchdog_lock);
686 if (!data->client) {
687 ret = -ENODEV;
688 goto leave;
689 }
690
691 if (resolution == 2)
692 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
693 else
694 data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
695
696 data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
697
698 /* Write new timeout value */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200699 i2c_smbus_write_byte_data(data->client,
700 FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
Hans de Goede97950c32009-01-07 16:37:33 +0100701 /* Write new control register, do not trigger! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200702 i2c_smbus_write_byte_data(data->client,
703 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100704 data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
705
706 ret = data->watchdog_preset * resolution;
707
708leave:
709 mutex_unlock(&data->watchdog_lock);
710 return ret;
711}
712
713static int watchdog_get_timeout(struct fschmd_data *data)
714{
715 int timeout;
716
717 mutex_lock(&data->watchdog_lock);
718 if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
719 timeout = data->watchdog_preset * 60;
720 else
721 timeout = data->watchdog_preset * 2;
722 mutex_unlock(&data->watchdog_lock);
723
724 return timeout;
725}
726
727static int watchdog_trigger(struct fschmd_data *data)
728{
729 int ret = 0;
730
731 mutex_lock(&data->watchdog_lock);
732 if (!data->client) {
733 ret = -ENODEV;
734 goto leave;
735 }
736
737 data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200738 i2c_smbus_write_byte_data(data->client,
739 FSCHMD_REG_WDOG_CONTROL[data->kind],
740 data->watchdog_control);
Hans de Goede97950c32009-01-07 16:37:33 +0100741leave:
742 mutex_unlock(&data->watchdog_lock);
743 return ret;
744}
745
746static int watchdog_stop(struct fschmd_data *data)
747{
748 int ret = 0;
749
750 mutex_lock(&data->watchdog_lock);
751 if (!data->client) {
752 ret = -ENODEV;
753 goto leave;
754 }
755
756 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
757 /* Don't store the stop flag in our watchdog control register copy, as
758 its a write only bit (read always returns 0) */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200759 i2c_smbus_write_byte_data(data->client,
760 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100761 data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
762leave:
763 mutex_unlock(&data->watchdog_lock);
764 return ret;
765}
766
767static int watchdog_open(struct inode *inode, struct file *filp)
768{
769 struct fschmd_data *pos, *data = NULL;
Hans de Goedec4536152010-01-25 15:00:50 +0100770 int watchdog_is_open;
Hans de Goede97950c32009-01-07 16:37:33 +0100771
772 /* We get called from drivers/char/misc.c with misc_mtx hold, and we
773 call misc_register() from fschmd_probe() with watchdog_data_mutex
774 hold, as misc_register() takes the misc_mtx lock, this is a possible
775 deadlock, so we use mutex_trylock here. */
776 if (!mutex_trylock(&watchdog_data_mutex))
777 return -ERESTARTSYS;
778 list_for_each_entry(pos, &watchdog_data_list, list) {
779 if (pos->watchdog_miscdev.minor == iminor(inode)) {
780 data = pos;
781 break;
782 }
783 }
784 /* Note we can never not have found data, so we don't check for this */
Hans de Goedec4536152010-01-25 15:00:50 +0100785 watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
786 if (!watchdog_is_open)
787 kref_get(&data->kref);
Hans de Goede97950c32009-01-07 16:37:33 +0100788 mutex_unlock(&watchdog_data_mutex);
789
Hans de Goedec4536152010-01-25 15:00:50 +0100790 if (watchdog_is_open)
Hans de Goede97950c32009-01-07 16:37:33 +0100791 return -EBUSY;
792
793 /* Start the watchdog */
794 watchdog_trigger(data);
795 filp->private_data = data;
796
797 return nonseekable_open(inode, filp);
798}
799
800static int watchdog_release(struct inode *inode, struct file *filp)
801{
802 struct fschmd_data *data = filp->private_data;
803
804 if (data->watchdog_expect_close) {
805 watchdog_stop(data);
806 data->watchdog_expect_close = 0;
807 } else {
808 watchdog_trigger(data);
809 dev_crit(&data->client->dev,
810 "unexpected close, not stopping watchdog!\n");
811 }
812
813 clear_bit(0, &data->watchdog_is_open);
814
815 mutex_lock(&watchdog_data_mutex);
816 kref_put(&data->kref, fschmd_release_resources);
817 mutex_unlock(&watchdog_data_mutex);
818
819 return 0;
820}
821
822static ssize_t watchdog_write(struct file *filp, const char __user *buf,
823 size_t count, loff_t *offset)
824{
Roel Kluinc7702c32009-10-24 13:28:45 +0200825 int ret;
Hans de Goede97950c32009-01-07 16:37:33 +0100826 struct fschmd_data *data = filp->private_data;
827
828 if (count) {
829 if (!nowayout) {
830 size_t i;
831
832 /* Clear it in case it was set with a previous write */
833 data->watchdog_expect_close = 0;
834
835 for (i = 0; i != count; i++) {
836 char c;
837 if (get_user(c, buf + i))
838 return -EFAULT;
839 if (c == 'V')
840 data->watchdog_expect_close = 1;
841 }
842 }
843 ret = watchdog_trigger(data);
844 if (ret < 0)
845 return ret;
846 }
847 return count;
848}
849
850static int watchdog_ioctl(struct inode *inode, struct file *filp,
851 unsigned int cmd, unsigned long arg)
852{
853 static struct watchdog_info ident = {
854 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
855 WDIOF_CARDRESET,
856 .identity = "FSC watchdog"
857 };
858 int i, ret = 0;
859 struct fschmd_data *data = filp->private_data;
860
861 switch (cmd) {
862 case WDIOC_GETSUPPORT:
863 ident.firmware_version = data->revision;
864 if (!nowayout)
865 ident.options |= WDIOF_MAGICCLOSE;
866 if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
867 ret = -EFAULT;
868 break;
869
870 case WDIOC_GETSTATUS:
871 ret = put_user(0, (int __user *)arg);
872 break;
873
874 case WDIOC_GETBOOTSTATUS:
875 if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
876 ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
877 else
878 ret = put_user(0, (int __user *)arg);
879 break;
880
881 case WDIOC_KEEPALIVE:
882 ret = watchdog_trigger(data);
883 break;
884
885 case WDIOC_GETTIMEOUT:
886 i = watchdog_get_timeout(data);
887 ret = put_user(i, (int __user *)arg);
888 break;
889
890 case WDIOC_SETTIMEOUT:
891 if (get_user(i, (int __user *)arg)) {
892 ret = -EFAULT;
893 break;
894 }
895 ret = watchdog_set_timeout(data, i);
896 if (ret > 0)
897 ret = put_user(ret, (int __user *)arg);
898 break;
899
900 case WDIOC_SETOPTIONS:
901 if (get_user(i, (int __user *)arg)) {
902 ret = -EFAULT;
903 break;
904 }
905
906 if (i & WDIOS_DISABLECARD)
907 ret = watchdog_stop(data);
908 else if (i & WDIOS_ENABLECARD)
909 ret = watchdog_trigger(data);
910 else
911 ret = -EINVAL;
912
913 break;
914 default:
915 ret = -ENOTTY;
916 }
917
918 return ret;
919}
920
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700921static const struct file_operations watchdog_fops = {
Hans de Goede97950c32009-01-07 16:37:33 +0100922 .owner = THIS_MODULE,
923 .llseek = no_llseek,
924 .open = watchdog_open,
925 .release = watchdog_release,
926 .write = watchdog_write,
927 .ioctl = watchdog_ioctl,
928};
929
930
931/*
932 * Detect, register, unregister and update device functions
Hans de Goede569ff102007-10-11 08:06:29 -0400933 */
934
Hans de Goede7845cd72007-12-20 16:42:59 +0100935/* DMI decode routine to read voltage scaling factors from special DMI tables,
936 which are available on FSC machines with an fscher or later chip. */
Jean Delvaree7a19c562009-03-30 21:46:44 +0200937static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
Hans de Goede7845cd72007-12-20 16:42:59 +0100938{
939 int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
940
941 /* dmi code ugliness, we get passed the address of the contents of
942 a complete DMI record, but in the form of a dmi_header pointer, in
943 reality this address holds header->length bytes of which the header
944 are the first 4 bytes */
945 u8 *dmi_data = (u8 *)header;
946
947 /* We are looking for OEM-specific type 185 */
948 if (header->type != 185)
949 return;
950
951 /* we are looking for what Siemens calls "subtype" 19, the subtype
952 is stored in byte 5 of the dmi block */
953 if (header->length < 5 || dmi_data[4] != 19)
954 return;
955
956 /* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
957 consisting of what Siemens calls an "Entity" number, followed by
958 2 16-bit words in LSB first order */
959 for (i = 6; (i + 4) < header->length; i += 5) {
960 /* entity 1 - 3: voltage multiplier and offset */
961 if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
962 /* Our in sensors order and the DMI order differ */
963 const int shuffle[3] = { 1, 0, 2 };
964 int in = shuffle[dmi_data[i] - 1];
965
966 /* Check for twice the same entity */
967 if (found & (1 << in))
968 return;
969
970 mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
971 offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
972
973 found |= 1 << in;
974 }
975
976 /* entity 7: reference voltage */
977 if (dmi_data[i] == 7) {
978 /* Check for twice the same entity */
979 if (found & 0x08)
980 return;
981
982 vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
983
984 found |= 0x08;
985 }
986 }
987
988 if (found == 0x0F) {
989 for (i = 0; i < 3; i++) {
990 dmi_mult[i] = mult[i] * 10;
991 dmi_offset[i] = offset[i] * 10;
992 }
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200993 /* According to the docs there should be separate dmi entries
994 for the mult's and offsets of in3-5 of the syl, but on
995 my test machine these are not present */
996 dmi_mult[3] = dmi_mult[2];
997 dmi_mult[4] = dmi_mult[1];
998 dmi_mult[5] = dmi_mult[2];
999 dmi_offset[3] = dmi_offset[2];
1000 dmi_offset[4] = dmi_offset[1];
1001 dmi_offset[5] = dmi_offset[2];
Hans de Goede7845cd72007-12-20 16:42:59 +01001002 dmi_vref = vref;
1003 }
1004}
1005
Jean Delvare310ec792009-12-14 21:17:23 +01001006static int fschmd_detect(struct i2c_client *client,
Jean Delvare40ac1992008-07-16 19:30:12 +02001007 struct i2c_board_info *info)
Hans de Goede569ff102007-10-11 08:06:29 -04001008{
Jean Delvare52df6442009-12-09 20:35:57 +01001009 enum chips kind;
Jean Delvare40ac1992008-07-16 19:30:12 +02001010 struct i2c_adapter *adapter = client->adapter;
Jean Delvare52df6442009-12-09 20:35:57 +01001011 char id[4];
Hans de Goede569ff102007-10-11 08:06:29 -04001012
1013 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Jean Delvare40ac1992008-07-16 19:30:12 +02001014 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001015
1016 /* Detect & Identify the chip */
Jean Delvare52df6442009-12-09 20:35:57 +01001017 id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
1018 id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
1019 id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
1020 id[3] = '\0';
Hans de Goede569ff102007-10-11 08:06:29 -04001021
Jean Delvare52df6442009-12-09 20:35:57 +01001022 if (!strcmp(id, "PEG"))
1023 kind = fscpos;
1024 else if (!strcmp(id, "HER"))
1025 kind = fscher;
1026 else if (!strcmp(id, "SCY"))
1027 kind = fscscy;
1028 else if (!strcmp(id, "HRC"))
1029 kind = fschrc;
1030 else if (!strcmp(id, "HMD"))
1031 kind = fschmd;
1032 else if (!strcmp(id, "HDS"))
1033 kind = fschds;
1034 else if (!strcmp(id, "SYL"))
1035 kind = fscsyl;
1036 else
1037 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001038
Jean Delvaredc71afe2010-03-05 22:17:26 +01001039 strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
Jean Delvare40ac1992008-07-16 19:30:12 +02001040
1041 return 0;
1042}
1043
1044static int fschmd_probe(struct i2c_client *client,
1045 const struct i2c_device_id *id)
1046{
1047 struct fschmd_data *data;
Hans de Goedede15f092009-03-30 21:46:45 +02001048 const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
1049 "Heracles", "Heimdall", "Hades", "Syleus" };
Hans de Goede97950c32009-01-07 16:37:33 +01001050 const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
Jean Delvare40ac1992008-07-16 19:30:12 +02001051 int i, err;
1052 enum chips kind = id->driver_data;
1053
1054 data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
1055 if (!data)
1056 return -ENOMEM;
1057
1058 i2c_set_clientdata(client, data);
1059 mutex_init(&data->update_lock);
Hans de Goede97950c32009-01-07 16:37:33 +01001060 mutex_init(&data->watchdog_lock);
1061 INIT_LIST_HEAD(&data->list);
1062 kref_init(&data->kref);
1063 /* Store client pointer in our data struct for watchdog usage
1064 (where the client is found through a data ptr instead of the
1065 otherway around) */
1066 data->client = client;
Jean Delvaredc71afe2010-03-05 22:17:26 +01001067 data->kind = kind;
Jean Delvare40ac1992008-07-16 19:30:12 +02001068
Hans de Goede569ff102007-10-11 08:06:29 -04001069 if (kind == fscpos) {
1070 /* The Poseidon has hardwired temp limits, fill these
1071 in for the alarm resetting code */
1072 data->temp_max[0] = 70 + 128;
1073 data->temp_max[1] = 50 + 128;
1074 data->temp_max[2] = 50 + 128;
1075 }
1076
Hans de Goede7845cd72007-12-20 16:42:59 +01001077 /* Read the special DMI table for fscher and newer chips */
Hans de Goede453e3082009-01-07 16:37:33 +01001078 if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
Jean Delvaree7a19c562009-03-30 21:46:44 +02001079 dmi_walk(fschmd_dmi_decode, NULL);
Hans de Goede7845cd72007-12-20 16:42:59 +01001080 if (dmi_vref == -1) {
Hans de Goede453e3082009-01-07 16:37:33 +01001081 dev_warn(&client->dev,
1082 "Couldn't get voltage scaling factors from "
Hans de Goede7845cd72007-12-20 16:42:59 +01001083 "BIOS DMI table, using builtin defaults\n");
1084 dmi_vref = 33;
1085 }
1086 }
1087
Hans de Goede97950c32009-01-07 16:37:33 +01001088 /* Read in some never changing registers */
1089 data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
1090 data->global_control = i2c_smbus_read_byte_data(client,
1091 FSCHMD_REG_CONTROL);
1092 data->watchdog_control = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001093 FSCHMD_REG_WDOG_CONTROL[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001094 data->watchdog_state = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001095 FSCHMD_REG_WDOG_STATE[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001096 data->watchdog_preset = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001097 FSCHMD_REG_WDOG_PRESET[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001098
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001099 err = device_create_file(&client->dev, &dev_attr_alert_led);
1100 if (err)
1101 goto exit_detach;
Hans de Goede569ff102007-10-11 08:06:29 -04001102
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001103 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
Hans de Goede569ff102007-10-11 08:06:29 -04001104 err = device_create_file(&client->dev,
1105 &fschmd_attr[i].dev_attr);
1106 if (err)
1107 goto exit_detach;
1108 }
1109
1110 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
1111 /* Poseidon doesn't have TEMP_LIMIT registers */
1112 if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
1113 show_temp_max)
1114 continue;
1115
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001116 if (kind == fscsyl) {
1117 if (i % 4 == 0)
1118 data->temp_status[i / 4] =
1119 i2c_smbus_read_byte_data(client,
1120 FSCHMD_REG_TEMP_STATE
1121 [data->kind][i / 4]);
1122 if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
1123 continue;
1124 }
1125
Hans de Goede569ff102007-10-11 08:06:29 -04001126 err = device_create_file(&client->dev,
1127 &fschmd_temp_attr[i].dev_attr);
1128 if (err)
1129 goto exit_detach;
1130 }
1131
1132 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
1133 /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
1134 if (kind == fscpos &&
1135 !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
1136 "pwm3_auto_point1_pwm"))
1137 continue;
1138
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001139 if (kind == fscsyl) {
1140 if (i % 5 == 0)
1141 data->fan_status[i / 5] =
1142 i2c_smbus_read_byte_data(client,
1143 FSCHMD_REG_FAN_STATE
1144 [data->kind][i / 5]);
1145 if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
1146 continue;
1147 }
1148
Hans de Goede569ff102007-10-11 08:06:29 -04001149 err = device_create_file(&client->dev,
1150 &fschmd_fan_attr[i].dev_attr);
1151 if (err)
1152 goto exit_detach;
1153 }
1154
1155 data->hwmon_dev = hwmon_device_register(&client->dev);
1156 if (IS_ERR(data->hwmon_dev)) {
1157 err = PTR_ERR(data->hwmon_dev);
1158 data->hwmon_dev = NULL;
1159 goto exit_detach;
1160 }
1161
Hans de Goede97950c32009-01-07 16:37:33 +01001162 /* We take the data_mutex lock early so that watchdog_open() cannot
1163 run when misc_register() has completed, but we've not yet added
1164 our data to the watchdog_data_list (and set the default timeout) */
1165 mutex_lock(&watchdog_data_mutex);
1166 for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
1167 /* Register our watchdog part */
1168 snprintf(data->watchdog_name, sizeof(data->watchdog_name),
1169 "watchdog%c", (i == 0) ? '\0' : ('0' + i));
1170 data->watchdog_miscdev.name = data->watchdog_name;
1171 data->watchdog_miscdev.fops = &watchdog_fops;
1172 data->watchdog_miscdev.minor = watchdog_minors[i];
1173 err = misc_register(&data->watchdog_miscdev);
1174 if (err == -EBUSY)
1175 continue;
1176 if (err) {
1177 data->watchdog_miscdev.minor = 0;
1178 dev_err(&client->dev,
1179 "Registering watchdog chardev: %d\n", err);
1180 break;
1181 }
1182
1183 list_add(&data->list, &watchdog_data_list);
1184 watchdog_set_timeout(data, 60);
1185 dev_info(&client->dev,
1186 "Registered watchdog chardev major 10, minor: %d\n",
1187 watchdog_minors[i]);
1188 break;
1189 }
1190 if (i == ARRAY_SIZE(watchdog_minors)) {
1191 data->watchdog_miscdev.minor = 0;
1192 dev_warn(&client->dev, "Couldn't register watchdog chardev "
1193 "(due to no free minor)\n");
1194 }
1195 mutex_unlock(&watchdog_data_mutex);
1196
Hans de Goede453e3082009-01-07 16:37:33 +01001197 dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
Hans de Goede97950c32009-01-07 16:37:33 +01001198 names[data->kind], (int) data->revision);
Hans de Goede569ff102007-10-11 08:06:29 -04001199
1200 return 0;
1201
1202exit_detach:
Jean Delvare40ac1992008-07-16 19:30:12 +02001203 fschmd_remove(client); /* will also free data for us */
Hans de Goede569ff102007-10-11 08:06:29 -04001204 return err;
1205}
1206
Jean Delvare40ac1992008-07-16 19:30:12 +02001207static int fschmd_remove(struct i2c_client *client)
Hans de Goede569ff102007-10-11 08:06:29 -04001208{
1209 struct fschmd_data *data = i2c_get_clientdata(client);
Jean Delvare40ac1992008-07-16 19:30:12 +02001210 int i;
Hans de Goede569ff102007-10-11 08:06:29 -04001211
Hans de Goede97950c32009-01-07 16:37:33 +01001212 /* Unregister the watchdog (if registered) */
1213 if (data->watchdog_miscdev.minor) {
1214 misc_deregister(&data->watchdog_miscdev);
1215 if (data->watchdog_is_open) {
1216 dev_warn(&client->dev,
1217 "i2c client detached with watchdog open! "
1218 "Stopping watchdog.\n");
1219 watchdog_stop(data);
1220 }
1221 mutex_lock(&watchdog_data_mutex);
1222 list_del(&data->list);
1223 mutex_unlock(&watchdog_data_mutex);
1224 /* Tell the watchdog code the client is gone */
1225 mutex_lock(&data->watchdog_lock);
1226 data->client = NULL;
1227 mutex_unlock(&data->watchdog_lock);
1228 }
1229
Hans de Goede569ff102007-10-11 08:06:29 -04001230 /* Check if registered in case we're called from fschmd_detect
1231 to cleanup after an error */
1232 if (data->hwmon_dev)
1233 hwmon_device_unregister(data->hwmon_dev);
1234
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001235 device_remove_file(&client->dev, &dev_attr_alert_led);
1236 for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001237 device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
1238 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
1239 device_remove_file(&client->dev,
1240 &fschmd_temp_attr[i].dev_attr);
1241 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
1242 device_remove_file(&client->dev,
1243 &fschmd_fan_attr[i].dev_attr);
1244
Hans de Goede97950c32009-01-07 16:37:33 +01001245 mutex_lock(&watchdog_data_mutex);
1246 kref_put(&data->kref, fschmd_release_resources);
1247 mutex_unlock(&watchdog_data_mutex);
1248
Hans de Goede569ff102007-10-11 08:06:29 -04001249 return 0;
1250}
1251
1252static struct fschmd_data *fschmd_update_device(struct device *dev)
1253{
1254 struct i2c_client *client = to_i2c_client(dev);
1255 struct fschmd_data *data = i2c_get_clientdata(client);
1256 int i;
1257
1258 mutex_lock(&data->update_lock);
1259
1260 if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
1261
1262 for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
1263 data->temp_act[i] = i2c_smbus_read_byte_data(client,
1264 FSCHMD_REG_TEMP_ACT[data->kind][i]);
1265 data->temp_status[i] = i2c_smbus_read_byte_data(client,
1266 FSCHMD_REG_TEMP_STATE[data->kind][i]);
1267
1268 /* The fscpos doesn't have TEMP_LIMIT registers */
1269 if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
1270 data->temp_max[i] = i2c_smbus_read_byte_data(
1271 client,
1272 FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
1273
1274 /* reset alarm if the alarm condition is gone,
1275 the chip doesn't do this itself */
1276 if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
1277 FSCHMD_TEMP_ALARM_MASK &&
1278 data->temp_act[i] < data->temp_max[i])
1279 i2c_smbus_write_byte_data(client,
1280 FSCHMD_REG_TEMP_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001281 data->temp_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001282 }
1283
1284 for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
1285 data->fan_act[i] = i2c_smbus_read_byte_data(client,
1286 FSCHMD_REG_FAN_ACT[data->kind][i]);
1287 data->fan_status[i] = i2c_smbus_read_byte_data(client,
1288 FSCHMD_REG_FAN_STATE[data->kind][i]);
1289 data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
1290 FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
1291
1292 /* The fscpos third fan doesn't have a fan_min */
1293 if (FSCHMD_REG_FAN_MIN[data->kind][i])
1294 data->fan_min[i] = i2c_smbus_read_byte_data(
1295 client,
1296 FSCHMD_REG_FAN_MIN[data->kind][i]);
1297
1298 /* reset fan status if speed is back to > 0 */
Hans de Goede453e3082009-01-07 16:37:33 +01001299 if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
Hans de Goede569ff102007-10-11 08:06:29 -04001300 data->fan_act[i])
1301 i2c_smbus_write_byte_data(client,
1302 FSCHMD_REG_FAN_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001303 data->fan_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001304 }
1305
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001306 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001307 data->volt[i] = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001308 FSCHMD_REG_VOLT[data->kind][i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001309
Hans de Goede569ff102007-10-11 08:06:29 -04001310 data->last_updated = jiffies;
1311 data->valid = 1;
1312 }
1313
1314 mutex_unlock(&data->update_lock);
1315
1316 return data;
1317}
1318
1319static int __init fschmd_init(void)
1320{
1321 return i2c_add_driver(&fschmd_driver);
1322}
1323
1324static void __exit fschmd_exit(void)
1325{
1326 i2c_del_driver(&fschmd_driver);
1327}
1328
Hans de Goede453e3082009-01-07 16:37:33 +01001329MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
Hans de Goedede15f092009-03-30 21:46:45 +02001330MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
1331 "and Syleus driver");
Hans de Goede569ff102007-10-11 08:06:29 -04001332MODULE_LICENSE("GPL");
1333
1334module_init(fschmd_init);
1335module_exit(fschmd_exit);