blob: ec29c611ed3e84badb60ae979c3f67b732defa07 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
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
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010053#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010054#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020055
56#define REGION_LENGTH 8
57#define ADDR_REG_OFFSET 5
58#define DATA_REG_OFFSET 6
59
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
61#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010063#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010066#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
67#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_FAN_STATUS 0x92
69#define F71882FG_REG_FAN_BEEP 0x93
70
Hans de Goede7567a042009-01-07 16:37:28 +010071#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
72#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
73#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_STATUS 0x62
75#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020076#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010077#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020078#define F71882FG_REG_TEMP_TYPE 0x6B
79#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
80
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
82#define F71882FG_REG_PWM_TYPE 0x94
83#define F71882FG_REG_PWM_ENABLE 0x96
84
Hans de Goedebc274902009-01-07 16:37:29 +010085#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010086
Hans de Goede98f7ba12011-03-09 20:57:09 +010087#define F71882FG_REG_FAN_FAULT_T 0x9F
88#define F71882FG_FAN_NEG_TEMP_EN 0x20
89
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010090#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
91#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
92#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
93
Hans de Goede45fb3662007-07-13 14:34:19 +020094#define F71882FG_REG_START 0x01
95
Hans de Goede0bae6402011-03-09 20:57:10 +010096#define F71882FG_MAX_INS 9
97
Hans de Goede45fb3662007-07-13 14:34:19 +020098#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
99
Jean Delvare67b671b2007-12-06 23:13:42 +0100100static unsigned short force_id;
101module_param(force_id, ushort, 0);
102MODULE_PARM_DESC(force_id, "Override the detected device ID");
103
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700104enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100105
106static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200107 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100108 "f71862fg",
109 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100110 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100111 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100112};
113
Hans de Goede0bae6402011-03-09 20:57:10 +0100114static const char f71882fg_has_in[5][F71882FG_MAX_INS] = {
115 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */
116 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */
117 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */
118 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */
119 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */
120};
121
122static const char f71882fg_has_in1_alarm[5] = {
123 0, /* f71858fg */
124 0, /* f71862fg */
125 1, /* f71882fg */
126 1, /* f71889fg */
127 0, /* f8000 */
128};
129
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100130static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200131
132/* Super-I/O Function prototypes */
133static inline int superio_inb(int base, int reg);
134static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400135static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200136static inline void superio_select(int base, int ld);
137static inline void superio_exit(int base);
138
Hans de Goede498be962009-01-07 16:37:28 +0100139struct f71882fg_sio_data {
140 enum chips type;
141};
142
Hans de Goede45fb3662007-07-13 14:34:19 +0200143struct f71882fg_data {
144 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100145 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700146 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200147
148 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200149 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200150 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100151 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200152 unsigned long last_updated; /* In jiffies */
153 unsigned long last_limits; /* In jiffies */
154
155 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100156 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200157 u8 in1_max;
158 u8 in_status;
159 u8 in_beep;
160 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100161 u16 fan_target[4];
162 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200163 u8 fan_status;
164 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100165 /* Note: all models have only 3 temperature channels, but on some
166 they are addressed as 0-2 and on others as 1-3, so for coding
167 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200168 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100169 u8 temp_ovt[4];
170 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100171 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100172 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200173 u8 temp_status;
174 u8 temp_beep;
175 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200176 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100177 u8 pwm[4];
178 u8 pwm_enable;
179 u8 pwm_auto_point_hyst[2];
180 u8 pwm_auto_point_mapping[4];
181 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100182 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200183};
184
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100185/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200186static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
187 char *buf);
188static ssize_t show_in_max(struct device *dev, struct device_attribute
189 *devattr, char *buf);
190static ssize_t store_in_max(struct device *dev, struct device_attribute
191 *devattr, const char *buf, size_t count);
192static ssize_t show_in_beep(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t store_in_beep(struct device *dev, struct device_attribute
195 *devattr, const char *buf, size_t count);
196static ssize_t show_in_alarm(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198/* Sysfs Fan */
199static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
200 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100201static ssize_t show_fan_full_speed(struct device *dev,
202 struct device_attribute *devattr, char *buf);
203static ssize_t store_fan_full_speed(struct device *dev,
204 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200205static ssize_t show_fan_beep(struct device *dev, struct device_attribute
206 *devattr, char *buf);
207static ssize_t store_fan_beep(struct device *dev, struct device_attribute
208 *devattr, const char *buf, size_t count);
209static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
210 *devattr, char *buf);
211/* Sysfs Temp */
212static ssize_t show_temp(struct device *dev, struct device_attribute
213 *devattr, char *buf);
214static ssize_t show_temp_max(struct device *dev, struct device_attribute
215 *devattr, char *buf);
216static ssize_t store_temp_max(struct device *dev, struct device_attribute
217 *devattr, const char *buf, size_t count);
218static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
219 *devattr, char *buf);
220static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
221 *devattr, const char *buf, size_t count);
222static ssize_t show_temp_crit(struct device *dev, struct device_attribute
223 *devattr, char *buf);
224static ssize_t store_temp_crit(struct device *dev, struct device_attribute
225 *devattr, const char *buf, size_t count);
226static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
227 *devattr, char *buf);
228static ssize_t show_temp_type(struct device *dev, struct device_attribute
229 *devattr, char *buf);
230static ssize_t show_temp_beep(struct device *dev, struct device_attribute
231 *devattr, char *buf);
232static ssize_t store_temp_beep(struct device *dev, struct device_attribute
233 *devattr, const char *buf, size_t count);
234static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
235 *devattr, char *buf);
236static ssize_t show_temp_fault(struct device *dev, struct device_attribute
237 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100238/* PWM and Auto point control */
239static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
240 char *buf);
241static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
242 const char *buf, size_t count);
243static ssize_t show_pwm_enable(struct device *dev,
244 struct device_attribute *devattr, char *buf);
245static ssize_t store_pwm_enable(struct device *dev,
246 struct device_attribute *devattr, const char *buf, size_t count);
247static ssize_t show_pwm_interpolate(struct device *dev,
248 struct device_attribute *devattr, char *buf);
249static ssize_t store_pwm_interpolate(struct device *dev,
250 struct device_attribute *devattr, const char *buf, size_t count);
251static ssize_t show_pwm_auto_point_channel(struct device *dev,
252 struct device_attribute *devattr, char *buf);
253static ssize_t store_pwm_auto_point_channel(struct device *dev,
254 struct device_attribute *devattr, const char *buf, size_t count);
255static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
256 struct device_attribute *devattr, char *buf);
257static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
258 struct device_attribute *devattr, const char *buf, size_t count);
259static ssize_t show_pwm_auto_point_pwm(struct device *dev,
260 struct device_attribute *devattr, char *buf);
261static ssize_t store_pwm_auto_point_pwm(struct device *dev,
262 struct device_attribute *devattr, const char *buf, size_t count);
263static ssize_t show_pwm_auto_point_temp(struct device *dev,
264 struct device_attribute *devattr, char *buf);
265static ssize_t store_pwm_auto_point_temp(struct device *dev,
266 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200267/* Sysfs misc */
268static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
269 char *buf);
270
271static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100272static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200273
274static struct platform_driver f71882fg_driver = {
275 .driver = {
276 .owner = THIS_MODULE,
277 .name = DRVNAME,
278 },
279 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200280 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200281};
282
Hans de Goedec13548c2009-01-07 16:37:27 +0100283static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200284
Hans de Goede0bae6402011-03-09 20:57:10 +0100285/* Temp attr for the f71858fg, the f71858fg is special as it has its
286 temperature indexes start at 0 (the others start at 1) */
287static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200288 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
289 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
290 store_temp_max, 0, 0),
291 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
292 store_temp_max_hyst, 0, 0),
293 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
294 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
295 store_temp_crit, 0, 0),
296 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
297 0, 0),
298 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
299 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
300 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
301 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
302 store_temp_max, 0, 1),
303 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
304 store_temp_max_hyst, 0, 1),
305 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
306 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
307 store_temp_crit, 0, 1),
308 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
309 0, 1),
310 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
311 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
312 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
313 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
314 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
315 store_temp_max, 0, 2),
316 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
317 store_temp_max_hyst, 0, 2),
318 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
319 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
320 store_temp_crit, 0, 2),
321 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
322 0, 2),
323 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
324 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
325};
326
Hans de Goede0bae6402011-03-09 20:57:10 +0100327/* Temp attr for the standard models */
328static struct sensor_device_attribute_2 fxxxx_temp_attr[] = {
Hans de Goede7567a042009-01-07 16:37:28 +0100329 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100330 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100331 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100332 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100333 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100334 /* Should really be temp1_max_alarm, but older versions did not handle
335 the max and crit alarms separately and lm_sensors v2 depends on the
336 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
337 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
338 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
339 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100340 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100341 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100342 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100343 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100344 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
345 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
346 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100348 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
349 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
350 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100351 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100352 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100353 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100354 /* Should be temp2_max_alarm, see temp1_alarm note */
355 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
356 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
357 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100358 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100359 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100360 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100361 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100362 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
363 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
364 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100365 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100366 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
367 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
368 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
369 store_temp_max, 0, 3),
370 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
371 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100372 /* Should be temp3_max_alarm, see temp1_alarm note */
373 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
374 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
375 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100376 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
377 store_temp_crit, 0, 3),
378 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
379 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100380 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
381 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
382 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100383 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100384 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200385};
386
Hans de Goede0bae6402011-03-09 20:57:10 +0100387/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100388 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
389 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100390 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100391 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100392static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100393 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
394 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
395 store_temp_crit, 0, 0),
396 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
397 store_temp_max, 0, 0),
398 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200399 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100400 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
401 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
402 store_temp_crit, 0, 1),
403 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
404 store_temp_max, 0, 1),
405 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
406 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200407 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100408 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
409 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
410 store_temp_crit, 0, 2),
411 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
412 store_temp_max, 0, 2),
413 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200414 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100415};
416
Hans de Goede0bae6402011-03-09 20:57:10 +0100417/* in attr for all models */
418static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
419 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
420 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
421 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
422 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
423 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
424 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
425 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
426 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
427 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
428};
429
430/* For models with in1 alarm capability */
431static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
432 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
433 0, 1),
434 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
435 0, 1),
436 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
437};
438
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100439/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100440static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100441 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100442 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
443 show_fan_full_speed,
444 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100445 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100446 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
447 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
448 store_pwm_enable, 0, 0),
449 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
450 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100451}, {
452 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
453 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
454 show_fan_full_speed,
455 store_fan_full_speed, 0, 1),
456 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100457 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
458 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
459 store_pwm_enable, 0, 1),
460 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
461 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100462}, {
463 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
464 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
465 show_fan_full_speed,
466 store_fan_full_speed, 0, 2),
467 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200468 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
469 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
470 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100471 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
472 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100473}, {
474 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
475 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
476 show_fan_full_speed,
477 store_fan_full_speed, 0, 3),
478 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
479 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
480 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
481 store_pwm_enable, 0, 3),
482 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
483 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
484} };
Hans de Goede498be962009-01-07 16:37:28 +0100485
Hans de Goede66344aa2009-12-09 20:35:59 +0100486/* Attr for models which can beep on Fan alarm */
487static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100488 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
489 store_fan_beep, 0, 0),
490 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
491 store_fan_beep, 0, 1),
492 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
493 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100494 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
495 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100496};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100497
Hans de Goede66344aa2009-12-09 20:35:59 +0100498/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
499 f71858fg / f71882fg / f71889fg */
500static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
501 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
502 show_pwm_auto_point_channel,
503 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100504 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
506 1, 0),
507 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 4, 0),
510 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
512 0, 0),
513 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 3, 0),
516 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp_hyst,
518 store_pwm_auto_point_temp_hyst,
519 0, 0),
520 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
521 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
522
Hans de Goede66344aa2009-12-09 20:35:59 +0100523 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
524 show_pwm_auto_point_channel,
525 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100526 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
528 1, 1),
529 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 4, 1),
532 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
534 0, 1),
535 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 3, 1),
538 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp_hyst,
540 store_pwm_auto_point_temp_hyst,
541 0, 1),
542 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
543 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100544
Hans de Goede66344aa2009-12-09 20:35:59 +0100545 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
546 show_pwm_auto_point_channel,
547 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100548 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
549 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
550 1, 2),
551 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
553 4, 2),
554 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
556 0, 2),
557 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
559 3, 2),
560 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_temp_hyst,
562 store_pwm_auto_point_temp_hyst,
563 0, 2),
564 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
565 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100566};
567
Hans de Goede66344aa2009-12-09 20:35:59 +0100568/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100569static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100570 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
571 show_pwm_auto_point_channel,
572 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100573 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
575 0, 0),
576 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
578 1, 0),
579 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
581 2, 0),
582 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
584 3, 0),
585 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
587 4, 0),
588 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
589 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
590 0, 0),
591 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
592 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
593 1, 0),
594 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
595 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
596 2, 0),
597 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
598 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
599 3, 0),
600 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
601 show_pwm_auto_point_temp_hyst,
602 store_pwm_auto_point_temp_hyst,
603 0, 0),
604 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
605 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
606 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
607 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
608 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
609 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100610}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100611 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_channel,
613 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100614 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
616 0, 1),
617 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
619 1, 1),
620 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
622 2, 1),
623 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
625 3, 1),
626 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
628 4, 1),
629 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
630 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
631 0, 1),
632 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
633 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
634 1, 1),
635 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
637 2, 1),
638 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
640 3, 1),
641 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
642 show_pwm_auto_point_temp_hyst,
643 store_pwm_auto_point_temp_hyst,
644 0, 1),
645 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
646 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
647 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
648 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
649 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
650 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100651}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100652 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
653 show_pwm_auto_point_channel,
654 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100655 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
657 0, 2),
658 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
659 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
660 1, 2),
661 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
662 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
663 2, 2),
664 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
665 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
666 3, 2),
667 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
668 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
669 4, 2),
670 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
671 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
672 0, 2),
673 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
674 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
675 1, 2),
676 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
678 2, 2),
679 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
681 3, 2),
682 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_temp_hyst,
684 store_pwm_auto_point_temp_hyst,
685 0, 2),
686 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
687 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
688 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
689 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
690 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
691 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100692}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100693 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_channel,
695 store_pwm_auto_point_channel, 0, 3),
696 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
698 0, 3),
699 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
701 1, 3),
702 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
704 2, 3),
705 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
707 3, 3),
708 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
710 4, 3),
711 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
712 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
713 0, 3),
714 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
715 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
716 1, 3),
717 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
718 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
719 2, 3),
720 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
721 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
722 3, 3),
723 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
724 show_pwm_auto_point_temp_hyst,
725 store_pwm_auto_point_temp_hyst,
726 0, 3),
727 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
728 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
729 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
730 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
731 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
732 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100733} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200734
Hans de Goede66344aa2009-12-09 20:35:59 +0100735/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100736static struct sensor_device_attribute_2 f8000_fan_attr[] = {
737 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100738};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100739
Hans de Goede66344aa2009-12-09 20:35:59 +0100740/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
741 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
742 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
743static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
744 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_channel,
746 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100747 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
749 0, 2),
750 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
752 1, 2),
753 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
755 2, 2),
756 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
758 3, 2),
759 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
761 4, 2),
762 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
764 0, 2),
765 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
766 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
767 1, 2),
768 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
770 2, 2),
771 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
773 3, 2),
774 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_temp_hyst,
776 store_pwm_auto_point_temp_hyst,
777 0, 2),
778 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
779 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
780 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
781 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
782 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
783 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
784
Hans de Goede66344aa2009-12-09 20:35:59 +0100785 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_channel,
787 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100788 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
790 0, 0),
791 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
793 1, 0),
794 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
796 2, 0),
797 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
799 3, 0),
800 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
802 4, 0),
803 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
804 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
805 0, 0),
806 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
807 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
808 1, 0),
809 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
811 2, 0),
812 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
814 3, 0),
815 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_temp_hyst,
817 store_pwm_auto_point_temp_hyst,
818 0, 0),
819 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
820 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
821 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
822 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
823 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
824 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
825
Hans de Goede66344aa2009-12-09 20:35:59 +0100826 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_channel,
828 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100829 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
831 0, 1),
832 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
834 1, 1),
835 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
837 2, 1),
838 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
840 3, 1),
841 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
843 4, 1),
844 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
845 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
846 0, 1),
847 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
848 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
849 1, 1),
850 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
851 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
852 2, 1),
853 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
854 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
855 3, 1),
856 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
857 show_pwm_auto_point_temp_hyst,
858 store_pwm_auto_point_temp_hyst,
859 0, 1),
860 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
861 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
862 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
863 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
864 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
865 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
866};
Hans de Goede45fb3662007-07-13 14:34:19 +0200867
868/* Super I/O functions */
869static inline int superio_inb(int base, int reg)
870{
871 outb(reg, base);
872 return inb(base + 1);
873}
874
875static int superio_inw(int base, int reg)
876{
877 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200878 val = superio_inb(base, reg) << 8;
879 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200880 return val;
881}
882
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400883static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200884{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400885 /* Don't step on other drivers' I/O space by accident */
886 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000887 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400888 return -EBUSY;
889 }
890
Hans de Goede45fb3662007-07-13 14:34:19 +0200891 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200892 outb(SIO_UNLOCK_KEY, base);
893 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400894
895 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200896}
897
Giel van Schijndel162bb592010-05-27 19:58:40 +0200898static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200899{
900 outb(SIO_REG_LDSEL, base);
901 outb(ld, base + 1);
902}
903
904static inline void superio_exit(int base)
905{
906 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400907 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200908}
909
Hans de Goede2f650632009-01-07 16:37:31 +0100910static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200911{
912 return reg ? (1500000 / reg) : 0;
913}
914
Hans de Goede2f650632009-01-07 16:37:31 +0100915static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100916{
917 return fan ? (1500000 / fan) : 0;
918}
919
Hans de Goede45fb3662007-07-13 14:34:19 +0200920static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
921{
922 u8 val;
923
924 outb(reg, data->addr + ADDR_REG_OFFSET);
925 val = inb(data->addr + DATA_REG_OFFSET);
926
927 return val;
928}
929
930static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
931{
932 u16 val;
933
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200934 val = f71882fg_read8(data, reg) << 8;
935 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200936
937 return val;
938}
939
940static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
941{
942 outb(reg, data->addr + ADDR_REG_OFFSET);
943 outb(val, data->addr + DATA_REG_OFFSET);
944}
945
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100946static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
947{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200948 f71882fg_write8(data, reg, val >> 8);
949 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100950}
951
Hans de Goede09475d32009-06-15 18:39:52 +0200952static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
953{
954 if (data->type == f71858fg)
955 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
956 else
957 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
958}
959
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100960static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200961{
962 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100963 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100964 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +0200965
966 mutex_lock(&data->update_lock);
967
968 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200969 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200970 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +0100971 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +0100972 data->in1_max =
973 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
974 data->in_beep =
975 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
976 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200977
978 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200979 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200980 data->temp_ovt[nr] = f71882fg_read8(data,
981 F71882FG_REG_TEMP_OVT(nr));
982 data->temp_high[nr] = f71882fg_read8(data,
983 F71882FG_REG_TEMP_HIGH(nr));
984 }
985
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100986 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100987 data->temp_hyst[0] = f71882fg_read8(data,
988 F71882FG_REG_TEMP_HYST(0));
989 data->temp_hyst[1] = f71882fg_read8(data,
990 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200991 }
992
Hans de Goede76698962009-12-09 20:36:01 +0100993 if (data->type == f71862fg || data->type == f71882fg ||
994 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200995 data->fan_beep = f71882fg_read8(data,
996 F71882FG_REG_FAN_BEEP);
997 data->temp_beep = f71882fg_read8(data,
998 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100999 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001000 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001001 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1002 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1003 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001004
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001005 data->pwm_enable = f71882fg_read8(data,
1006 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001007 data->pwm_auto_point_hyst[0] =
1008 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1009 data->pwm_auto_point_hyst[1] =
1010 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1011
Hans de Goede498be962009-01-07 16:37:28 +01001012 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001013 data->pwm_auto_point_mapping[nr] =
1014 f71882fg_read8(data,
1015 F71882FG_REG_POINT_MAPPING(nr));
1016
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001017 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001018 int point;
1019 for (point = 0; point < 5; point++) {
1020 data->pwm_auto_point_pwm[nr][point] =
1021 f71882fg_read8(data,
1022 F71882FG_REG_POINT_PWM
1023 (nr, point));
1024 }
1025 for (point = 0; point < 4; point++) {
1026 data->pwm_auto_point_temp[nr][point] =
1027 f71882fg_read8(data,
1028 F71882FG_REG_POINT_TEMP
1029 (nr, point));
1030 }
1031 } else {
1032 data->pwm_auto_point_pwm[nr][1] =
1033 f71882fg_read8(data,
1034 F71882FG_REG_POINT_PWM
1035 (nr, 1));
1036 data->pwm_auto_point_pwm[nr][4] =
1037 f71882fg_read8(data,
1038 F71882FG_REG_POINT_PWM
1039 (nr, 4));
1040 data->pwm_auto_point_temp[nr][0] =
1041 f71882fg_read8(data,
1042 F71882FG_REG_POINT_TEMP
1043 (nr, 0));
1044 data->pwm_auto_point_temp[nr][3] =
1045 f71882fg_read8(data,
1046 F71882FG_REG_POINT_TEMP
1047 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001048 }
1049 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001050 data->last_limits = jiffies;
1051 }
1052
1053 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001054 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001055 data->temp_status = f71882fg_read8(data,
1056 F71882FG_REG_TEMP_STATUS);
1057 data->temp_diode_open = f71882fg_read8(data,
1058 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001059 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1060 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001061
1062 data->fan_status = f71882fg_read8(data,
1063 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001064 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001065 data->fan[nr] = f71882fg_read16(data,
1066 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001067 data->fan_target[nr] =
1068 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1069 data->fan_full_speed[nr] =
1070 f71882fg_read16(data,
1071 F71882FG_REG_FAN_FULL_SPEED(nr));
1072 data->pwm[nr] =
1073 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1074 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001075 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1076 if (data->type == f8000)
1077 data->fan[3] = f71882fg_read16(data,
1078 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001079
1080 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001081 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001082 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001083 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1084 if (f71882fg_has_in[data->type][nr])
1085 data->in[nr] = f71882fg_read8(data,
1086 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001087
1088 data->last_updated = jiffies;
1089 data->valid = 1;
1090 }
1091
1092 mutex_unlock(&data->update_lock);
1093
1094 return data;
1095}
1096
1097/* Sysfs Interface */
1098static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1099 char *buf)
1100{
1101 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001102 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001103 int speed = fan_from_reg(data->fan[nr]);
1104
1105 if (speed == FAN_MIN_DETECT)
1106 speed = 0;
1107
1108 return sprintf(buf, "%d\n", speed);
1109}
1110
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001111static ssize_t show_fan_full_speed(struct device *dev,
1112 struct device_attribute *devattr, char *buf)
1113{
1114 struct f71882fg_data *data = f71882fg_update_device(dev);
1115 int nr = to_sensor_dev_attr_2(devattr)->index;
1116 int speed = fan_from_reg(data->fan_full_speed[nr]);
1117 return sprintf(buf, "%d\n", speed);
1118}
1119
1120static ssize_t store_fan_full_speed(struct device *dev,
1121 struct device_attribute *devattr,
1122 const char *buf, size_t count)
1123{
1124 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001125 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1126 long val;
1127
1128 err = strict_strtol(buf, 10, &val);
1129 if (err)
1130 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001131
1132 val = SENSORS_LIMIT(val, 23, 1500000);
1133 val = fan_to_reg(val);
1134
1135 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001136 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1137 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001138 mutex_unlock(&data->update_lock);
1139
1140 return count;
1141}
1142
Hans de Goede45fb3662007-07-13 14:34:19 +02001143static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1144 *devattr, char *buf)
1145{
1146 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001147 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001148
1149 if (data->fan_beep & (1 << nr))
1150 return sprintf(buf, "1\n");
1151 else
1152 return sprintf(buf, "0\n");
1153}
1154
1155static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1156 *devattr, const char *buf, size_t count)
1157{
1158 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001159 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1160 unsigned long val;
1161
1162 err = strict_strtoul(buf, 10, &val);
1163 if (err)
1164 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001165
1166 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001167 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001168 if (val)
1169 data->fan_beep |= 1 << nr;
1170 else
1171 data->fan_beep &= ~(1 << nr);
1172
1173 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1174 mutex_unlock(&data->update_lock);
1175
1176 return count;
1177}
1178
1179static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1180 *devattr, char *buf)
1181{
1182 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001183 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001184
1185 if (data->fan_status & (1 << nr))
1186 return sprintf(buf, "1\n");
1187 else
1188 return sprintf(buf, "0\n");
1189}
1190
1191static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1192 char *buf)
1193{
1194 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001195 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001196
1197 return sprintf(buf, "%d\n", data->in[nr] * 8);
1198}
1199
1200static ssize_t show_in_max(struct device *dev, struct device_attribute
1201 *devattr, char *buf)
1202{
1203 struct f71882fg_data *data = f71882fg_update_device(dev);
1204
1205 return sprintf(buf, "%d\n", data->in1_max * 8);
1206}
1207
1208static ssize_t store_in_max(struct device *dev, struct device_attribute
1209 *devattr, const char *buf, size_t count)
1210{
1211 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001212 int err;
1213 long val;
1214
1215 err = strict_strtol(buf, 10, &val);
1216 if (err)
1217 return err;
1218
1219 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001220 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001221
1222 mutex_lock(&data->update_lock);
1223 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1224 data->in1_max = val;
1225 mutex_unlock(&data->update_lock);
1226
1227 return count;
1228}
1229
1230static ssize_t show_in_beep(struct device *dev, struct device_attribute
1231 *devattr, char *buf)
1232{
1233 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001234 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001235
1236 if (data->in_beep & (1 << nr))
1237 return sprintf(buf, "1\n");
1238 else
1239 return sprintf(buf, "0\n");
1240}
1241
1242static ssize_t store_in_beep(struct device *dev, struct device_attribute
1243 *devattr, const char *buf, size_t count)
1244{
1245 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001246 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1247 unsigned long val;
1248
1249 err = strict_strtoul(buf, 10, &val);
1250 if (err)
1251 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001252
1253 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001254 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001255 if (val)
1256 data->in_beep |= 1 << nr;
1257 else
1258 data->in_beep &= ~(1 << nr);
1259
1260 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1261 mutex_unlock(&data->update_lock);
1262
1263 return count;
1264}
1265
1266static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1267 *devattr, char *buf)
1268{
1269 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001270 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001271
1272 if (data->in_status & (1 << nr))
1273 return sprintf(buf, "1\n");
1274 else
1275 return sprintf(buf, "0\n");
1276}
1277
1278static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1279 char *buf)
1280{
1281 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001282 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001283 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001284
Hans de Goede09475d32009-06-15 18:39:52 +02001285 if (data->type == f71858fg) {
1286 /* TEMP_TABLE_SEL 1 or 3 ? */
1287 if (data->temp_config & 1) {
1288 sign = data->temp[nr] & 0x0001;
1289 temp = (data->temp[nr] >> 5) & 0x7ff;
1290 } else {
1291 sign = data->temp[nr] & 0x8000;
1292 temp = (data->temp[nr] >> 5) & 0x3ff;
1293 }
1294 temp *= 125;
1295 if (sign)
1296 temp -= 128000;
1297 } else
1298 temp = data->temp[nr] * 1000;
1299
1300 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001301}
1302
1303static ssize_t show_temp_max(struct device *dev, struct device_attribute
1304 *devattr, char *buf)
1305{
1306 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001307 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001308
1309 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1310}
1311
1312static ssize_t store_temp_max(struct device *dev, struct device_attribute
1313 *devattr, const char *buf, size_t count)
1314{
1315 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001316 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1317 long val;
1318
1319 err = strict_strtol(buf, 10, &val);
1320 if (err)
1321 return err;
1322
1323 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001324 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001325
1326 mutex_lock(&data->update_lock);
1327 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1328 data->temp_high[nr] = val;
1329 mutex_unlock(&data->update_lock);
1330
1331 return count;
1332}
1333
1334static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1335 *devattr, char *buf)
1336{
1337 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001338 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001339 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001340
Hans de Goedece0bfa52009-01-07 16:37:28 +01001341 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001342 if (nr & 1)
1343 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1344 else
1345 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1346 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001347 mutex_unlock(&data->update_lock);
1348
1349 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001350}
1351
1352static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1353 *devattr, const char *buf, size_t count)
1354{
1355 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001356 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001357 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001358 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001359 long val;
1360
1361 err = strict_strtol(buf, 10, &val);
1362 if (err)
1363 return err;
1364
1365 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001366
1367 mutex_lock(&data->update_lock);
1368
1369 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001370 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1371 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1372 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001373 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001374
1375 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001376 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1377 if (nr & 1)
1378 reg = (reg & 0x0f) | (val << 4);
1379 else
1380 reg = (reg & 0xf0) | val;
1381 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1382 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001383
Hans de Goede45fb3662007-07-13 14:34:19 +02001384 mutex_unlock(&data->update_lock);
1385 return ret;
1386}
1387
1388static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1389 *devattr, char *buf)
1390{
1391 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001392 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001393
1394 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1395}
1396
1397static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1398 *devattr, const char *buf, size_t count)
1399{
1400 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001401 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1402 long val;
1403
1404 err = strict_strtol(buf, 10, &val);
1405 if (err)
1406 return err;
1407
1408 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001409 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001410
1411 mutex_lock(&data->update_lock);
1412 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1413 data->temp_ovt[nr] = val;
1414 mutex_unlock(&data->update_lock);
1415
1416 return count;
1417}
1418
1419static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1420 *devattr, char *buf)
1421{
1422 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001423 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001424 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001425
Hans de Goedece0bfa52009-01-07 16:37:28 +01001426 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001427 if (nr & 1)
1428 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1429 else
1430 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1431 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001432 mutex_unlock(&data->update_lock);
1433
1434 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001435}
1436
1437static ssize_t show_temp_type(struct device *dev, struct device_attribute
1438 *devattr, char *buf)
1439{
1440 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001441 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001442
1443 return sprintf(buf, "%d\n", data->temp_type[nr]);
1444}
1445
1446static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1447 *devattr, char *buf)
1448{
1449 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001450 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001451
Hans de Goede7567a042009-01-07 16:37:28 +01001452 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001453 return sprintf(buf, "1\n");
1454 else
1455 return sprintf(buf, "0\n");
1456}
1457
1458static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1459 *devattr, const char *buf, size_t count)
1460{
1461 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001462 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1463 unsigned long val;
1464
1465 err = strict_strtoul(buf, 10, &val);
1466 if (err)
1467 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001468
1469 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001470 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001471 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001472 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001473 else
Hans de Goede7567a042009-01-07 16:37:28 +01001474 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001475
1476 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1477 mutex_unlock(&data->update_lock);
1478
1479 return count;
1480}
1481
1482static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1483 *devattr, char *buf)
1484{
1485 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001486 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001487
Hans de Goede7567a042009-01-07 16:37:28 +01001488 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001489 return sprintf(buf, "1\n");
1490 else
1491 return sprintf(buf, "0\n");
1492}
1493
1494static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1495 *devattr, char *buf)
1496{
1497 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001498 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001499
Hans de Goede7567a042009-01-07 16:37:28 +01001500 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001501 return sprintf(buf, "1\n");
1502 else
1503 return sprintf(buf, "0\n");
1504}
1505
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001506static ssize_t show_pwm(struct device *dev,
1507 struct device_attribute *devattr, char *buf)
1508{
1509 struct f71882fg_data *data = f71882fg_update_device(dev);
1510 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001511 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001512 if (data->pwm_enable & (1 << (2 * nr)))
1513 /* PWM mode */
1514 val = data->pwm[nr];
1515 else {
1516 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001517 val = 255 * fan_from_reg(data->fan_target[nr])
1518 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001519 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001520 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001521 return sprintf(buf, "%d\n", val);
1522}
1523
1524static ssize_t store_pwm(struct device *dev,
1525 struct device_attribute *devattr, const char *buf,
1526 size_t count)
1527{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001528 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001529 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1530 long val;
1531
1532 err = strict_strtol(buf, 10, &val);
1533 if (err)
1534 return err;
1535
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001536 val = SENSORS_LIMIT(val, 0, 255);
1537
1538 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001539 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001540 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1541 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1542 count = -EROFS;
1543 goto leave;
1544 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001545 if (data->pwm_enable & (1 << (2 * nr))) {
1546 /* PWM mode */
1547 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1548 data->pwm[nr] = val;
1549 } else {
1550 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001551 int target, full_speed;
1552 full_speed = f71882fg_read16(data,
1553 F71882FG_REG_FAN_FULL_SPEED(nr));
1554 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1555 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1556 data->fan_target[nr] = target;
1557 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001558 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001559leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001560 mutex_unlock(&data->update_lock);
1561
1562 return count;
1563}
1564
1565static ssize_t show_pwm_enable(struct device *dev,
1566 struct device_attribute *devattr, char *buf)
1567{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001568 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001569 struct f71882fg_data *data = f71882fg_update_device(dev);
1570 int nr = to_sensor_dev_attr_2(devattr)->index;
1571
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001572 switch ((data->pwm_enable >> 2 * nr) & 3) {
1573 case 0:
1574 case 1:
1575 result = 2; /* Normal auto mode */
1576 break;
1577 case 2:
1578 result = 1; /* Manual mode */
1579 break;
1580 case 3:
1581 if (data->type == f8000)
1582 result = 3; /* Thermostat mode */
1583 else
1584 result = 1; /* Manual mode */
1585 break;
1586 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001587
1588 return sprintf(buf, "%d\n", result);
1589}
1590
1591static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1592 *devattr, const char *buf, size_t count)
1593{
1594 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001595 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1596 long val;
1597
1598 err = strict_strtol(buf, 10, &val);
1599 if (err)
1600 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001601
Hans de Goede3fc78382009-06-15 18:39:50 +02001602 /* Special case for F8000 pwm channel 3 which only does auto mode */
1603 if (data->type == f8000 && nr == 2 && val != 2)
1604 return -EINVAL;
1605
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001606 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001607 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001608 /* Special case for F8000 auto PWM mode / Thermostat mode */
1609 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1610 switch (val) {
1611 case 2:
1612 data->pwm_enable &= ~(2 << (2 * nr));
1613 break; /* Normal auto mode */
1614 case 3:
1615 data->pwm_enable |= 2 << (2 * nr);
1616 break; /* Thermostat mode */
1617 default:
1618 count = -EINVAL;
1619 goto leave;
1620 }
1621 } else {
1622 switch (val) {
1623 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001624 /* The f71858fg does not support manual RPM mode */
1625 if (data->type == f71858fg &&
1626 ((data->pwm_enable >> (2 * nr)) & 1)) {
1627 count = -EINVAL;
1628 goto leave;
1629 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001630 data->pwm_enable |= 2 << (2 * nr);
1631 break; /* Manual */
1632 case 2:
1633 data->pwm_enable &= ~(2 << (2 * nr));
1634 break; /* Normal auto mode */
1635 default:
1636 count = -EINVAL;
1637 goto leave;
1638 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001639 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001640 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001641leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001642 mutex_unlock(&data->update_lock);
1643
1644 return count;
1645}
1646
1647static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1648 struct device_attribute *devattr,
1649 char *buf)
1650{
1651 int result;
1652 struct f71882fg_data *data = f71882fg_update_device(dev);
1653 int pwm = to_sensor_dev_attr_2(devattr)->index;
1654 int point = to_sensor_dev_attr_2(devattr)->nr;
1655
Hans de Goedece0bfa52009-01-07 16:37:28 +01001656 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001657 if (data->pwm_enable & (1 << (2 * pwm))) {
1658 /* PWM mode */
1659 result = data->pwm_auto_point_pwm[pwm][point];
1660 } else {
1661 /* RPM mode */
1662 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1663 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001664 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001665
1666 return sprintf(buf, "%d\n", result);
1667}
1668
1669static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1670 struct device_attribute *devattr,
1671 const char *buf, size_t count)
1672{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001673 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001674 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001675 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001676 long val;
1677
1678 err = strict_strtol(buf, 10, &val);
1679 if (err)
1680 return err;
1681
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001682 val = SENSORS_LIMIT(val, 0, 255);
1683
1684 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001685 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001686 if (data->pwm_enable & (1 << (2 * pwm))) {
1687 /* PWM mode */
1688 } else {
1689 /* RPM mode */
1690 if (val < 29) /* Prevent negative numbers */
1691 val = 255;
1692 else
1693 val = (255 - val) * 32 / val;
1694 }
1695 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1696 data->pwm_auto_point_pwm[pwm][point] = val;
1697 mutex_unlock(&data->update_lock);
1698
1699 return count;
1700}
1701
1702static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1703 struct device_attribute *devattr,
1704 char *buf)
1705{
1706 int result = 0;
1707 struct f71882fg_data *data = f71882fg_update_device(dev);
1708 int nr = to_sensor_dev_attr_2(devattr)->index;
1709 int point = to_sensor_dev_attr_2(devattr)->nr;
1710
1711 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001712 if (nr & 1)
1713 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1714 else
1715 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001716 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1717 mutex_unlock(&data->update_lock);
1718
1719 return sprintf(buf, "%d\n", result);
1720}
1721
1722static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1723 struct device_attribute *devattr,
1724 const char *buf, size_t count)
1725{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001726 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001727 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001728 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001729 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001730 long val;
1731
1732 err = strict_strtol(buf, 10, &val);
1733 if (err)
1734 return err;
1735
1736 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001737
1738 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001739 data->pwm_auto_point_temp[nr][point] =
1740 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001741 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1742 data->pwm_auto_point_temp[nr][point]);
1743 val = data->pwm_auto_point_temp[nr][point] - val;
1744
Hans de Goedebc274902009-01-07 16:37:29 +01001745 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1746 if (nr & 1)
1747 reg = (reg & 0x0f) | (val << 4);
1748 else
1749 reg = (reg & 0xf0) | val;
1750
1751 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1752 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001753 mutex_unlock(&data->update_lock);
1754
1755 return count;
1756}
1757
1758static ssize_t show_pwm_interpolate(struct device *dev,
1759 struct device_attribute *devattr, char *buf)
1760{
1761 int result;
1762 struct f71882fg_data *data = f71882fg_update_device(dev);
1763 int nr = to_sensor_dev_attr_2(devattr)->index;
1764
1765 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1766
1767 return sprintf(buf, "%d\n", result);
1768}
1769
1770static ssize_t store_pwm_interpolate(struct device *dev,
1771 struct device_attribute *devattr,
1772 const char *buf, size_t count)
1773{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001774 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001775 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1776 unsigned long val;
1777
1778 err = strict_strtoul(buf, 10, &val);
1779 if (err)
1780 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001781
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001782 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001783 data->pwm_auto_point_mapping[nr] =
1784 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001785 if (val)
1786 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1787 else
1788 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1789 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1790 data->pwm_auto_point_mapping[nr] = val;
1791 mutex_unlock(&data->update_lock);
1792
1793 return count;
1794}
1795
1796static ssize_t show_pwm_auto_point_channel(struct device *dev,
1797 struct device_attribute *devattr,
1798 char *buf)
1799{
1800 int result;
1801 struct f71882fg_data *data = f71882fg_update_device(dev);
1802 int nr = to_sensor_dev_attr_2(devattr)->index;
1803
Hans de Goede09475d32009-06-15 18:39:52 +02001804 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1805 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001806
1807 return sprintf(buf, "%d\n", result);
1808}
1809
1810static ssize_t store_pwm_auto_point_channel(struct device *dev,
1811 struct device_attribute *devattr,
1812 const char *buf, size_t count)
1813{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001814 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001815 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1816 long val;
1817
1818 err = strict_strtol(buf, 10, &val);
1819 if (err)
1820 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001821
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001822 switch (val) {
1823 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001824 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001825 break;
1826 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001827 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001828 break;
1829 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001830 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001831 break;
1832 default:
1833 return -EINVAL;
1834 }
Hans de Goede09475d32009-06-15 18:39:52 +02001835 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001836 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001837 data->pwm_auto_point_mapping[nr] =
1838 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001839 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1840 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1841 data->pwm_auto_point_mapping[nr] = val;
1842 mutex_unlock(&data->update_lock);
1843
1844 return count;
1845}
1846
1847static ssize_t show_pwm_auto_point_temp(struct device *dev,
1848 struct device_attribute *devattr,
1849 char *buf)
1850{
1851 int result;
1852 struct f71882fg_data *data = f71882fg_update_device(dev);
1853 int pwm = to_sensor_dev_attr_2(devattr)->index;
1854 int point = to_sensor_dev_attr_2(devattr)->nr;
1855
1856 result = data->pwm_auto_point_temp[pwm][point];
1857 return sprintf(buf, "%d\n", 1000 * result);
1858}
1859
1860static ssize_t store_pwm_auto_point_temp(struct device *dev,
1861 struct device_attribute *devattr,
1862 const char *buf, size_t count)
1863{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001864 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001865 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001866 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001867 long val;
1868
1869 err = strict_strtol(buf, 10, &val);
1870 if (err)
1871 return err;
1872
1873 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001874
Hans de Goede98f7ba12011-03-09 20:57:09 +01001875 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001876 val = SENSORS_LIMIT(val, -128, 127);
1877 else
1878 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001879
1880 mutex_lock(&data->update_lock);
1881 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1882 data->pwm_auto_point_temp[pwm][point] = val;
1883 mutex_unlock(&data->update_lock);
1884
1885 return count;
1886}
1887
Hans de Goede45fb3662007-07-13 14:34:19 +02001888static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1889 char *buf)
1890{
Hans de Goede498be962009-01-07 16:37:28 +01001891 struct f71882fg_data *data = dev_get_drvdata(dev);
1892 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001893}
1894
Hans de Goedec13548c2009-01-07 16:37:27 +01001895static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1896 struct sensor_device_attribute_2 *attr, int count)
1897{
1898 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001899
Hans de Goedec13548c2009-01-07 16:37:27 +01001900 for (i = 0; i < count; i++) {
1901 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1902 if (err)
1903 return err;
1904 }
1905 return 0;
1906}
1907
Hans de Goedefc16c562009-12-09 20:36:01 +01001908static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1909 struct sensor_device_attribute_2 *attr, int count)
1910{
1911 int i;
1912
1913 for (i = 0; i < count; i++)
1914 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1915}
1916
Hans de Goedec13548c2009-01-07 16:37:27 +01001917static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001918{
1919 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001920 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001921 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01001922 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001923
Hans de Goedec13548c2009-01-07 16:37:27 +01001924 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1925 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001926 return -ENOMEM;
1927
1928 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001929 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001930 data->temp_start =
1931 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001932 mutex_init(&data->update_lock);
1933 platform_set_drvdata(pdev, data);
1934
Hans de Goede3cc74752009-01-07 16:37:28 +01001935 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001936 if (start_reg & 0x04) {
1937 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1938 err = -ENODEV;
1939 goto exit_free;
1940 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001941 if (!(start_reg & 0x03)) {
1942 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1943 err = -ENODEV;
1944 goto exit_free;
1945 }
1946
Hans de Goede45fb3662007-07-13 14:34:19 +02001947 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001948 err = device_create_file(&pdev->dev, &dev_attr_name);
1949 if (err)
1950 goto exit_unregister_sysfs;
1951
Hans de Goedec13548c2009-01-07 16:37:27 +01001952 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001953 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001954 case f71858fg:
1955 data->temp_config =
1956 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1957 if (data->temp_config & 0x10)
1958 /* The f71858fg temperature alarms behave as
1959 the f8000 alarms in this mode */
1960 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001961 f8000_temp_attr,
1962 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001963 else
1964 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001965 f71858fg_temp_attr,
1966 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001967 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01001968 case f8000:
1969 err = f71882fg_create_sysfs_files(pdev,
1970 f8000_temp_attr,
1971 ARRAY_SIZE(f8000_temp_attr));
1972 break;
1973 default:
1974 err = f71882fg_create_sysfs_files(pdev,
1975 fxxxx_temp_attr,
1976 ARRAY_SIZE(fxxxx_temp_attr));
1977 }
1978 if (err)
1979 goto exit_unregister_sysfs;
1980
1981 for (i = 0; i < F71882FG_MAX_INS; i++) {
1982 if (f71882fg_has_in[data->type][i]) {
1983 err = device_create_file(&pdev->dev,
1984 &fxxxx_in_attr[i].dev_attr);
1985 if (err)
1986 goto exit_unregister_sysfs;
1987 }
1988 }
1989 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001990 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001991 fxxxx_in1_alarm_attr,
1992 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001993 if (err)
1994 goto exit_unregister_sysfs;
1995 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001996 }
1997
Hans de Goede45fb3662007-07-13 14:34:19 +02001998 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01001999 switch (data->type) {
2000 case f71889fg:
2001 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2002 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2003 data->auto_point_temp_signed = 1;
2004 break;
2005 default:
2006 break;
2007 }
2008
Hans de Goede996cadb2009-06-15 18:39:51 +02002009 data->pwm_enable =
2010 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2011
2012 /* Sanity check the pwm settings */
2013 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002014 case f71858fg:
2015 err = 0;
2016 for (i = 0; i < nr_fans; i++)
2017 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2018 err = 1;
2019 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002020 case f71862fg:
2021 err = (data->pwm_enable & 0x15) != 0x15;
2022 break;
2023 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002024 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002025 err = 0;
2026 break;
2027 case f8000:
2028 err = data->pwm_enable & 0x20;
2029 break;
2030 }
2031 if (err) {
2032 dev_err(&pdev->dev,
2033 "Invalid (reserved) pwm settings: 0x%02x\n",
2034 (unsigned int)data->pwm_enable);
2035 err = -ENODEV;
2036 goto exit_unregister_sysfs;
2037 }
2038
Hans de Goedeb69b0392009-12-09 20:36:00 +01002039 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2040 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002041 if (err)
2042 goto exit_unregister_sysfs;
2043
Hans de Goede76698962009-12-09 20:36:01 +01002044 if (data->type == f71862fg || data->type == f71882fg ||
2045 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002046 err = f71882fg_create_sysfs_files(pdev,
2047 fxxxx_fan_beep_attr, nr_fans);
2048 if (err)
2049 goto exit_unregister_sysfs;
2050 }
2051
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002052 switch (data->type) {
2053 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002054 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002055 f71862fg_auto_pwm_attr,
2056 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002057 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002058 case f8000:
2059 err = f71882fg_create_sysfs_files(pdev,
2060 f8000_fan_attr,
2061 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002062 if (err)
2063 goto exit_unregister_sysfs;
2064 err = f71882fg_create_sysfs_files(pdev,
2065 f8000_auto_pwm_attr,
2066 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002067 break;
Hans de Goede76698962009-12-09 20:36:01 +01002068 case f71889fg:
2069 for (i = 0; i < nr_fans; i++) {
2070 data->pwm_auto_point_mapping[i] =
2071 f71882fg_read8(data,
2072 F71882FG_REG_POINT_MAPPING(i));
2073 if (data->pwm_auto_point_mapping[i] & 0x80)
2074 break;
2075 }
2076 if (i != nr_fans) {
2077 dev_warn(&pdev->dev,
2078 "Auto pwm controlled by raw digital "
2079 "data, disabling pwm auto_point "
2080 "sysfs attributes\n");
2081 break;
2082 }
2083 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002084 default: /* f71858fg / f71882fg */
2085 err = f71882fg_create_sysfs_files(pdev,
2086 &fxxxx_auto_pwm_attr[0][0],
2087 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002088 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002089 if (err)
2090 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002091
2092 for (i = 0; i < nr_fans; i++)
2093 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2094 (data->pwm_enable & (1 << 2 * i)) ?
2095 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002096 }
2097
Tony Jones1beeffe2007-08-20 13:46:20 -07002098 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2099 if (IS_ERR(data->hwmon_dev)) {
2100 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002101 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002102 goto exit_unregister_sysfs;
2103 }
2104
2105 return 0;
2106
2107exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002108 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002109 return err; /* f71882fg_remove() also frees our data */
2110exit_free:
2111 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002112 return err;
2113}
2114
Hans de Goedec13548c2009-01-07 16:37:27 +01002115static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002116{
Hans de Goede45fb3662007-07-13 14:34:19 +02002117 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002118 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002119 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002120
Hans de Goedec13548c2009-01-07 16:37:27 +01002121 if (data->hwmon_dev)
2122 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002123
Hans de Goedec13548c2009-01-07 16:37:27 +01002124 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002125
Hans de Goedefc16c562009-12-09 20:36:01 +01002126 if (start_reg & 0x01) {
2127 switch (data->type) {
2128 case f71858fg:
2129 if (data->temp_config & 0x10)
2130 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002131 f8000_temp_attr,
2132 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002133 else
2134 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002135 f71858fg_temp_attr,
2136 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002137 break;
2138 case f8000:
2139 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002140 f8000_temp_attr,
2141 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002142 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002143 default:
2144 f71882fg_remove_sysfs_files(pdev,
2145 fxxxx_temp_attr,
2146 ARRAY_SIZE(fxxxx_temp_attr));
2147 }
2148 for (i = 0; i < F71882FG_MAX_INS; i++) {
2149 if (f71882fg_has_in[data->type][i]) {
2150 device_remove_file(&pdev->dev,
2151 &fxxxx_in_attr[i].dev_attr);
2152 }
2153 }
2154 if (f71882fg_has_in1_alarm[data->type]) {
2155 f71882fg_remove_sysfs_files(pdev,
2156 fxxxx_in1_alarm_attr,
2157 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002158 }
2159 }
Hans de Goede498be962009-01-07 16:37:28 +01002160
Hans de Goedefc16c562009-12-09 20:36:01 +01002161 if (start_reg & 0x02) {
2162 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2163 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002164
Hans de Goede76698962009-12-09 20:36:01 +01002165 if (data->type == f71862fg || data->type == f71882fg ||
2166 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002167 f71882fg_remove_sysfs_files(pdev,
2168 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002169
Hans de Goedefc16c562009-12-09 20:36:01 +01002170 switch (data->type) {
2171 case f71862fg:
2172 f71882fg_remove_sysfs_files(pdev,
2173 f71862fg_auto_pwm_attr,
2174 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2175 break;
2176 case f8000:
2177 f71882fg_remove_sysfs_files(pdev,
2178 f8000_fan_attr,
2179 ARRAY_SIZE(f8000_fan_attr));
2180 f71882fg_remove_sysfs_files(pdev,
2181 f8000_auto_pwm_attr,
2182 ARRAY_SIZE(f8000_auto_pwm_attr));
2183 break;
2184 default: /* f71858fg / f71882fg / f71889fg */
2185 f71882fg_remove_sysfs_files(pdev,
2186 &fxxxx_auto_pwm_attr[0][0],
2187 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2188 }
2189 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002190
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002191 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002192 kfree(data);
2193
2194 return 0;
2195}
2196
Hans de Goede498be962009-01-07 16:37:28 +01002197static int __init f71882fg_find(int sioaddr, unsigned short *address,
2198 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002199{
Hans de Goede45fb3662007-07-13 14:34:19 +02002200 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002201 int err = superio_enter(sioaddr);
2202 if (err)
2203 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002204
2205 devid = superio_inw(sioaddr, SIO_REG_MANID);
2206 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002207 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002208 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002209 goto exit;
2210 }
2211
Jean Delvare67b671b2007-12-06 23:13:42 +01002212 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002213 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002214 case SIO_F71858_ID:
2215 sio_data->type = f71858fg;
2216 break;
Hans de Goede498be962009-01-07 16:37:28 +01002217 case SIO_F71862_ID:
2218 sio_data->type = f71862fg;
2219 break;
2220 case SIO_F71882_ID:
2221 sio_data->type = f71882fg;
2222 break;
Hans de Goede76698962009-12-09 20:36:01 +01002223 case SIO_F71889_ID:
2224 sio_data->type = f71889fg;
2225 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002226 case SIO_F8000_ID:
2227 sio_data->type = f8000;
2228 break;
Hans de Goede498be962009-01-07 16:37:28 +01002229 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002230 pr_info("Unsupported Fintek device: %04x\n",
2231 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002232 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002233 goto exit;
2234 }
2235
Hans de Goede09475d32009-06-15 18:39:52 +02002236 if (sio_data->type == f71858fg)
2237 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2238 else
2239 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2240
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002241 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002242 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002243 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002244 goto exit;
2245 }
2246
2247 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002248 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002249 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002250 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002251 goto exit;
2252 }
2253 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2254
Hans de Goede45fb3662007-07-13 14:34:19 +02002255 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002256 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002257 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002258 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2259exit:
2260 superio_exit(sioaddr);
2261 return err;
2262}
2263
Hans de Goede498be962009-01-07 16:37:28 +01002264static int __init f71882fg_device_add(unsigned short address,
2265 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002266{
2267 struct resource res = {
2268 .start = address,
2269 .end = address + REGION_LENGTH - 1,
2270 .flags = IORESOURCE_IO,
2271 };
2272 int err;
2273
2274 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002275 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002276 return -ENOMEM;
2277
2278 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002279 err = acpi_check_resource_conflict(&res);
2280 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002281 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002282
Hans de Goede45fb3662007-07-13 14:34:19 +02002283 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002284 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002285 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002286 goto exit_device_put;
2287 }
2288
Hans de Goede498be962009-01-07 16:37:28 +01002289 err = platform_device_add_data(f71882fg_pdev, sio_data,
2290 sizeof(struct f71882fg_sio_data));
2291 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002292 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002293 goto exit_device_put;
2294 }
2295
Hans de Goede45fb3662007-07-13 14:34:19 +02002296 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002297 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002298 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002299 goto exit_device_put;
2300 }
2301
2302 return 0;
2303
2304exit_device_put:
2305 platform_device_put(f71882fg_pdev);
2306
2307 return err;
2308}
2309
2310static int __init f71882fg_init(void)
2311{
2312 int err = -ENODEV;
2313 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002314 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002315
Hans de Goede498be962009-01-07 16:37:28 +01002316 memset(&sio_data, 0, sizeof(sio_data));
2317
2318 if (f71882fg_find(0x2e, &address, &sio_data) &&
2319 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002320 goto exit;
2321
Hans de Goedec13548c2009-01-07 16:37:27 +01002322 err = platform_driver_register(&f71882fg_driver);
2323 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002324 goto exit;
2325
Hans de Goede498be962009-01-07 16:37:28 +01002326 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002327 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002328 goto exit_driver;
2329
2330 return 0;
2331
2332exit_driver:
2333 platform_driver_unregister(&f71882fg_driver);
2334exit:
2335 return err;
2336}
2337
2338static void __exit f71882fg_exit(void)
2339{
2340 platform_device_unregister(f71882fg_pdev);
2341 platform_driver_unregister(&f71882fg_driver);
2342}
2343
2344MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002345MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002346MODULE_LICENSE("GPL");
2347
2348module_init(f71882fg_init);
2349module_exit(f71882fg_exit);