aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon
diff options
context:
space:
mode:
authorHans de Goede <j.w.r.degoede@hhs.nl>2007-07-13 08:34:19 -0400
committerMark M. Hoffman <mhoffman@lightlink.com>2007-10-09 22:56:29 -0400
commit45fb366940d51c309581813ef35bb70a9e34b17d (patch)
treec4d38da93550b564e5b6dffe411f2ab4ba82959b /drivers/hwmon
parent9cab0217f3f35bd618363842576867badb72ca4b (diff)
hwmon: add support for Fintek F71882FG and F71883FG
This is the second version of a new driver for the hardware monitoring features of the Fintek F71882FG and F71883FG Super-I/O chips. This version has several small fixes for flaws discovered during the review of the first version. This version of the driver does not support the pwm part of these chips (yet). I'll first design a sysfs api for this and post that for discussion, and then implement pwm support as an incremental patch over this one. This driver supports all sensors of this chip, except for the vid inputs. The vid inputs are somewhat documented in the datasheet, but I know nothing about vid/vrm stuff. Help with this would be much appreciated. Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl> Acked-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/f71882fg.c950
3 files changed, 961 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 2aeec4787e5f..73177933ae86 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -216,6 +216,16 @@ config SENSORS_F71805F
216 This driver can also be built as a module. If so, the module 216 This driver can also be built as a module. If so, the module
217 will be called f71805f. 217 will be called f71805f.
218 218
219config SENSORS_F71882FG
220 tristate "Fintek F71882FG and F71883FG"
221 depends on EXPERIMENTAL
222 help
223 If you say yes here you get support for hardware monitoring
224 features of the Fintek F71882FG and F71883FG Super-I/O chips.
225
226 This driver can also be built as a module. If so, the module
227 will be called f71882fg.
228
219config SENSORS_FSCHER 229config SENSORS_FSCHER
220 tristate "FSC Hermes" 230 tristate "FSC Hermes"
221 depends on I2C 231 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index d04f90031ebf..6e9fdc29061f 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
29obj-$(CONFIG_SENSORS_DME1737) += dme1737.o 29obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
30obj-$(CONFIG_SENSORS_DS1621) += ds1621.o 30obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
31obj-$(CONFIG_SENSORS_F71805F) += f71805f.o 31obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
32obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
32obj-$(CONFIG_SENSORS_FSCHER) += fscher.o 33obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
33obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o 34obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
34obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o 35obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
new file mode 100644
index 000000000000..68f5102110b1
--- /dev/null
+++ b/drivers/hwmon/f71882fg.c
@@ -0,0 +1,950 @@
1/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
3 * Copyright (C) 2007 by Hans de Goede <j.w.r.degoede@hhs.nl> *
4 * *
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 *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/jiffies.h>
25#include <linux/platform_device.h>
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h>
29#include <linux/mutex.h>
30#include <asm/io.h>
31
32#define DRVNAME "f71882fg"
33
34#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device*/
35#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
36#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
37
38#define SIO_REG_LDSEL 0x07 /* Logical device select */
39#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
40#define SIO_REG_DEVREV 0x22 /* Device revision */
41#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
42#define SIO_REG_ENABLE 0x30 /* Logical device enable */
43#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
44
45#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
46#define SIO_F71882_ID 0x0541 /* Chipset ID */
47
48#define REGION_LENGTH 8
49#define ADDR_REG_OFFSET 5
50#define DATA_REG_OFFSET 6
51
52#define F71882FG_REG_PECI 0x0A
53
54#define F71882FG_REG_IN_STATUS 0x12
55#define F71882FG_REG_IN_BEEP 0x13
56#define F71882FG_REG_IN(nr) (0x20 + (nr))
57#define F71882FG_REG_IN1_HIGH 0x32
58
59#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
60#define F71882FG_REG_FAN_STATUS 0x92
61#define F71882FG_REG_FAN_BEEP 0x93
62
63#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
64#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
65#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
66#define F71882FG_REG_TEMP_STATUS 0x62
67#define F71882FG_REG_TEMP_BEEP 0x63
68#define F71882FG_REG_TEMP_HYST1 0x6C
69#define F71882FG_REG_TEMP_HYST23 0x6D
70#define F71882FG_REG_TEMP_TYPE 0x6B
71#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
72
73#define F71882FG_REG_START 0x01
74
75#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
76
77static struct platform_device *f71882fg_pdev = NULL;
78
79/* Super-I/O Function prototypes */
80static inline int superio_inb(int base, int reg);
81static inline int superio_inw(int base, int reg);
82static inline void superio_enter(int base);
83static inline void superio_select(int base, int ld);
84static inline void superio_exit(int base);
85
86static inline u16 fan_from_reg ( u16 reg );
87
88struct f71882fg_data {
89 unsigned short addr;
90 struct class_device *class_dev;
91
92 struct mutex update_lock;
93 char valid; /* !=0 if following fields are valid */
94 unsigned long last_updated; /* In jiffies */
95 unsigned long last_limits; /* In jiffies */
96
97 /* Register Values */
98 u8 in[9];
99 u8 in1_max;
100 u8 in_status;
101 u8 in_beep;
102 u16 fan[4];
103 u8 fan_status;
104 u8 fan_beep;
105 u8 temp[3];
106 u8 temp_ovt[3];
107 u8 temp_high[3];
108 u8 temp_hyst[3];
109 u8 temp_type[3];
110 u8 temp_status;
111 u8 temp_beep;
112 u8 temp_diode_open;
113};
114
115static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
116static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
117static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
118
119/* Sysfs in*/
120static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
121 char *buf);
122static ssize_t show_in_max(struct device *dev, struct device_attribute
123 *devattr, char *buf);
124static ssize_t store_in_max(struct device *dev, struct device_attribute
125 *devattr, const char *buf, size_t count);
126static ssize_t show_in_beep(struct device *dev, struct device_attribute
127 *devattr, char *buf);
128static ssize_t store_in_beep(struct device *dev, struct device_attribute
129 *devattr, const char *buf, size_t count);
130static ssize_t show_in_alarm(struct device *dev, struct device_attribute
131 *devattr, char *buf);
132/* Sysfs Fan */
133static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
134 char *buf);
135static ssize_t show_fan_beep(struct device *dev, struct device_attribute
136 *devattr, char *buf);
137static ssize_t store_fan_beep(struct device *dev, struct device_attribute
138 *devattr, const char *buf, size_t count);
139static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
140 *devattr, char *buf);
141/* Sysfs Temp */
142static ssize_t show_temp(struct device *dev, struct device_attribute
143 *devattr, char *buf);
144static ssize_t show_temp_max(struct device *dev, struct device_attribute
145 *devattr, char *buf);
146static ssize_t store_temp_max(struct device *dev, struct device_attribute
147 *devattr, const char *buf, size_t count);
148static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
149 *devattr, char *buf);
150static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
151 *devattr, const char *buf, size_t count);
152static ssize_t show_temp_crit(struct device *dev, struct device_attribute
153 *devattr, char *buf);
154static ssize_t store_temp_crit(struct device *dev, struct device_attribute
155 *devattr, const char *buf, size_t count);
156static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
157 *devattr, char *buf);
158static ssize_t show_temp_type(struct device *dev, struct device_attribute
159 *devattr, char *buf);
160static ssize_t show_temp_beep(struct device *dev, struct device_attribute
161 *devattr, char *buf);
162static ssize_t store_temp_beep(struct device *dev, struct device_attribute
163 *devattr, const char *buf, size_t count);
164static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
165 *devattr, char *buf);
166static ssize_t show_temp_fault(struct device *dev, struct device_attribute
167 *devattr, char *buf);
168/* Sysfs misc */
169static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
170 char *buf);
171
172static int __devinit f71882fg_probe(struct platform_device * pdev);
173static int __devexit f71882fg_remove(struct platform_device *pdev);
174static int __init f71882fg_init(void);
175static int __init f71882fg_find(int sioaddr, unsigned short *address);
176static int __init f71882fg_device_add(unsigned short address);
177static void __exit f71882fg_exit(void);
178
179static struct platform_driver f71882fg_driver = {
180 .driver = {
181 .owner = THIS_MODULE,
182 .name = DRVNAME,
183 },
184 .probe = f71882fg_probe,
185 .remove = __devexit_p(f71882fg_remove),
186};
187
188static struct device_attribute f71882fg_dev_attr[] =
189{
190 __ATTR( name, S_IRUGO, show_name, NULL ),
191};
192
193static struct sensor_device_attribute f71882fg_in_temp_attr[] =
194{
195 SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
196 SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
197 SENSOR_ATTR(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max, 1),
198 SENSOR_ATTR(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep, 1),
199 SENSOR_ATTR(in1_alarm, S_IRUGO, show_in_alarm, NULL, 1),
200 SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
201 SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
202 SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
203 SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
204 SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
205 SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
206 SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
207 SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
208 SENSOR_ATTR(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
209 store_temp_max, 0),
210 SENSOR_ATTR(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
211 store_temp_max_hyst, 0),
212 SENSOR_ATTR(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
213 store_temp_crit, 0),
214 SENSOR_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 0),
215 SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
216 SENSOR_ATTR(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
217 store_temp_beep, 0),
218 SENSOR_ATTR(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0),
219 SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0),
220 SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
221 SENSOR_ATTR(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
222 store_temp_max, 1),
223 SENSOR_ATTR(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
224 store_temp_max_hyst, 1),
225 SENSOR_ATTR(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
226 store_temp_crit, 1),
227 SENSOR_ATTR(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 1),
228 SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
229 SENSOR_ATTR(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
230 store_temp_beep, 1),
231 SENSOR_ATTR(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 1),
232 SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1),
233 SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
234 SENSOR_ATTR(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
235 store_temp_max, 2),
236 SENSOR_ATTR(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
237 store_temp_max_hyst, 2),
238 SENSOR_ATTR(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
239 store_temp_crit, 2),
240 SENSOR_ATTR(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, 2),
241 SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
242 SENSOR_ATTR(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
243 store_temp_beep, 2),
244 SENSOR_ATTR(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 2),
245 SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2)
246};
247
248static struct sensor_device_attribute f71882fg_fan_attr[] =
249{
250 SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
251 SENSOR_ATTR(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
252 store_fan_beep, 0),
253 SENSOR_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0),
254 SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
255 SENSOR_ATTR(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
256 store_fan_beep, 1),
257 SENSOR_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1),
258 SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
259 SENSOR_ATTR(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
260 store_fan_beep, 2),
261 SENSOR_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2),
262 SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
263 SENSOR_ATTR(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
264 store_fan_beep, 3),
265 SENSOR_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3)
266};
267
268
269/* Super I/O functions */
270static inline int superio_inb(int base, int reg)
271{
272 outb(reg, base);
273 return inb(base + 1);
274}
275
276static int superio_inw(int base, int reg)
277{
278 int val;
279 outb(reg++, base);
280 val = inb(base + 1) << 8;
281 outb(reg, base);
282 val |= inb(base + 1);
283 return val;
284}
285
286static inline void superio_enter(int base)
287{
288 /* according to the datasheet the key must be send twice! */
289 outb( SIO_UNLOCK_KEY, base);
290 outb( SIO_UNLOCK_KEY, base);
291}
292
293static inline void superio_select( int base, int ld)
294{
295 outb(SIO_REG_LDSEL, base);
296 outb(ld, base + 1);
297}
298
299static inline void superio_exit(int base)
300{
301 outb(SIO_LOCK_KEY, base);
302}
303
304static inline u16 fan_from_reg(u16 reg)
305{
306 return reg ? (1500000 / reg) : 0;
307}
308
309static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
310{
311 u8 val;
312
313 outb(reg, data->addr + ADDR_REG_OFFSET);
314 val = inb(data->addr + DATA_REG_OFFSET);
315
316 return val;
317}
318
319static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
320{
321 u16 val;
322
323 outb(reg++, data->addr + ADDR_REG_OFFSET);
324 val = inb(data->addr + DATA_REG_OFFSET) << 8;
325 outb(reg, data->addr + ADDR_REG_OFFSET);
326 val |= inb(data->addr + DATA_REG_OFFSET);
327
328 return val;
329}
330
331static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
332{
333 outb(reg, data->addr + ADDR_REG_OFFSET);
334 outb(val, data->addr + DATA_REG_OFFSET);
335}
336
337static struct f71882fg_data *f71882fg_update_device(struct device * dev)
338{
339 struct f71882fg_data *data = dev_get_drvdata(dev);
340 int nr, reg, reg2;
341
342 mutex_lock(&data->update_lock);
343
344 /* Update once every 60 seconds */
345 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
346 !data->valid) {
347 data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
348 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
349
350 /* Get High & boundary temps*/
351 for (nr = 0; nr < 3; nr++) {
352 data->temp_ovt[nr] = f71882fg_read8(data,
353 F71882FG_REG_TEMP_OVT(nr));
354 data->temp_high[nr] = f71882fg_read8(data,
355 F71882FG_REG_TEMP_HIGH(nr));
356 }
357
358 /* Have to hardcode hyst*/
359 data->temp_hyst[0] = f71882fg_read8(data,
360 F71882FG_REG_TEMP_HYST1) >> 4;
361 /* Hyst temps 2 & 3 stored in same register */
362 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
363 data->temp_hyst[1] = reg & 0x0F;
364 data->temp_hyst[2] = reg >> 4;
365
366 /* Have to hardcode type, because temp1 is special */
367 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
368 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
369 if ((reg2 & 0x03) == 0x01)
370 data->temp_type[0] = 6 /* PECI */;
371 else if ((reg2 & 0x03) == 0x02)
372 data->temp_type[0] = 5 /* AMDSI */;
373 else
374 data->temp_type[0] = (reg & 0x02) ? 2 : 4;
375
376 data->temp_type[1] = (reg & 0x04) ? 2 : 4;
377 data->temp_type[2] = (reg & 0x08) ? 2 : 4;
378
379 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
380
381 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
382
383 data->last_limits = jiffies;
384 }
385
386 /* Update every second */
387 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
388 data->temp_status = f71882fg_read8(data,
389 F71882FG_REG_TEMP_STATUS);
390 data->temp_diode_open = f71882fg_read8(data,
391 F71882FG_REG_TEMP_DIODE_OPEN);
392 for (nr = 0; nr < 3; nr++)
393 data->temp[nr] = f71882fg_read8(data,
394 F71882FG_REG_TEMP(nr));
395
396 data->fan_status = f71882fg_read8(data,
397 F71882FG_REG_FAN_STATUS);
398 for (nr = 0; nr < 4; nr++)
399 data->fan[nr] = f71882fg_read16(data,
400 F71882FG_REG_FAN(nr));
401
402 data->in_status = f71882fg_read8(data,
403 F71882FG_REG_IN_STATUS);
404 for (nr = 0; nr < 9; nr++)
405 data->in[nr] = f71882fg_read8(data,
406 F71882FG_REG_IN(nr));
407
408 data->last_updated = jiffies;
409 data->valid = 1;
410 }
411
412 mutex_unlock(&data->update_lock);
413
414 return data;
415}
416
417/* Sysfs Interface */
418static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
419 char *buf)
420{
421 struct f71882fg_data *data = f71882fg_update_device(dev);
422 int nr = to_sensor_dev_attr(devattr)->index;
423 int speed = fan_from_reg(data->fan[nr]);
424
425 if (speed == FAN_MIN_DETECT)
426 speed = 0;
427
428 return sprintf(buf, "%d\n", speed);
429}
430
431static ssize_t show_fan_beep(struct device *dev, struct device_attribute
432 *devattr, char *buf)
433{
434 struct f71882fg_data *data = f71882fg_update_device(dev);
435 int nr = to_sensor_dev_attr(devattr)->index;
436
437 if (data->fan_beep & (1 << nr))
438 return sprintf(buf, "1\n");
439 else
440 return sprintf(buf, "0\n");
441}
442
443static ssize_t store_fan_beep(struct device *dev, struct device_attribute
444 *devattr, const char *buf, size_t count)
445{
446 struct f71882fg_data *data = dev_get_drvdata(dev);
447 int nr = to_sensor_dev_attr(devattr)->index;
448 int val = simple_strtoul(buf, NULL, 10);
449
450 mutex_lock(&data->update_lock);
451 if (val)
452 data->fan_beep |= 1 << nr;
453 else
454 data->fan_beep &= ~(1 << nr);
455
456 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
457 mutex_unlock(&data->update_lock);
458
459 return count;
460}
461
462static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
463 *devattr, char *buf)
464{
465 struct f71882fg_data *data = f71882fg_update_device(dev);
466 int nr = to_sensor_dev_attr(devattr)->index;
467
468 if (data->fan_status & (1 << nr))
469 return sprintf(buf, "1\n");
470 else
471 return sprintf(buf, "0\n");
472}
473
474static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
475 char *buf)
476{
477 struct f71882fg_data *data = f71882fg_update_device(dev);
478 int nr = to_sensor_dev_attr(devattr)->index;
479
480 return sprintf(buf, "%d\n", data->in[nr] * 8);
481}
482
483static ssize_t show_in_max(struct device *dev, struct device_attribute
484 *devattr, char *buf)
485{
486 struct f71882fg_data *data = f71882fg_update_device(dev);
487
488 return sprintf(buf, "%d\n", data->in1_max * 8);
489}
490
491static ssize_t store_in_max(struct device *dev, struct device_attribute
492 *devattr, const char *buf, size_t count)
493{
494 struct f71882fg_data *data = dev_get_drvdata(dev);
495 int val = simple_strtoul(buf, NULL, 10) / 8;
496
497 if (val > 255)
498 val = 255;
499
500 mutex_lock(&data->update_lock);
501 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
502 data->in1_max = val;
503 mutex_unlock(&data->update_lock);
504
505 return count;
506}
507
508static ssize_t show_in_beep(struct device *dev, struct device_attribute
509 *devattr, char *buf)
510{
511 struct f71882fg_data *data = f71882fg_update_device(dev);
512 int nr = to_sensor_dev_attr(devattr)->index;
513
514 if (data->in_beep & (1 << nr))
515 return sprintf(buf, "1\n");
516 else
517 return sprintf(buf, "0\n");
518}
519
520static ssize_t store_in_beep(struct device *dev, struct device_attribute
521 *devattr, const char *buf, size_t count)
522{
523 struct f71882fg_data *data = dev_get_drvdata(dev);
524 int nr = to_sensor_dev_attr(devattr)->index;
525 int val = simple_strtoul(buf, NULL, 10);
526
527 mutex_lock(&data->update_lock);
528 if (val)
529 data->in_beep |= 1 << nr;
530 else
531 data->in_beep &= ~(1 << nr);
532
533 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
534 mutex_unlock(&data->update_lock);
535
536 return count;
537}
538
539static ssize_t show_in_alarm(struct device *dev, struct device_attribute
540 *devattr, char *buf)
541{
542 struct f71882fg_data *data = f71882fg_update_device(dev);
543 int nr = to_sensor_dev_attr(devattr)->index;
544
545 if (data->in_status & (1 << nr))
546 return sprintf(buf, "1\n");
547 else
548 return sprintf(buf, "0\n");
549}
550
551static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
552 char *buf)
553{
554 struct f71882fg_data *data = f71882fg_update_device(dev);
555 int nr = to_sensor_dev_attr(devattr)->index;
556
557 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
558}
559
560static ssize_t show_temp_max(struct device *dev, struct device_attribute
561 *devattr, char *buf)
562{
563 struct f71882fg_data *data = f71882fg_update_device(dev);
564 int nr = to_sensor_dev_attr(devattr)->index;
565
566 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
567}
568
569static ssize_t store_temp_max(struct device *dev, struct device_attribute
570 *devattr, const char *buf, size_t count)
571{
572 struct f71882fg_data *data = dev_get_drvdata(dev);
573 int nr = to_sensor_dev_attr(devattr)->index;
574 int val = simple_strtoul(buf, NULL, 10) / 1000;
575
576 if (val > 255)
577 val = 255;
578
579 mutex_lock(&data->update_lock);
580 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
581 data->temp_high[nr] = val;
582 mutex_unlock(&data->update_lock);
583
584 return count;
585}
586
587static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
588 *devattr, char *buf)
589{
590 struct f71882fg_data *data = f71882fg_update_device(dev);
591 int nr = to_sensor_dev_attr(devattr)->index;
592
593 return sprintf(buf, "%d\n",
594 (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
595}
596
597static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
598 *devattr, const char *buf, size_t count)
599{
600 struct f71882fg_data *data = dev_get_drvdata(dev);
601 int nr = to_sensor_dev_attr(devattr)->index;
602 int val = simple_strtoul(buf, NULL, 10) / 1000;
603 ssize_t ret = count;
604
605 mutex_lock(&data->update_lock);
606
607 /* convert abs to relative and check */
608 val = data->temp_high[nr] - val;
609 if (val < 0 || val > 15) {
610 ret = -EINVAL;
611 goto store_temp_max_hyst_exit;
612 }
613
614 data->temp_hyst[nr] = val;
615
616 /* convert value to register contents */
617 switch(nr) {
618 case 0:
619 val = val << 4;
620 break;
621 case 1:
622 val = val | (data->temp_hyst[2] << 4);
623 break;
624 case 2:
625 val = data->temp_hyst[1] | (val << 4);
626 break;
627 }
628
629 f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
630 F71882FG_REG_TEMP_HYST1, val);
631
632store_temp_max_hyst_exit:
633 mutex_unlock(&data->update_lock);
634 return ret;
635}
636
637static ssize_t show_temp_crit(struct device *dev, struct device_attribute
638 *devattr, char *buf)
639{
640 struct f71882fg_data *data = f71882fg_update_device(dev);
641 int nr = to_sensor_dev_attr(devattr)->index;
642
643 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
644}
645
646static ssize_t store_temp_crit(struct device *dev, struct device_attribute
647 *devattr, const char *buf, size_t count)
648{
649 struct f71882fg_data *data = dev_get_drvdata(dev);
650 int nr = to_sensor_dev_attr(devattr)->index;
651 int val = simple_strtoul(buf, NULL, 10) / 1000;
652
653 if (val > 255)
654 val = 255;
655
656 mutex_lock(&data->update_lock);
657 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
658 data->temp_ovt[nr] = val;
659 mutex_unlock(&data->update_lock);
660
661 return count;
662}
663
664static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
665 *devattr, char *buf)
666{
667 struct f71882fg_data *data = f71882fg_update_device(dev);
668 int nr = to_sensor_dev_attr(devattr)->index;
669
670 return sprintf(buf, "%d\n",
671 (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
672}
673
674static ssize_t show_temp_type(struct device *dev, struct device_attribute
675 *devattr, char *buf)
676{
677 struct f71882fg_data *data = f71882fg_update_device(dev);
678 int nr = to_sensor_dev_attr(devattr)->index;
679
680 return sprintf(buf, "%d\n", data->temp_type[nr]);
681}
682
683static ssize_t show_temp_beep(struct device *dev, struct device_attribute
684 *devattr, char *buf)
685{
686 struct f71882fg_data *data = f71882fg_update_device(dev);
687 int nr = to_sensor_dev_attr(devattr)->index;
688
689 if (data->temp_beep & (1 << (nr + 1)))
690 return sprintf(buf, "1\n");
691 else
692 return sprintf(buf, "0\n");
693}
694
695static ssize_t store_temp_beep(struct device *dev, struct device_attribute
696 *devattr, const char *buf, size_t count)
697{
698 struct f71882fg_data *data = dev_get_drvdata(dev);
699 int nr = to_sensor_dev_attr(devattr)->index;
700 int val = simple_strtoul(buf, NULL, 10);
701
702 mutex_lock(&data->update_lock);
703 if (val)
704 data->temp_beep |= 1 << (nr + 1);
705 else
706 data->temp_beep &= ~(1 << (nr + 1));
707
708 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
709 mutex_unlock(&data->update_lock);
710
711 return count;
712}
713
714static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
715 *devattr, char *buf)
716{
717 struct f71882fg_data *data = f71882fg_update_device(dev);
718 int nr = to_sensor_dev_attr(devattr)->index;
719
720 if (data->temp_status & (1 << (nr + 1)))
721 return sprintf(buf, "1\n");
722 else
723 return sprintf(buf, "0\n");
724}
725
726static ssize_t show_temp_fault(struct device *dev, struct device_attribute
727 *devattr, char *buf)
728{
729 struct f71882fg_data *data = f71882fg_update_device(dev);
730 int nr = to_sensor_dev_attr(devattr)->index;
731
732 if (data->temp_diode_open & (1 << (nr + 1)))
733 return sprintf(buf, "1\n");
734 else
735 return sprintf(buf, "0\n");
736}
737
738static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
739 char *buf)
740{
741 return sprintf(buf, DRVNAME "\n");
742}
743
744
745static int __devinit f71882fg_probe(struct platform_device * pdev)
746{
747 struct f71882fg_data *data;
748 int err, i;
749 u8 start_reg;
750
751 if(!(data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL)))
752 return -ENOMEM;
753
754 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
755 mutex_init(&data->update_lock);
756 platform_set_drvdata(pdev, data);
757
758 /* Register sysfs interface files */
759 for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++) {
760 err = device_create_file(&pdev->dev, &f71882fg_dev_attr[i]);
761 if (err)
762 goto exit_unregister_sysfs;
763 }
764
765 start_reg = f71882fg_read8(data, F71882FG_REG_START);
766 if (start_reg & 0x01) {
767 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++) {
768 err = device_create_file(&pdev->dev,
769 &f71882fg_in_temp_attr[i].dev_attr);
770 if (err)
771 goto exit_unregister_sysfs;
772 }
773 }
774
775 if (start_reg & 0x02) {
776 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++) {
777 err = device_create_file(&pdev->dev,
778 &f71882fg_fan_attr[i].dev_attr);
779 if (err)
780 goto exit_unregister_sysfs;
781 }
782 }
783
784 data->class_dev = hwmon_device_register(&pdev->dev);
785 if (IS_ERR(data->class_dev)) {
786 err = PTR_ERR(data->class_dev);
787 goto exit_unregister_sysfs;
788 }
789
790 return 0;
791
792exit_unregister_sysfs:
793 for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
794 device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
795
796 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
797 device_remove_file(&pdev->dev,
798 &f71882fg_in_temp_attr[i].dev_attr);
799
800 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
801 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
802
803 kfree(data);
804
805 return err;
806}
807
808static int __devexit f71882fg_remove(struct platform_device *pdev)
809{
810 int i;
811 struct f71882fg_data *data = platform_get_drvdata(pdev);
812
813 platform_set_drvdata(pdev, NULL);
814 hwmon_device_unregister(data->class_dev);
815
816 for (i = 0; i < ARRAY_SIZE(f71882fg_dev_attr); i++)
817 device_remove_file(&pdev->dev, &f71882fg_dev_attr[i]);
818
819 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
820 device_remove_file(&pdev->dev,
821 &f71882fg_in_temp_attr[i].dev_attr);
822
823 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
824 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
825
826 kfree(data);
827
828 return 0;
829}
830
831static int __init f71882fg_find(int sioaddr, unsigned short *address)
832{
833 int err = -ENODEV;
834 u16 devid;
835 u8 start_reg;
836 struct f71882fg_data data;
837
838 superio_enter(sioaddr);
839
840 devid = superio_inw(sioaddr, SIO_REG_MANID);
841 if (devid != SIO_FINTEK_ID) {
842 printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
843 goto exit;
844 }
845
846 devid = superio_inw(sioaddr, SIO_REG_DEVID);
847 if (devid != SIO_F71882_ID) {
848 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
849 goto exit;
850 }
851
852 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
853 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
854 printk(KERN_WARNING DRVNAME ": Device not activated\n");
855 goto exit;
856 }
857
858 *address = superio_inw(sioaddr, SIO_REG_ADDR);
859 if (*address == 0)
860 {
861 printk(KERN_WARNING DRVNAME ": Base address not set\n");
862 goto exit;
863 }
864 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
865
866 data.addr = *address;
867 start_reg = f71882fg_read8(&data, F71882FG_REG_START);
868 if (!(start_reg & 0x03)) {
869 printk(KERN_WARNING DRVNAME
870 ": Hardware monitoring not activated\n");
871 goto exit;
872 }
873
874 err = 0;
875 printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
876 (unsigned int)*address,
877 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
878exit:
879 superio_exit(sioaddr);
880 return err;
881}
882
883static int __init f71882fg_device_add(unsigned short address)
884{
885 struct resource res = {
886 .start = address,
887 .end = address + REGION_LENGTH - 1,
888 .flags = IORESOURCE_IO,
889 };
890 int err;
891
892 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
893 if(!f71882fg_pdev)
894 return -ENOMEM;
895
896 res.name = f71882fg_pdev->name;
897 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
898 if(err) {
899 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
900 goto exit_device_put;
901 }
902
903 err = platform_device_add(f71882fg_pdev);
904 if(err) {
905 printk(KERN_ERR DRVNAME ": Device addition failed\n");
906 goto exit_device_put;
907 }
908
909 return 0;
910
911exit_device_put:
912 platform_device_put(f71882fg_pdev);
913
914 return err;
915}
916
917static int __init f71882fg_init(void)
918{
919 int err = -ENODEV;
920 unsigned short address;
921
922 if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
923 goto exit;
924
925 if ((err = platform_driver_register(&f71882fg_driver)))
926 goto exit;
927
928 if ((err = f71882fg_device_add(address)))
929 goto exit_driver;
930
931 return 0;
932
933exit_driver:
934 platform_driver_unregister(&f71882fg_driver);
935exit:
936 return err;
937}
938
939static void __exit f71882fg_exit(void)
940{
941 platform_device_unregister(f71882fg_pdev);
942 platform_driver_unregister(&f71882fg_driver);
943}
944
945MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
946MODULE_AUTHOR("Hans Edgington (hans@edgington.nl)");
947MODULE_LICENSE("GPL");
948
949module_init(f71882fg_init);
950module_exit(f71882fg_exit);