blob: b7ca2a9676cf8b62aab21fa7a04d205457828c6e [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>
Arnd Bergmann55929332010-04-27 00:24:05 +020041#include <linux/smp_lock.h>
Hans de Goede569ff102007-10-11 08:06:29 -040042#include <linux/err.h>
43#include <linux/mutex.h>
44#include <linux/sysfs.h>
Hans de Goede7845cd72007-12-20 16:42:59 +010045#include <linux/dmi.h>
Hans de Goede97950c32009-01-07 16:37:33 +010046#include <linux/fs.h>
47#include <linux/watchdog.h>
48#include <linux/miscdevice.h>
49#include <linux/uaccess.h>
50#include <linux/kref.h>
Hans de Goede569ff102007-10-11 08:06:29 -040051
52/* Addresses to scan */
Mark M. Hoffman25e9c862008-02-17 22:28:03 -050053static const unsigned short normal_i2c[] = { 0x73, I2C_CLIENT_END };
Hans de Goede569ff102007-10-11 08:06:29 -040054
55/* Insmod parameters */
Hans de Goede97950c32009-01-07 16:37:33 +010056static int nowayout = WATCHDOG_NOWAYOUT;
57module_param(nowayout, int, 0);
58MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
59 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
Jean Delvaree5e9f442009-12-14 21:17:27 +010060
61enum chips { fscpos, fscher, fscscy, fschrc, fschmd, fschds, fscsyl };
Hans de Goede569ff102007-10-11 08:06:29 -040062
63/*
64 * The FSCHMD registers and other defines
65 */
66
67/* chip identification */
68#define FSCHMD_REG_IDENT_0 0x00
69#define FSCHMD_REG_IDENT_1 0x01
70#define FSCHMD_REG_IDENT_2 0x02
71#define FSCHMD_REG_REVISION 0x03
72
73/* global control and status */
74#define FSCHMD_REG_EVENT_STATE 0x04
75#define FSCHMD_REG_CONTROL 0x05
76
Hans de Goede453e3082009-01-07 16:37:33 +010077#define FSCHMD_CONTROL_ALERT_LED 0x01
Hans de Goede569ff102007-10-11 08:06:29 -040078
Hans de Goede97950c32009-01-07 16:37:33 +010079/* watchdog */
Hans de Goedede15f092009-03-30 21:46:45 +020080static const u8 FSCHMD_REG_WDOG_CONTROL[7] =
81 { 0x21, 0x21, 0x21, 0x21, 0x21, 0x28, 0x28 };
82static const u8 FSCHMD_REG_WDOG_STATE[7] =
83 { 0x23, 0x23, 0x23, 0x23, 0x23, 0x29, 0x29 };
84static const u8 FSCHMD_REG_WDOG_PRESET[7] =
85 { 0x28, 0x28, 0x28, 0x28, 0x28, 0x2a, 0x2a };
Hans de Goede569ff102007-10-11 08:06:29 -040086
Hans de Goede97950c32009-01-07 16:37:33 +010087#define FSCHMD_WDOG_CONTROL_TRIGGER 0x10
88#define FSCHMD_WDOG_CONTROL_STARTED 0x10 /* the same as trigger */
89#define FSCHMD_WDOG_CONTROL_STOP 0x20
90#define FSCHMD_WDOG_CONTROL_RESOLUTION 0x40
91
92#define FSCHMD_WDOG_STATE_CARDRESET 0x02
93
Hans de Goede569ff102007-10-11 08:06:29 -040094/* voltages, weird order is to keep the same order as the old drivers */
Hans de Goedede15f092009-03-30 21:46:45 +020095static const u8 FSCHMD_REG_VOLT[7][6] = {
Hans de Goedec69ab2b2009-03-30 21:46:45 +020096 { 0x45, 0x42, 0x48 }, /* pos */
97 { 0x45, 0x42, 0x48 }, /* her */
98 { 0x45, 0x42, 0x48 }, /* scy */
99 { 0x45, 0x42, 0x48 }, /* hrc */
100 { 0x45, 0x42, 0x48 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200101 { 0x21, 0x20, 0x22 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200102 { 0x21, 0x20, 0x22, 0x23, 0x24, 0x25 }, /* syl */
103};
104
Hans de Goedede15f092009-03-30 21:46:45 +0200105static const int FSCHMD_NO_VOLT_SENSORS[7] = { 3, 3, 3, 3, 3, 3, 6 };
Hans de Goede569ff102007-10-11 08:06:29 -0400106
107/* minimum pwm at which the fan is driven (pwm can by increased depending on
108 the temp. Notice that for the scy some fans share there minimum speed.
Frederik Schwarzer025dfda2008-10-16 19:02:37 +0200109 Also notice that with the scy the sensor order is different than with the
Hans de Goede569ff102007-10-11 08:06:29 -0400110 other chips, this order was in the 2.4 driver and kept for consistency. */
Hans de Goedede15f092009-03-30 21:46:45 +0200111static const u8 FSCHMD_REG_FAN_MIN[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400112 { 0x55, 0x65 }, /* pos */
113 { 0x55, 0x65, 0xb5 }, /* her */
114 { 0x65, 0x65, 0x55, 0xa5, 0x55, 0xa5 }, /* scy */
115 { 0x55, 0x65, 0xa5, 0xb5 }, /* hrc */
116 { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200117 { 0x55, 0x65, 0xa5, 0xb5, 0xc5 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200118 { 0x54, 0x64, 0x74, 0x84, 0x94, 0xa4, 0xb4 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400119};
120
121/* actual fan speed */
Hans de Goedede15f092009-03-30 21:46:45 +0200122static const u8 FSCHMD_REG_FAN_ACT[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400123 { 0x0e, 0x6b, 0xab }, /* pos */
124 { 0x0e, 0x6b, 0xbb }, /* her */
125 { 0x6b, 0x6c, 0x0e, 0xab, 0x5c, 0xbb }, /* scy */
126 { 0x0e, 0x6b, 0xab, 0xbb }, /* hrc */
127 { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200128 { 0x5b, 0x6b, 0xab, 0xbb, 0xcb }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200129 { 0x57, 0x67, 0x77, 0x87, 0x97, 0xa7, 0xb7 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400130};
131
132/* fan status registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200133static const u8 FSCHMD_REG_FAN_STATE[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400134 { 0x0d, 0x62, 0xa2 }, /* pos */
135 { 0x0d, 0x62, 0xb2 }, /* her */
136 { 0x62, 0x61, 0x0d, 0xa2, 0x52, 0xb2 }, /* scy */
137 { 0x0d, 0x62, 0xa2, 0xb2 }, /* hrc */
138 { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200139 { 0x52, 0x62, 0xa2, 0xb2, 0xc2 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200140 { 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400141};
142
143/* fan ripple / divider registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200144static const u8 FSCHMD_REG_FAN_RIPPLE[7][7] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400145 { 0x0f, 0x6f, 0xaf }, /* pos */
146 { 0x0f, 0x6f, 0xbf }, /* her */
147 { 0x6f, 0x6f, 0x0f, 0xaf, 0x0f, 0xbf }, /* scy */
148 { 0x0f, 0x6f, 0xaf, 0xbf }, /* hrc */
149 { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200150 { 0x5f, 0x6f, 0xaf, 0xbf, 0xcf }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200151 { 0x56, 0x66, 0x76, 0x86, 0x96, 0xa6, 0xb6 }, /* syl */
Hans de Goede569ff102007-10-11 08:06:29 -0400152};
153
Hans de Goedede15f092009-03-30 21:46:45 +0200154static const int FSCHMD_NO_FAN_SENSORS[7] = { 3, 3, 6, 4, 5, 5, 7 };
Hans de Goede569ff102007-10-11 08:06:29 -0400155
156/* Fan status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100157#define FSCHMD_FAN_ALARM 0x04 /* called fault by FSC! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200158#define FSCHMD_FAN_NOT_PRESENT 0x08
159#define FSCHMD_FAN_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400160
161
162/* actual temperature registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200163static const u8 FSCHMD_REG_TEMP_ACT[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400164 { 0x64, 0x32, 0x35 }, /* pos */
165 { 0x64, 0x32, 0x35 }, /* her */
166 { 0x64, 0xD0, 0x32, 0x35 }, /* scy */
167 { 0x64, 0x32, 0x35 }, /* hrc */
168 { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200169 { 0x70, 0x80, 0x90, 0xd0, 0xe0 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200170 { 0x58, 0x68, 0x78, 0x88, 0x98, 0xa8, /* syl */
171 0xb8, 0xc8, 0xd8, 0xe8, 0xf8 },
Hans de Goede569ff102007-10-11 08:06:29 -0400172};
173
174/* temperature state registers */
Hans de Goedede15f092009-03-30 21:46:45 +0200175static const u8 FSCHMD_REG_TEMP_STATE[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400176 { 0x71, 0x81, 0x91 }, /* pos */
177 { 0x71, 0x81, 0x91 }, /* her */
178 { 0x71, 0xd1, 0x81, 0x91 }, /* scy */
179 { 0x71, 0x81, 0x91 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500180 { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200181 { 0x71, 0x81, 0x91, 0xd1, 0xe1 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200182 { 0x59, 0x69, 0x79, 0x89, 0x99, 0xa9, /* syl */
183 0xb9, 0xc9, 0xd9, 0xe9, 0xf9 },
Hans de Goede569ff102007-10-11 08:06:29 -0400184};
185
186/* temperature high limit registers, FSC does not document these. Proven to be
187 there with field testing on the fscher and fschrc, already supported / used
188 in the fscscy 2.4 driver. FSC has confirmed that the fschmd has registers
189 at these addresses, but doesn't want to confirm they are the same as with
190 the fscher?? */
Hans de Goedede15f092009-03-30 21:46:45 +0200191static const u8 FSCHMD_REG_TEMP_LIMIT[7][11] = {
Hans de Goede569ff102007-10-11 08:06:29 -0400192 { 0, 0, 0 }, /* pos */
193 { 0x76, 0x86, 0x96 }, /* her */
194 { 0x76, 0xd6, 0x86, 0x96 }, /* scy */
195 { 0x76, 0x86, 0x96 }, /* hrc */
Jean Delvare7dcf9a32007-11-24 17:45:09 -0500196 { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hmd */
Hans de Goedede15f092009-03-30 21:46:45 +0200197 { 0x76, 0x86, 0x96, 0xd6, 0xe6 }, /* hds */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200198 { 0x5a, 0x6a, 0x7a, 0x8a, 0x9a, 0xaa, /* syl */
199 0xba, 0xca, 0xda, 0xea, 0xfa },
Hans de Goede569ff102007-10-11 08:06:29 -0400200};
201
202/* These were found through experimenting with an fscher, currently they are
203 not used, but we keep them around for future reference.
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200204 On the fscsyl AUTOP1 lives at 0x#c (so 0x5c for fan1, 0x6c for fan2, etc),
205 AUTOP2 lives at 0x#e, and 0x#1 is a bitmask defining which temps influence
206 the fan speed.
Hans de Goede569ff102007-10-11 08:06:29 -0400207static const u8 FSCHER_REG_TEMP_AUTOP1[] = { 0x73, 0x83, 0x93 };
208static const u8 FSCHER_REG_TEMP_AUTOP2[] = { 0x75, 0x85, 0x95 }; */
209
Hans de Goedede15f092009-03-30 21:46:45 +0200210static const int FSCHMD_NO_TEMP_SENSORS[7] = { 3, 3, 4, 3, 5, 5, 11 };
Hans de Goede569ff102007-10-11 08:06:29 -0400211
212/* temp status register bitmasks */
Hans de Goede453e3082009-01-07 16:37:33 +0100213#define FSCHMD_TEMP_WORKING 0x01
214#define FSCHMD_TEMP_ALERT 0x02
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200215#define FSCHMD_TEMP_DISABLED 0x80
Hans de Goede569ff102007-10-11 08:06:29 -0400216/* there only really is an alarm if the sensor is working and alert == 1 */
217#define FSCHMD_TEMP_ALARM_MASK \
Hans de Goede453e3082009-01-07 16:37:33 +0100218 (FSCHMD_TEMP_WORKING | FSCHMD_TEMP_ALERT)
Hans de Goede569ff102007-10-11 08:06:29 -0400219
220/*
221 * Functions declarations
222 */
223
Jean Delvare40ac1992008-07-16 19:30:12 +0200224static int fschmd_probe(struct i2c_client *client,
225 const struct i2c_device_id *id);
Jean Delvare310ec792009-12-14 21:17:23 +0100226static int fschmd_detect(struct i2c_client *client,
Jean Delvare40ac1992008-07-16 19:30:12 +0200227 struct i2c_board_info *info);
228static int fschmd_remove(struct i2c_client *client);
Hans de Goede569ff102007-10-11 08:06:29 -0400229static struct fschmd_data *fschmd_update_device(struct device *dev);
230
231/*
232 * Driver data (common to all clients)
233 */
234
Jean Delvare40ac1992008-07-16 19:30:12 +0200235static const struct i2c_device_id fschmd_id[] = {
236 { "fscpos", fscpos },
237 { "fscher", fscher },
238 { "fscscy", fscscy },
239 { "fschrc", fschrc },
240 { "fschmd", fschmd },
Hans de Goedede15f092009-03-30 21:46:45 +0200241 { "fschds", fschds },
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200242 { "fscsyl", fscsyl },
Jean Delvare40ac1992008-07-16 19:30:12 +0200243 { }
244};
245MODULE_DEVICE_TABLE(i2c, fschmd_id);
246
Hans de Goede569ff102007-10-11 08:06:29 -0400247static struct i2c_driver fschmd_driver = {
Jean Delvare40ac1992008-07-16 19:30:12 +0200248 .class = I2C_CLASS_HWMON,
Hans de Goede569ff102007-10-11 08:06:29 -0400249 .driver = {
Hans de Goede453e3082009-01-07 16:37:33 +0100250 .name = "fschmd",
Hans de Goede569ff102007-10-11 08:06:29 -0400251 },
Jean Delvare40ac1992008-07-16 19:30:12 +0200252 .probe = fschmd_probe,
253 .remove = fschmd_remove,
254 .id_table = fschmd_id,
255 .detect = fschmd_detect,
Jean Delvarec3813d62009-12-14 21:17:25 +0100256 .address_list = normal_i2c,
Hans de Goede569ff102007-10-11 08:06:29 -0400257};
258
259/*
260 * Client data (each client gets its own)
261 */
262
263struct fschmd_data {
Hans de Goede97950c32009-01-07 16:37:33 +0100264 struct i2c_client *client;
Hans de Goede569ff102007-10-11 08:06:29 -0400265 struct device *hwmon_dev;
266 struct mutex update_lock;
Hans de Goede97950c32009-01-07 16:37:33 +0100267 struct mutex watchdog_lock;
268 struct list_head list; /* member of the watchdog_data_list */
269 struct kref kref;
270 struct miscdevice watchdog_miscdev;
Jean Delvaredc71afe2010-03-05 22:17:26 +0100271 enum chips kind;
Hans de Goede97950c32009-01-07 16:37:33 +0100272 unsigned long watchdog_is_open;
273 char watchdog_expect_close;
274 char watchdog_name[10]; /* must be unique to avoid sysfs conflict */
Hans de Goede569ff102007-10-11 08:06:29 -0400275 char valid; /* zero until following fields are valid */
276 unsigned long last_updated; /* in jiffies */
277
278 /* register values */
Hans de Goede97950c32009-01-07 16:37:33 +0100279 u8 revision; /* chip revision */
Hans de Goede569ff102007-10-11 08:06:29 -0400280 u8 global_control; /* global control register */
Hans de Goede97950c32009-01-07 16:37:33 +0100281 u8 watchdog_control; /* watchdog control register */
282 u8 watchdog_state; /* watchdog status register */
283 u8 watchdog_preset; /* watchdog counter preset on trigger val */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200284 u8 volt[6]; /* voltage */
285 u8 temp_act[11]; /* temperature */
286 u8 temp_status[11]; /* status of sensor */
287 u8 temp_max[11]; /* high temp limit, notice: undocumented! */
288 u8 fan_act[7]; /* fans revolutions per second */
289 u8 fan_status[7]; /* fan status */
290 u8 fan_min[7]; /* fan min value for rps */
291 u8 fan_ripple[7]; /* divider for rps */
Hans de Goede569ff102007-10-11 08:06:29 -0400292};
293
Hans de Goede7845cd72007-12-20 16:42:59 +0100294/* Global variables to hold information read from special DMI tables, which are
Hans de Goede97950c32009-01-07 16:37:33 +0100295 available on FSC machines with an fscher or later chip. There is no need to
296 protect these with a lock as they are only modified from our attach function
297 which always gets called with the i2c-core lock held and never accessed
298 before the attach function is done with them. */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200299static int dmi_mult[6] = { 490, 200, 100, 100, 200, 100 };
300static int dmi_offset[6] = { 0, 0, 0, 0, 0, 0 };
Hans de Goede7845cd72007-12-20 16:42:59 +0100301static int dmi_vref = -1;
302
Hans de Goede97950c32009-01-07 16:37:33 +0100303/* Somewhat ugly :( global data pointer list with all fschmd devices, so that
304 we can find our device data as when using misc_register there is no other
305 method to get to ones device data from the open fop. */
306static LIST_HEAD(watchdog_data_list);
307/* Note this lock not only protect list access, but also data.kref access */
308static DEFINE_MUTEX(watchdog_data_mutex);
309
310/* Release our data struct when we're detached from the i2c client *and* all
311 references to our watchdog device are released */
312static void fschmd_release_resources(struct kref *ref)
313{
314 struct fschmd_data *data = container_of(ref, struct fschmd_data, kref);
315 kfree(data);
316}
Hans de Goede7845cd72007-12-20 16:42:59 +0100317
Hans de Goede569ff102007-10-11 08:06:29 -0400318/*
319 * Sysfs attr show / store functions
320 */
321
322static ssize_t show_in_value(struct device *dev,
323 struct device_attribute *devattr, char *buf)
324{
325 const int max_reading[3] = { 14200, 6600, 3300 };
326 int index = to_sensor_dev_attr(devattr)->index;
327 struct fschmd_data *data = fschmd_update_device(dev);
328
Jean Delvaredc71afe2010-03-05 22:17:26 +0100329 if (data->kind == fscher || data->kind >= fschrc)
Hans de Goede7845cd72007-12-20 16:42:59 +0100330 return sprintf(buf, "%d\n", (data->volt[index] * dmi_vref *
331 dmi_mult[index]) / 255 + dmi_offset[index]);
332 else
333 return sprintf(buf, "%d\n", (data->volt[index] *
334 max_reading[index] + 128) / 255);
Hans de Goede569ff102007-10-11 08:06:29 -0400335}
336
337
338#define TEMP_FROM_REG(val) (((val) - 128) * 1000)
339
340static ssize_t show_temp_value(struct device *dev,
341 struct device_attribute *devattr, char *buf)
342{
343 int index = to_sensor_dev_attr(devattr)->index;
344 struct fschmd_data *data = fschmd_update_device(dev);
345
346 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_act[index]));
347}
348
349static ssize_t show_temp_max(struct device *dev,
350 struct device_attribute *devattr, char *buf)
351{
352 int index = to_sensor_dev_attr(devattr)->index;
353 struct fschmd_data *data = fschmd_update_device(dev);
354
355 return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[index]));
356}
357
358static ssize_t store_temp_max(struct device *dev, struct device_attribute
359 *devattr, const char *buf, size_t count)
360{
361 int index = to_sensor_dev_attr(devattr)->index;
362 struct fschmd_data *data = dev_get_drvdata(dev);
363 long v = simple_strtol(buf, NULL, 10) / 1000;
364
365 v = SENSORS_LIMIT(v, -128, 127) + 128;
366
367 mutex_lock(&data->update_lock);
Jean Delvare40ac1992008-07-16 19:30:12 +0200368 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400369 FSCHMD_REG_TEMP_LIMIT[data->kind][index], v);
370 data->temp_max[index] = v;
371 mutex_unlock(&data->update_lock);
372
373 return count;
374}
375
376static ssize_t show_temp_fault(struct device *dev,
377 struct device_attribute *devattr, char *buf)
378{
379 int index = to_sensor_dev_attr(devattr)->index;
380 struct fschmd_data *data = fschmd_update_device(dev);
381
382 /* bit 0 set means sensor working ok, so no fault! */
Hans de Goede453e3082009-01-07 16:37:33 +0100383 if (data->temp_status[index] & FSCHMD_TEMP_WORKING)
Hans de Goede569ff102007-10-11 08:06:29 -0400384 return sprintf(buf, "0\n");
385 else
386 return sprintf(buf, "1\n");
387}
388
389static ssize_t show_temp_alarm(struct device *dev,
390 struct device_attribute *devattr, char *buf)
391{
392 int index = to_sensor_dev_attr(devattr)->index;
393 struct fschmd_data *data = fschmd_update_device(dev);
394
395 if ((data->temp_status[index] & FSCHMD_TEMP_ALARM_MASK) ==
396 FSCHMD_TEMP_ALARM_MASK)
397 return sprintf(buf, "1\n");
398 else
399 return sprintf(buf, "0\n");
400}
401
402
403#define RPM_FROM_REG(val) ((val) * 60)
404
405static ssize_t show_fan_value(struct device *dev,
406 struct device_attribute *devattr, char *buf)
407{
408 int index = to_sensor_dev_attr(devattr)->index;
409 struct fschmd_data *data = fschmd_update_device(dev);
410
411 return sprintf(buf, "%u\n", RPM_FROM_REG(data->fan_act[index]));
412}
413
414static ssize_t show_fan_div(struct device *dev,
415 struct device_attribute *devattr, char *buf)
416{
417 int index = to_sensor_dev_attr(devattr)->index;
418 struct fschmd_data *data = fschmd_update_device(dev);
419
420 /* bits 2..7 reserved => mask with 3 */
421 return sprintf(buf, "%d\n", 1 << (data->fan_ripple[index] & 3));
422}
423
424static ssize_t store_fan_div(struct device *dev, struct device_attribute
425 *devattr, const char *buf, size_t count)
426{
427 u8 reg;
428 int index = to_sensor_dev_attr(devattr)->index;
429 struct fschmd_data *data = dev_get_drvdata(dev);
430 /* supported values: 2, 4, 8 */
431 unsigned long v = simple_strtoul(buf, NULL, 10);
432
433 switch (v) {
434 case 2: v = 1; break;
435 case 4: v = 2; break;
436 case 8: v = 3; break;
437 default:
438 dev_err(dev, "fan_div value %lu not supported. "
439 "Choose one of 2, 4 or 8!\n", v);
440 return -EINVAL;
441 }
442
443 mutex_lock(&data->update_lock);
444
Jean Delvare40ac1992008-07-16 19:30:12 +0200445 reg = i2c_smbus_read_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400446 FSCHMD_REG_FAN_RIPPLE[data->kind][index]);
447
448 /* bits 2..7 reserved => mask with 0x03 */
449 reg &= ~0x03;
450 reg |= v;
451
Jean Delvare40ac1992008-07-16 19:30:12 +0200452 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400453 FSCHMD_REG_FAN_RIPPLE[data->kind][index], reg);
454
455 data->fan_ripple[index] = reg;
456
457 mutex_unlock(&data->update_lock);
458
459 return count;
460}
461
462static ssize_t show_fan_alarm(struct device *dev,
463 struct device_attribute *devattr, char *buf)
464{
465 int index = to_sensor_dev_attr(devattr)->index;
466 struct fschmd_data *data = fschmd_update_device(dev);
467
Hans de Goede453e3082009-01-07 16:37:33 +0100468 if (data->fan_status[index] & FSCHMD_FAN_ALARM)
Hans de Goede569ff102007-10-11 08:06:29 -0400469 return sprintf(buf, "1\n");
470 else
471 return sprintf(buf, "0\n");
472}
473
474static ssize_t show_fan_fault(struct device *dev,
475 struct device_attribute *devattr, char *buf)
476{
477 int index = to_sensor_dev_attr(devattr)->index;
478 struct fschmd_data *data = fschmd_update_device(dev);
479
Hans de Goede453e3082009-01-07 16:37:33 +0100480 if (data->fan_status[index] & FSCHMD_FAN_NOT_PRESENT)
Hans de Goede569ff102007-10-11 08:06:29 -0400481 return sprintf(buf, "1\n");
482 else
483 return sprintf(buf, "0\n");
484}
485
486
487static ssize_t show_pwm_auto_point1_pwm(struct device *dev,
488 struct device_attribute *devattr, char *buf)
489{
490 int index = to_sensor_dev_attr(devattr)->index;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200491 struct fschmd_data *data = fschmd_update_device(dev);
492 int val = data->fan_min[index];
Hans de Goede569ff102007-10-11 08:06:29 -0400493
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200494 /* 0 = allow turning off (except on the syl), 1-255 = 50-100% */
Jean Delvaredc71afe2010-03-05 22:17:26 +0100495 if (val || data->kind == fscsyl)
Hans de Goede569ff102007-10-11 08:06:29 -0400496 val = val / 2 + 128;
497
498 return sprintf(buf, "%d\n", val);
499}
500
501static ssize_t store_pwm_auto_point1_pwm(struct device *dev,
502 struct device_attribute *devattr, const char *buf, size_t count)
503{
504 int index = to_sensor_dev_attr(devattr)->index;
505 struct fschmd_data *data = dev_get_drvdata(dev);
506 unsigned long v = simple_strtoul(buf, NULL, 10);
507
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200508 /* reg: 0 = allow turning off (except on the syl), 1-255 = 50-100% */
Jean Delvaredc71afe2010-03-05 22:17:26 +0100509 if (v || data->kind == fscsyl) {
Hans de Goede569ff102007-10-11 08:06:29 -0400510 v = SENSORS_LIMIT(v, 128, 255);
511 v = (v - 128) * 2 + 1;
512 }
513
514 mutex_lock(&data->update_lock);
515
Jean Delvare40ac1992008-07-16 19:30:12 +0200516 i2c_smbus_write_byte_data(to_i2c_client(dev),
Hans de Goede569ff102007-10-11 08:06:29 -0400517 FSCHMD_REG_FAN_MIN[data->kind][index], v);
518 data->fan_min[index] = v;
519
520 mutex_unlock(&data->update_lock);
521
522 return count;
523}
524
525
526/* The FSC hwmon family has the ability to force an attached alert led to flash
527 from software, we export this as an alert_led sysfs attr */
528static ssize_t show_alert_led(struct device *dev,
529 struct device_attribute *devattr, char *buf)
530{
531 struct fschmd_data *data = fschmd_update_device(dev);
532
Hans de Goede453e3082009-01-07 16:37:33 +0100533 if (data->global_control & FSCHMD_CONTROL_ALERT_LED)
Hans de Goede569ff102007-10-11 08:06:29 -0400534 return sprintf(buf, "1\n");
535 else
536 return sprintf(buf, "0\n");
537}
538
539static ssize_t store_alert_led(struct device *dev,
540 struct device_attribute *devattr, const char *buf, size_t count)
541{
542 u8 reg;
543 struct fschmd_data *data = dev_get_drvdata(dev);
544 unsigned long v = simple_strtoul(buf, NULL, 10);
545
546 mutex_lock(&data->update_lock);
547
Jean Delvare40ac1992008-07-16 19:30:12 +0200548 reg = i2c_smbus_read_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL);
Hans de Goede569ff102007-10-11 08:06:29 -0400549
550 if (v)
Hans de Goede453e3082009-01-07 16:37:33 +0100551 reg |= FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400552 else
Hans de Goede453e3082009-01-07 16:37:33 +0100553 reg &= ~FSCHMD_CONTROL_ALERT_LED;
Hans de Goede569ff102007-10-11 08:06:29 -0400554
Jean Delvare40ac1992008-07-16 19:30:12 +0200555 i2c_smbus_write_byte_data(to_i2c_client(dev), FSCHMD_REG_CONTROL, reg);
Hans de Goede569ff102007-10-11 08:06:29 -0400556
557 data->global_control = reg;
558
559 mutex_unlock(&data->update_lock);
560
561 return count;
562}
563
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200564static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led);
565
Hans de Goede569ff102007-10-11 08:06:29 -0400566static struct sensor_device_attribute fschmd_attr[] = {
567 SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0),
568 SENSOR_ATTR(in1_input, 0444, show_in_value, NULL, 1),
569 SENSOR_ATTR(in2_input, 0444, show_in_value, NULL, 2),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200570 SENSOR_ATTR(in3_input, 0444, show_in_value, NULL, 3),
571 SENSOR_ATTR(in4_input, 0444, show_in_value, NULL, 4),
572 SENSOR_ATTR(in5_input, 0444, show_in_value, NULL, 5),
Hans de Goede569ff102007-10-11 08:06:29 -0400573};
574
575static struct sensor_device_attribute fschmd_temp_attr[] = {
576 SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
577 SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
578 SENSOR_ATTR(temp1_fault, 0444, show_temp_fault, NULL, 0),
579 SENSOR_ATTR(temp1_alarm, 0444, show_temp_alarm, NULL, 0),
580 SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
581 SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
582 SENSOR_ATTR(temp2_fault, 0444, show_temp_fault, NULL, 1),
583 SENSOR_ATTR(temp2_alarm, 0444, show_temp_alarm, NULL, 1),
584 SENSOR_ATTR(temp3_input, 0444, show_temp_value, NULL, 2),
585 SENSOR_ATTR(temp3_max, 0644, show_temp_max, store_temp_max, 2),
586 SENSOR_ATTR(temp3_fault, 0444, show_temp_fault, NULL, 2),
587 SENSOR_ATTR(temp3_alarm, 0444, show_temp_alarm, NULL, 2),
588 SENSOR_ATTR(temp4_input, 0444, show_temp_value, NULL, 3),
589 SENSOR_ATTR(temp4_max, 0644, show_temp_max, store_temp_max, 3),
590 SENSOR_ATTR(temp4_fault, 0444, show_temp_fault, NULL, 3),
591 SENSOR_ATTR(temp4_alarm, 0444, show_temp_alarm, NULL, 3),
592 SENSOR_ATTR(temp5_input, 0444, show_temp_value, NULL, 4),
593 SENSOR_ATTR(temp5_max, 0644, show_temp_max, store_temp_max, 4),
594 SENSOR_ATTR(temp5_fault, 0444, show_temp_fault, NULL, 4),
595 SENSOR_ATTR(temp5_alarm, 0444, show_temp_alarm, NULL, 4),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200596 SENSOR_ATTR(temp6_input, 0444, show_temp_value, NULL, 5),
597 SENSOR_ATTR(temp6_max, 0644, show_temp_max, store_temp_max, 5),
598 SENSOR_ATTR(temp6_fault, 0444, show_temp_fault, NULL, 5),
599 SENSOR_ATTR(temp6_alarm, 0444, show_temp_alarm, NULL, 5),
600 SENSOR_ATTR(temp7_input, 0444, show_temp_value, NULL, 6),
601 SENSOR_ATTR(temp7_max, 0644, show_temp_max, store_temp_max, 6),
602 SENSOR_ATTR(temp7_fault, 0444, show_temp_fault, NULL, 6),
603 SENSOR_ATTR(temp7_alarm, 0444, show_temp_alarm, NULL, 6),
604 SENSOR_ATTR(temp8_input, 0444, show_temp_value, NULL, 7),
605 SENSOR_ATTR(temp8_max, 0644, show_temp_max, store_temp_max, 7),
606 SENSOR_ATTR(temp8_fault, 0444, show_temp_fault, NULL, 7),
607 SENSOR_ATTR(temp8_alarm, 0444, show_temp_alarm, NULL, 7),
608 SENSOR_ATTR(temp9_input, 0444, show_temp_value, NULL, 8),
609 SENSOR_ATTR(temp9_max, 0644, show_temp_max, store_temp_max, 8),
610 SENSOR_ATTR(temp9_fault, 0444, show_temp_fault, NULL, 8),
611 SENSOR_ATTR(temp9_alarm, 0444, show_temp_alarm, NULL, 8),
612 SENSOR_ATTR(temp10_input, 0444, show_temp_value, NULL, 9),
613 SENSOR_ATTR(temp10_max, 0644, show_temp_max, store_temp_max, 9),
614 SENSOR_ATTR(temp10_fault, 0444, show_temp_fault, NULL, 9),
615 SENSOR_ATTR(temp10_alarm, 0444, show_temp_alarm, NULL, 9),
616 SENSOR_ATTR(temp11_input, 0444, show_temp_value, NULL, 10),
617 SENSOR_ATTR(temp11_max, 0644, show_temp_max, store_temp_max, 10),
618 SENSOR_ATTR(temp11_fault, 0444, show_temp_fault, NULL, 10),
619 SENSOR_ATTR(temp11_alarm, 0444, show_temp_alarm, NULL, 10),
Hans de Goede569ff102007-10-11 08:06:29 -0400620};
621
622static struct sensor_device_attribute fschmd_fan_attr[] = {
623 SENSOR_ATTR(fan1_input, 0444, show_fan_value, NULL, 0),
624 SENSOR_ATTR(fan1_div, 0644, show_fan_div, store_fan_div, 0),
625 SENSOR_ATTR(fan1_alarm, 0444, show_fan_alarm, NULL, 0),
626 SENSOR_ATTR(fan1_fault, 0444, show_fan_fault, NULL, 0),
627 SENSOR_ATTR(pwm1_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
628 store_pwm_auto_point1_pwm, 0),
629 SENSOR_ATTR(fan2_input, 0444, show_fan_value, NULL, 1),
630 SENSOR_ATTR(fan2_div, 0644, show_fan_div, store_fan_div, 1),
631 SENSOR_ATTR(fan2_alarm, 0444, show_fan_alarm, NULL, 1),
632 SENSOR_ATTR(fan2_fault, 0444, show_fan_fault, NULL, 1),
633 SENSOR_ATTR(pwm2_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
634 store_pwm_auto_point1_pwm, 1),
635 SENSOR_ATTR(fan3_input, 0444, show_fan_value, NULL, 2),
636 SENSOR_ATTR(fan3_div, 0644, show_fan_div, store_fan_div, 2),
637 SENSOR_ATTR(fan3_alarm, 0444, show_fan_alarm, NULL, 2),
638 SENSOR_ATTR(fan3_fault, 0444, show_fan_fault, NULL, 2),
639 SENSOR_ATTR(pwm3_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
640 store_pwm_auto_point1_pwm, 2),
641 SENSOR_ATTR(fan4_input, 0444, show_fan_value, NULL, 3),
642 SENSOR_ATTR(fan4_div, 0644, show_fan_div, store_fan_div, 3),
643 SENSOR_ATTR(fan4_alarm, 0444, show_fan_alarm, NULL, 3),
644 SENSOR_ATTR(fan4_fault, 0444, show_fan_fault, NULL, 3),
645 SENSOR_ATTR(pwm4_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
646 store_pwm_auto_point1_pwm, 3),
647 SENSOR_ATTR(fan5_input, 0444, show_fan_value, NULL, 4),
648 SENSOR_ATTR(fan5_div, 0644, show_fan_div, store_fan_div, 4),
649 SENSOR_ATTR(fan5_alarm, 0444, show_fan_alarm, NULL, 4),
650 SENSOR_ATTR(fan5_fault, 0444, show_fan_fault, NULL, 4),
651 SENSOR_ATTR(pwm5_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
652 store_pwm_auto_point1_pwm, 4),
653 SENSOR_ATTR(fan6_input, 0444, show_fan_value, NULL, 5),
654 SENSOR_ATTR(fan6_div, 0644, show_fan_div, store_fan_div, 5),
655 SENSOR_ATTR(fan6_alarm, 0444, show_fan_alarm, NULL, 5),
656 SENSOR_ATTR(fan6_fault, 0444, show_fan_fault, NULL, 5),
657 SENSOR_ATTR(pwm6_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
658 store_pwm_auto_point1_pwm, 5),
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200659 SENSOR_ATTR(fan7_input, 0444, show_fan_value, NULL, 6),
660 SENSOR_ATTR(fan7_div, 0644, show_fan_div, store_fan_div, 6),
661 SENSOR_ATTR(fan7_alarm, 0444, show_fan_alarm, NULL, 6),
662 SENSOR_ATTR(fan7_fault, 0444, show_fan_fault, NULL, 6),
663 SENSOR_ATTR(pwm7_auto_point1_pwm, 0644, show_pwm_auto_point1_pwm,
664 store_pwm_auto_point1_pwm, 6),
Hans de Goede569ff102007-10-11 08:06:29 -0400665};
666
667
668/*
Hans de Goede97950c32009-01-07 16:37:33 +0100669 * Watchdog routines
670 */
671
672static int watchdog_set_timeout(struct fschmd_data *data, int timeout)
673{
674 int ret, resolution;
675 int kind = data->kind + 1; /* 0-x array index -> 1-x module param */
676
677 /* 2 second or 60 second resolution? */
678 if (timeout <= 510 || kind == fscpos || kind == fscscy)
679 resolution = 2;
680 else
681 resolution = 60;
682
683 if (timeout < resolution || timeout > (resolution * 255))
684 return -EINVAL;
685
686 mutex_lock(&data->watchdog_lock);
687 if (!data->client) {
688 ret = -ENODEV;
689 goto leave;
690 }
691
692 if (resolution == 2)
693 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_RESOLUTION;
694 else
695 data->watchdog_control |= FSCHMD_WDOG_CONTROL_RESOLUTION;
696
697 data->watchdog_preset = DIV_ROUND_UP(timeout, resolution);
698
699 /* Write new timeout value */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200700 i2c_smbus_write_byte_data(data->client,
701 FSCHMD_REG_WDOG_PRESET[data->kind], data->watchdog_preset);
Hans de Goede97950c32009-01-07 16:37:33 +0100702 /* Write new control register, do not trigger! */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200703 i2c_smbus_write_byte_data(data->client,
704 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100705 data->watchdog_control & ~FSCHMD_WDOG_CONTROL_TRIGGER);
706
707 ret = data->watchdog_preset * resolution;
708
709leave:
710 mutex_unlock(&data->watchdog_lock);
711 return ret;
712}
713
714static int watchdog_get_timeout(struct fschmd_data *data)
715{
716 int timeout;
717
718 mutex_lock(&data->watchdog_lock);
719 if (data->watchdog_control & FSCHMD_WDOG_CONTROL_RESOLUTION)
720 timeout = data->watchdog_preset * 60;
721 else
722 timeout = data->watchdog_preset * 2;
723 mutex_unlock(&data->watchdog_lock);
724
725 return timeout;
726}
727
728static int watchdog_trigger(struct fschmd_data *data)
729{
730 int ret = 0;
731
732 mutex_lock(&data->watchdog_lock);
733 if (!data->client) {
734 ret = -ENODEV;
735 goto leave;
736 }
737
738 data->watchdog_control |= FSCHMD_WDOG_CONTROL_TRIGGER;
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200739 i2c_smbus_write_byte_data(data->client,
740 FSCHMD_REG_WDOG_CONTROL[data->kind],
741 data->watchdog_control);
Hans de Goede97950c32009-01-07 16:37:33 +0100742leave:
743 mutex_unlock(&data->watchdog_lock);
744 return ret;
745}
746
747static int watchdog_stop(struct fschmd_data *data)
748{
749 int ret = 0;
750
751 mutex_lock(&data->watchdog_lock);
752 if (!data->client) {
753 ret = -ENODEV;
754 goto leave;
755 }
756
757 data->watchdog_control &= ~FSCHMD_WDOG_CONTROL_STARTED;
758 /* Don't store the stop flag in our watchdog control register copy, as
759 its a write only bit (read always returns 0) */
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200760 i2c_smbus_write_byte_data(data->client,
761 FSCHMD_REG_WDOG_CONTROL[data->kind],
Hans de Goede97950c32009-01-07 16:37:33 +0100762 data->watchdog_control | FSCHMD_WDOG_CONTROL_STOP);
763leave:
764 mutex_unlock(&data->watchdog_lock);
765 return ret;
766}
767
768static int watchdog_open(struct inode *inode, struct file *filp)
769{
770 struct fschmd_data *pos, *data = NULL;
Hans de Goedec4536152010-01-25 15:00:50 +0100771 int watchdog_is_open;
Hans de Goede97950c32009-01-07 16:37:33 +0100772
773 /* We get called from drivers/char/misc.c with misc_mtx hold, and we
774 call misc_register() from fschmd_probe() with watchdog_data_mutex
775 hold, as misc_register() takes the misc_mtx lock, this is a possible
776 deadlock, so we use mutex_trylock here. */
777 if (!mutex_trylock(&watchdog_data_mutex))
778 return -ERESTARTSYS;
779 list_for_each_entry(pos, &watchdog_data_list, list) {
780 if (pos->watchdog_miscdev.minor == iminor(inode)) {
781 data = pos;
782 break;
783 }
784 }
785 /* Note we can never not have found data, so we don't check for this */
Hans de Goedec4536152010-01-25 15:00:50 +0100786 watchdog_is_open = test_and_set_bit(0, &data->watchdog_is_open);
787 if (!watchdog_is_open)
788 kref_get(&data->kref);
Hans de Goede97950c32009-01-07 16:37:33 +0100789 mutex_unlock(&watchdog_data_mutex);
790
Hans de Goedec4536152010-01-25 15:00:50 +0100791 if (watchdog_is_open)
Hans de Goede97950c32009-01-07 16:37:33 +0100792 return -EBUSY;
793
794 /* Start the watchdog */
795 watchdog_trigger(data);
796 filp->private_data = data;
797
798 return nonseekable_open(inode, filp);
799}
800
801static int watchdog_release(struct inode *inode, struct file *filp)
802{
803 struct fschmd_data *data = filp->private_data;
804
805 if (data->watchdog_expect_close) {
806 watchdog_stop(data);
807 data->watchdog_expect_close = 0;
808 } else {
809 watchdog_trigger(data);
810 dev_crit(&data->client->dev,
811 "unexpected close, not stopping watchdog!\n");
812 }
813
814 clear_bit(0, &data->watchdog_is_open);
815
816 mutex_lock(&watchdog_data_mutex);
817 kref_put(&data->kref, fschmd_release_resources);
818 mutex_unlock(&watchdog_data_mutex);
819
820 return 0;
821}
822
823static ssize_t watchdog_write(struct file *filp, const char __user *buf,
824 size_t count, loff_t *offset)
825{
Roel Kluinc7702c32009-10-24 13:28:45 +0200826 int ret;
Hans de Goede97950c32009-01-07 16:37:33 +0100827 struct fschmd_data *data = filp->private_data;
828
829 if (count) {
830 if (!nowayout) {
831 size_t i;
832
833 /* Clear it in case it was set with a previous write */
834 data->watchdog_expect_close = 0;
835
836 for (i = 0; i != count; i++) {
837 char c;
838 if (get_user(c, buf + i))
839 return -EFAULT;
840 if (c == 'V')
841 data->watchdog_expect_close = 1;
842 }
843 }
844 ret = watchdog_trigger(data);
845 if (ret < 0)
846 return ret;
847 }
848 return count;
849}
850
Arnd Bergmann55929332010-04-27 00:24:05 +0200851static long watchdog_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
Hans de Goede97950c32009-01-07 16:37:33 +0100852{
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
Arnd Bergmann55929332010-04-27 00:24:05 +0200861 lock_kernel();
Hans de Goede97950c32009-01-07 16:37:33 +0100862 switch (cmd) {
863 case WDIOC_GETSUPPORT:
864 ident.firmware_version = data->revision;
865 if (!nowayout)
866 ident.options |= WDIOF_MAGICCLOSE;
867 if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
868 ret = -EFAULT;
869 break;
870
871 case WDIOC_GETSTATUS:
872 ret = put_user(0, (int __user *)arg);
873 break;
874
875 case WDIOC_GETBOOTSTATUS:
876 if (data->watchdog_state & FSCHMD_WDOG_STATE_CARDRESET)
877 ret = put_user(WDIOF_CARDRESET, (int __user *)arg);
878 else
879 ret = put_user(0, (int __user *)arg);
880 break;
881
882 case WDIOC_KEEPALIVE:
883 ret = watchdog_trigger(data);
884 break;
885
886 case WDIOC_GETTIMEOUT:
887 i = watchdog_get_timeout(data);
888 ret = put_user(i, (int __user *)arg);
889 break;
890
891 case WDIOC_SETTIMEOUT:
892 if (get_user(i, (int __user *)arg)) {
893 ret = -EFAULT;
894 break;
895 }
896 ret = watchdog_set_timeout(data, i);
897 if (ret > 0)
898 ret = put_user(ret, (int __user *)arg);
899 break;
900
901 case WDIOC_SETOPTIONS:
902 if (get_user(i, (int __user *)arg)) {
903 ret = -EFAULT;
904 break;
905 }
906
907 if (i & WDIOS_DISABLECARD)
908 ret = watchdog_stop(data);
909 else if (i & WDIOS_ENABLECARD)
910 ret = watchdog_trigger(data);
911 else
912 ret = -EINVAL;
913
914 break;
915 default:
916 ret = -ENOTTY;
917 }
Arnd Bergmann55929332010-04-27 00:24:05 +0200918 unlock_kernel();
Hans de Goede97950c32009-01-07 16:37:33 +0100919 return ret;
920}
921
Alexey Dobriyan828c0952009-10-01 15:43:56 -0700922static const struct file_operations watchdog_fops = {
Hans de Goede97950c32009-01-07 16:37:33 +0100923 .owner = THIS_MODULE,
924 .llseek = no_llseek,
925 .open = watchdog_open,
926 .release = watchdog_release,
927 .write = watchdog_write,
Arnd Bergmann55929332010-04-27 00:24:05 +0200928 .unlocked_ioctl = watchdog_ioctl,
Hans de Goede97950c32009-01-07 16:37:33 +0100929};
930
931
932/*
933 * Detect, register, unregister and update device functions
Hans de Goede569ff102007-10-11 08:06:29 -0400934 */
935
Hans de Goede7845cd72007-12-20 16:42:59 +0100936/* DMI decode routine to read voltage scaling factors from special DMI tables,
937 which are available on FSC machines with an fscher or later chip. */
Jean Delvaree7a19c562009-03-30 21:46:44 +0200938static void fschmd_dmi_decode(const struct dmi_header *header, void *dummy)
Hans de Goede7845cd72007-12-20 16:42:59 +0100939{
940 int i, mult[3] = { 0 }, offset[3] = { 0 }, vref = 0, found = 0;
941
942 /* dmi code ugliness, we get passed the address of the contents of
943 a complete DMI record, but in the form of a dmi_header pointer, in
944 reality this address holds header->length bytes of which the header
945 are the first 4 bytes */
946 u8 *dmi_data = (u8 *)header;
947
948 /* We are looking for OEM-specific type 185 */
949 if (header->type != 185)
950 return;
951
952 /* we are looking for what Siemens calls "subtype" 19, the subtype
953 is stored in byte 5 of the dmi block */
954 if (header->length < 5 || dmi_data[4] != 19)
955 return;
956
957 /* After the subtype comes 1 unknown byte and then blocks of 5 bytes,
958 consisting of what Siemens calls an "Entity" number, followed by
959 2 16-bit words in LSB first order */
960 for (i = 6; (i + 4) < header->length; i += 5) {
961 /* entity 1 - 3: voltage multiplier and offset */
962 if (dmi_data[i] >= 1 && dmi_data[i] <= 3) {
963 /* Our in sensors order and the DMI order differ */
964 const int shuffle[3] = { 1, 0, 2 };
965 int in = shuffle[dmi_data[i] - 1];
966
967 /* Check for twice the same entity */
968 if (found & (1 << in))
969 return;
970
971 mult[in] = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
972 offset[in] = dmi_data[i + 3] | (dmi_data[i + 4] << 8);
973
974 found |= 1 << in;
975 }
976
977 /* entity 7: reference voltage */
978 if (dmi_data[i] == 7) {
979 /* Check for twice the same entity */
980 if (found & 0x08)
981 return;
982
983 vref = dmi_data[i + 1] | (dmi_data[i + 2] << 8);
984
985 found |= 0x08;
986 }
987 }
988
989 if (found == 0x0F) {
990 for (i = 0; i < 3; i++) {
991 dmi_mult[i] = mult[i] * 10;
992 dmi_offset[i] = offset[i] * 10;
993 }
Hans de Goedec69ab2b2009-03-30 21:46:45 +0200994 /* According to the docs there should be separate dmi entries
995 for the mult's and offsets of in3-5 of the syl, but on
996 my test machine these are not present */
997 dmi_mult[3] = dmi_mult[2];
998 dmi_mult[4] = dmi_mult[1];
999 dmi_mult[5] = dmi_mult[2];
1000 dmi_offset[3] = dmi_offset[2];
1001 dmi_offset[4] = dmi_offset[1];
1002 dmi_offset[5] = dmi_offset[2];
Hans de Goede7845cd72007-12-20 16:42:59 +01001003 dmi_vref = vref;
1004 }
1005}
1006
Jean Delvare310ec792009-12-14 21:17:23 +01001007static int fschmd_detect(struct i2c_client *client,
Jean Delvare40ac1992008-07-16 19:30:12 +02001008 struct i2c_board_info *info)
Hans de Goede569ff102007-10-11 08:06:29 -04001009{
Jean Delvare52df6442009-12-09 20:35:57 +01001010 enum chips kind;
Jean Delvare40ac1992008-07-16 19:30:12 +02001011 struct i2c_adapter *adapter = client->adapter;
Jean Delvare52df6442009-12-09 20:35:57 +01001012 char id[4];
Hans de Goede569ff102007-10-11 08:06:29 -04001013
1014 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
Jean Delvare40ac1992008-07-16 19:30:12 +02001015 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001016
1017 /* Detect & Identify the chip */
Jean Delvare52df6442009-12-09 20:35:57 +01001018 id[0] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_0);
1019 id[1] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_1);
1020 id[2] = i2c_smbus_read_byte_data(client, FSCHMD_REG_IDENT_2);
1021 id[3] = '\0';
Hans de Goede569ff102007-10-11 08:06:29 -04001022
Jean Delvare52df6442009-12-09 20:35:57 +01001023 if (!strcmp(id, "PEG"))
1024 kind = fscpos;
1025 else if (!strcmp(id, "HER"))
1026 kind = fscher;
1027 else if (!strcmp(id, "SCY"))
1028 kind = fscscy;
1029 else if (!strcmp(id, "HRC"))
1030 kind = fschrc;
1031 else if (!strcmp(id, "HMD"))
1032 kind = fschmd;
1033 else if (!strcmp(id, "HDS"))
1034 kind = fschds;
1035 else if (!strcmp(id, "SYL"))
1036 kind = fscsyl;
1037 else
1038 return -ENODEV;
Hans de Goede569ff102007-10-11 08:06:29 -04001039
Jean Delvaredc71afe2010-03-05 22:17:26 +01001040 strlcpy(info->type, fschmd_id[kind].name, I2C_NAME_SIZE);
Jean Delvare40ac1992008-07-16 19:30:12 +02001041
1042 return 0;
1043}
1044
1045static int fschmd_probe(struct i2c_client *client,
1046 const struct i2c_device_id *id)
1047{
1048 struct fschmd_data *data;
Hans de Goedede15f092009-03-30 21:46:45 +02001049 const char * const names[7] = { "Poseidon", "Hermes", "Scylla",
1050 "Heracles", "Heimdall", "Hades", "Syleus" };
Hans de Goede97950c32009-01-07 16:37:33 +01001051 const int watchdog_minors[] = { WATCHDOG_MINOR, 212, 213, 214, 215 };
Jean Delvare40ac1992008-07-16 19:30:12 +02001052 int i, err;
1053 enum chips kind = id->driver_data;
1054
1055 data = kzalloc(sizeof(struct fschmd_data), GFP_KERNEL);
1056 if (!data)
1057 return -ENOMEM;
1058
1059 i2c_set_clientdata(client, data);
1060 mutex_init(&data->update_lock);
Hans de Goede97950c32009-01-07 16:37:33 +01001061 mutex_init(&data->watchdog_lock);
1062 INIT_LIST_HEAD(&data->list);
1063 kref_init(&data->kref);
1064 /* Store client pointer in our data struct for watchdog usage
1065 (where the client is found through a data ptr instead of the
1066 otherway around) */
1067 data->client = client;
Jean Delvaredc71afe2010-03-05 22:17:26 +01001068 data->kind = kind;
Jean Delvare40ac1992008-07-16 19:30:12 +02001069
Hans de Goede569ff102007-10-11 08:06:29 -04001070 if (kind == fscpos) {
1071 /* The Poseidon has hardwired temp limits, fill these
1072 in for the alarm resetting code */
1073 data->temp_max[0] = 70 + 128;
1074 data->temp_max[1] = 50 + 128;
1075 data->temp_max[2] = 50 + 128;
1076 }
1077
Hans de Goede7845cd72007-12-20 16:42:59 +01001078 /* Read the special DMI table for fscher and newer chips */
Hans de Goede453e3082009-01-07 16:37:33 +01001079 if ((kind == fscher || kind >= fschrc) && dmi_vref == -1) {
Jean Delvaree7a19c562009-03-30 21:46:44 +02001080 dmi_walk(fschmd_dmi_decode, NULL);
Hans de Goede7845cd72007-12-20 16:42:59 +01001081 if (dmi_vref == -1) {
Hans de Goede453e3082009-01-07 16:37:33 +01001082 dev_warn(&client->dev,
1083 "Couldn't get voltage scaling factors from "
Hans de Goede7845cd72007-12-20 16:42:59 +01001084 "BIOS DMI table, using builtin defaults\n");
1085 dmi_vref = 33;
1086 }
1087 }
1088
Hans de Goede97950c32009-01-07 16:37:33 +01001089 /* Read in some never changing registers */
1090 data->revision = i2c_smbus_read_byte_data(client, FSCHMD_REG_REVISION);
1091 data->global_control = i2c_smbus_read_byte_data(client,
1092 FSCHMD_REG_CONTROL);
1093 data->watchdog_control = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001094 FSCHMD_REG_WDOG_CONTROL[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001095 data->watchdog_state = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001096 FSCHMD_REG_WDOG_STATE[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001097 data->watchdog_preset = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001098 FSCHMD_REG_WDOG_PRESET[data->kind]);
Hans de Goede97950c32009-01-07 16:37:33 +01001099
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001100 err = device_create_file(&client->dev, &dev_attr_alert_led);
1101 if (err)
1102 goto exit_detach;
Hans de Goede569ff102007-10-11 08:06:29 -04001103
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001104 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++) {
Hans de Goede569ff102007-10-11 08:06:29 -04001105 err = device_create_file(&client->dev,
1106 &fschmd_attr[i].dev_attr);
1107 if (err)
1108 goto exit_detach;
1109 }
1110
1111 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++) {
1112 /* Poseidon doesn't have TEMP_LIMIT registers */
1113 if (kind == fscpos && fschmd_temp_attr[i].dev_attr.show ==
1114 show_temp_max)
1115 continue;
1116
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001117 if (kind == fscsyl) {
1118 if (i % 4 == 0)
1119 data->temp_status[i / 4] =
1120 i2c_smbus_read_byte_data(client,
1121 FSCHMD_REG_TEMP_STATE
1122 [data->kind][i / 4]);
1123 if (data->temp_status[i / 4] & FSCHMD_TEMP_DISABLED)
1124 continue;
1125 }
1126
Hans de Goede569ff102007-10-11 08:06:29 -04001127 err = device_create_file(&client->dev,
1128 &fschmd_temp_attr[i].dev_attr);
1129 if (err)
1130 goto exit_detach;
1131 }
1132
1133 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++) {
1134 /* Poseidon doesn't have a FAN_MIN register for its 3rd fan */
1135 if (kind == fscpos &&
1136 !strcmp(fschmd_fan_attr[i].dev_attr.attr.name,
1137 "pwm3_auto_point1_pwm"))
1138 continue;
1139
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001140 if (kind == fscsyl) {
1141 if (i % 5 == 0)
1142 data->fan_status[i / 5] =
1143 i2c_smbus_read_byte_data(client,
1144 FSCHMD_REG_FAN_STATE
1145 [data->kind][i / 5]);
1146 if (data->fan_status[i / 5] & FSCHMD_FAN_DISABLED)
1147 continue;
1148 }
1149
Hans de Goede569ff102007-10-11 08:06:29 -04001150 err = device_create_file(&client->dev,
1151 &fschmd_fan_attr[i].dev_attr);
1152 if (err)
1153 goto exit_detach;
1154 }
1155
1156 data->hwmon_dev = hwmon_device_register(&client->dev);
1157 if (IS_ERR(data->hwmon_dev)) {
1158 err = PTR_ERR(data->hwmon_dev);
1159 data->hwmon_dev = NULL;
1160 goto exit_detach;
1161 }
1162
Hans de Goede97950c32009-01-07 16:37:33 +01001163 /* We take the data_mutex lock early so that watchdog_open() cannot
1164 run when misc_register() has completed, but we've not yet added
1165 our data to the watchdog_data_list (and set the default timeout) */
1166 mutex_lock(&watchdog_data_mutex);
1167 for (i = 0; i < ARRAY_SIZE(watchdog_minors); i++) {
1168 /* Register our watchdog part */
1169 snprintf(data->watchdog_name, sizeof(data->watchdog_name),
1170 "watchdog%c", (i == 0) ? '\0' : ('0' + i));
1171 data->watchdog_miscdev.name = data->watchdog_name;
1172 data->watchdog_miscdev.fops = &watchdog_fops;
1173 data->watchdog_miscdev.minor = watchdog_minors[i];
1174 err = misc_register(&data->watchdog_miscdev);
1175 if (err == -EBUSY)
1176 continue;
1177 if (err) {
1178 data->watchdog_miscdev.minor = 0;
1179 dev_err(&client->dev,
1180 "Registering watchdog chardev: %d\n", err);
1181 break;
1182 }
1183
1184 list_add(&data->list, &watchdog_data_list);
1185 watchdog_set_timeout(data, 60);
1186 dev_info(&client->dev,
1187 "Registered watchdog chardev major 10, minor: %d\n",
1188 watchdog_minors[i]);
1189 break;
1190 }
1191 if (i == ARRAY_SIZE(watchdog_minors)) {
1192 data->watchdog_miscdev.minor = 0;
1193 dev_warn(&client->dev, "Couldn't register watchdog chardev "
1194 "(due to no free minor)\n");
1195 }
1196 mutex_unlock(&watchdog_data_mutex);
1197
Hans de Goede453e3082009-01-07 16:37:33 +01001198 dev_info(&client->dev, "Detected FSC %s chip, revision: %d\n",
Hans de Goede97950c32009-01-07 16:37:33 +01001199 names[data->kind], (int) data->revision);
Hans de Goede569ff102007-10-11 08:06:29 -04001200
1201 return 0;
1202
1203exit_detach:
Jean Delvare40ac1992008-07-16 19:30:12 +02001204 fschmd_remove(client); /* will also free data for us */
Hans de Goede569ff102007-10-11 08:06:29 -04001205 return err;
1206}
1207
Jean Delvare40ac1992008-07-16 19:30:12 +02001208static int fschmd_remove(struct i2c_client *client)
Hans de Goede569ff102007-10-11 08:06:29 -04001209{
1210 struct fschmd_data *data = i2c_get_clientdata(client);
Jean Delvare40ac1992008-07-16 19:30:12 +02001211 int i;
Hans de Goede569ff102007-10-11 08:06:29 -04001212
Hans de Goede97950c32009-01-07 16:37:33 +01001213 /* Unregister the watchdog (if registered) */
1214 if (data->watchdog_miscdev.minor) {
1215 misc_deregister(&data->watchdog_miscdev);
1216 if (data->watchdog_is_open) {
1217 dev_warn(&client->dev,
1218 "i2c client detached with watchdog open! "
1219 "Stopping watchdog.\n");
1220 watchdog_stop(data);
1221 }
1222 mutex_lock(&watchdog_data_mutex);
1223 list_del(&data->list);
1224 mutex_unlock(&watchdog_data_mutex);
1225 /* Tell the watchdog code the client is gone */
1226 mutex_lock(&data->watchdog_lock);
1227 data->client = NULL;
1228 mutex_unlock(&data->watchdog_lock);
1229 }
1230
Hans de Goede569ff102007-10-11 08:06:29 -04001231 /* Check if registered in case we're called from fschmd_detect
1232 to cleanup after an error */
1233 if (data->hwmon_dev)
1234 hwmon_device_unregister(data->hwmon_dev);
1235
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001236 device_remove_file(&client->dev, &dev_attr_alert_led);
1237 for (i = 0; i < (FSCHMD_NO_VOLT_SENSORS[data->kind]); i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001238 device_remove_file(&client->dev, &fschmd_attr[i].dev_attr);
1239 for (i = 0; i < (FSCHMD_NO_TEMP_SENSORS[data->kind] * 4); i++)
1240 device_remove_file(&client->dev,
1241 &fschmd_temp_attr[i].dev_attr);
1242 for (i = 0; i < (FSCHMD_NO_FAN_SENSORS[data->kind] * 5); i++)
1243 device_remove_file(&client->dev,
1244 &fschmd_fan_attr[i].dev_attr);
1245
Hans de Goede97950c32009-01-07 16:37:33 +01001246 mutex_lock(&watchdog_data_mutex);
1247 kref_put(&data->kref, fschmd_release_resources);
1248 mutex_unlock(&watchdog_data_mutex);
1249
Hans de Goede569ff102007-10-11 08:06:29 -04001250 return 0;
1251}
1252
1253static struct fschmd_data *fschmd_update_device(struct device *dev)
1254{
1255 struct i2c_client *client = to_i2c_client(dev);
1256 struct fschmd_data *data = i2c_get_clientdata(client);
1257 int i;
1258
1259 mutex_lock(&data->update_lock);
1260
1261 if (time_after(jiffies, data->last_updated + 2 * HZ) || !data->valid) {
1262
1263 for (i = 0; i < FSCHMD_NO_TEMP_SENSORS[data->kind]; i++) {
1264 data->temp_act[i] = i2c_smbus_read_byte_data(client,
1265 FSCHMD_REG_TEMP_ACT[data->kind][i]);
1266 data->temp_status[i] = i2c_smbus_read_byte_data(client,
1267 FSCHMD_REG_TEMP_STATE[data->kind][i]);
1268
1269 /* The fscpos doesn't have TEMP_LIMIT registers */
1270 if (FSCHMD_REG_TEMP_LIMIT[data->kind][i])
1271 data->temp_max[i] = i2c_smbus_read_byte_data(
1272 client,
1273 FSCHMD_REG_TEMP_LIMIT[data->kind][i]);
1274
1275 /* reset alarm if the alarm condition is gone,
1276 the chip doesn't do this itself */
1277 if ((data->temp_status[i] & FSCHMD_TEMP_ALARM_MASK) ==
1278 FSCHMD_TEMP_ALARM_MASK &&
1279 data->temp_act[i] < data->temp_max[i])
1280 i2c_smbus_write_byte_data(client,
1281 FSCHMD_REG_TEMP_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001282 data->temp_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001283 }
1284
1285 for (i = 0; i < FSCHMD_NO_FAN_SENSORS[data->kind]; i++) {
1286 data->fan_act[i] = i2c_smbus_read_byte_data(client,
1287 FSCHMD_REG_FAN_ACT[data->kind][i]);
1288 data->fan_status[i] = i2c_smbus_read_byte_data(client,
1289 FSCHMD_REG_FAN_STATE[data->kind][i]);
1290 data->fan_ripple[i] = i2c_smbus_read_byte_data(client,
1291 FSCHMD_REG_FAN_RIPPLE[data->kind][i]);
1292
1293 /* The fscpos third fan doesn't have a fan_min */
1294 if (FSCHMD_REG_FAN_MIN[data->kind][i])
1295 data->fan_min[i] = i2c_smbus_read_byte_data(
1296 client,
1297 FSCHMD_REG_FAN_MIN[data->kind][i]);
1298
1299 /* reset fan status if speed is back to > 0 */
Hans de Goede453e3082009-01-07 16:37:33 +01001300 if ((data->fan_status[i] & FSCHMD_FAN_ALARM) &&
Hans de Goede569ff102007-10-11 08:06:29 -04001301 data->fan_act[i])
1302 i2c_smbus_write_byte_data(client,
1303 FSCHMD_REG_FAN_STATE[data->kind][i],
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001304 data->fan_status[i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001305 }
1306
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001307 for (i = 0; i < FSCHMD_NO_VOLT_SENSORS[data->kind]; i++)
Hans de Goede569ff102007-10-11 08:06:29 -04001308 data->volt[i] = i2c_smbus_read_byte_data(client,
Hans de Goedec69ab2b2009-03-30 21:46:45 +02001309 FSCHMD_REG_VOLT[data->kind][i]);
Hans de Goede569ff102007-10-11 08:06:29 -04001310
Hans de Goede569ff102007-10-11 08:06:29 -04001311 data->last_updated = jiffies;
1312 data->valid = 1;
1313 }
1314
1315 mutex_unlock(&data->update_lock);
1316
1317 return data;
1318}
1319
1320static int __init fschmd_init(void)
1321{
1322 return i2c_add_driver(&fschmd_driver);
1323}
1324
1325static void __exit fschmd_exit(void)
1326{
1327 i2c_del_driver(&fschmd_driver);
1328}
1329
Hans de Goede453e3082009-01-07 16:37:33 +01001330MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
Hans de Goedede15f092009-03-30 21:46:45 +02001331MODULE_DESCRIPTION("FSC Poseidon, Hermes, Scylla, Heracles, Heimdall, Hades "
1332 "and Syleus driver");
Hans de Goede569ff102007-10-11 08:06:29 -04001333MODULE_LICENSE("GPL");
1334
1335module_init(fschmd_init);
1336module_exit(fschmd_exit);