blob: bf939e1aa73f500189f9926207f4c29b7600f147 [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 */
Hans de Goede60d2b372011-03-09 20:57:11 +0100328static struct sensor_device_attribute_2 fxxxx_temp_attr[3][11] = { {
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),
Hans de Goede60d2b372011-03-09 20:57:11 +0100349}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100350 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
351 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100354 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100355 /* Should be temp2_max_alarm, see temp1_alarm note */
356 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
357 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
358 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100359 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100360 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100361 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100362 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100363 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
364 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
365 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100366 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100368}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100369 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
370 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
371 store_temp_max, 0, 3),
372 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
373 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100374 /* Should be temp3_max_alarm, see temp1_alarm note */
375 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
376 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
377 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100378 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
379 store_temp_crit, 0, 3),
380 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
381 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100382 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
383 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
384 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100385 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100386 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100387} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200388
Hans de Goede0bae6402011-03-09 20:57:10 +0100389/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100390 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
391 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100392 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100393 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100394static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100395 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
396 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
397 store_temp_crit, 0, 0),
398 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
399 store_temp_max, 0, 0),
400 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200401 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100402 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
403 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
404 store_temp_crit, 0, 1),
405 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
406 store_temp_max, 0, 1),
407 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
408 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200409 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100410 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
411 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
412 store_temp_crit, 0, 2),
413 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
414 store_temp_max, 0, 2),
415 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200416 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100417};
418
Hans de Goede0bae6402011-03-09 20:57:10 +0100419/* in attr for all models */
420static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
421 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
422 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
423 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
424 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
425 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
426 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
427 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
428 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
429 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
430};
431
432/* For models with in1 alarm capability */
433static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
434 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
435 0, 1),
436 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
437 0, 1),
438 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
439};
440
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100441/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100442static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100443 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100444 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
445 show_fan_full_speed,
446 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100447 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100448 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
449 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
450 store_pwm_enable, 0, 0),
451 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
452 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100453}, {
454 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
455 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
456 show_fan_full_speed,
457 store_fan_full_speed, 0, 1),
458 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100459 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
460 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
461 store_pwm_enable, 0, 1),
462 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
463 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100464}, {
465 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
466 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
467 show_fan_full_speed,
468 store_fan_full_speed, 0, 2),
469 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200470 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
471 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
472 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100473 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
474 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100475}, {
476 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
477 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
478 show_fan_full_speed,
479 store_fan_full_speed, 0, 3),
480 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
481 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
482 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
483 store_pwm_enable, 0, 3),
484 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
485 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
486} };
Hans de Goede498be962009-01-07 16:37:28 +0100487
Hans de Goede66344aa2009-12-09 20:35:59 +0100488/* Attr for models which can beep on Fan alarm */
489static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100490 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
491 store_fan_beep, 0, 0),
492 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
493 store_fan_beep, 0, 1),
494 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
495 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100496 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
497 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100498};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100499
Hans de Goede66344aa2009-12-09 20:35:59 +0100500/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
501 f71858fg / f71882fg / f71889fg */
502static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
503 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
504 show_pwm_auto_point_channel,
505 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100506 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
507 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
508 1, 0),
509 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
510 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
511 4, 0),
512 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
513 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
514 0, 0),
515 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
517 3, 0),
518 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_temp_hyst,
520 store_pwm_auto_point_temp_hyst,
521 0, 0),
522 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
523 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
524
Hans de Goede66344aa2009-12-09 20:35:59 +0100525 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
526 show_pwm_auto_point_channel,
527 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100528 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
529 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
530 1, 1),
531 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
532 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
533 4, 1),
534 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
535 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
536 0, 1),
537 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
538 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
539 3, 1),
540 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
541 show_pwm_auto_point_temp_hyst,
542 store_pwm_auto_point_temp_hyst,
543 0, 1),
544 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
545 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100546
Hans de Goede66344aa2009-12-09 20:35:59 +0100547 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
548 show_pwm_auto_point_channel,
549 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100550 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
551 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
552 1, 2),
553 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
554 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
555 4, 2),
556 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
557 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
558 0, 2),
559 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
560 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
561 3, 2),
562 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
563 show_pwm_auto_point_temp_hyst,
564 store_pwm_auto_point_temp_hyst,
565 0, 2),
566 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
567 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100568};
569
Hans de Goede66344aa2009-12-09 20:35:59 +0100570/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100571static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100572 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
573 show_pwm_auto_point_channel,
574 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100575 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
576 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
577 0, 0),
578 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
580 1, 0),
581 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
583 2, 0),
584 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
585 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
586 3, 0),
587 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
588 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
589 4, 0),
590 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
592 0, 0),
593 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
595 1, 0),
596 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
598 2, 0),
599 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
601 3, 0),
602 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_temp_hyst,
604 store_pwm_auto_point_temp_hyst,
605 0, 0),
606 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
607 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
608 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
609 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
610 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
611 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100612}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100613 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_channel,
615 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100616 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
618 0, 1),
619 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
621 1, 1),
622 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
624 2, 1),
625 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
627 3, 1),
628 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 4, 1),
631 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
633 0, 1),
634 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
636 1, 1),
637 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
639 2, 1),
640 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 3, 1),
643 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp_hyst,
645 store_pwm_auto_point_temp_hyst,
646 0, 1),
647 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
648 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
649 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
650 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
651 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
652 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100653}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100654 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_channel,
656 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100657 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
659 0, 2),
660 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
662 1, 2),
663 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
665 2, 2),
666 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
667 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
668 3, 2),
669 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
670 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
671 4, 2),
672 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
674 0, 2),
675 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
677 1, 2),
678 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
680 2, 2),
681 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
683 3, 2),
684 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_temp_hyst,
686 store_pwm_auto_point_temp_hyst,
687 0, 2),
688 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
689 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
690 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
691 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
692 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
693 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100694}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100695 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_channel,
697 store_pwm_auto_point_channel, 0, 3),
698 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
700 0, 3),
701 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
703 1, 3),
704 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
706 2, 3),
707 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
708 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
709 3, 3),
710 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
711 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
712 4, 3),
713 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
714 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
715 0, 3),
716 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
718 1, 3),
719 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
721 2, 3),
722 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
724 3, 3),
725 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_temp_hyst,
727 store_pwm_auto_point_temp_hyst,
728 0, 3),
729 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
730 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
731 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
732 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
733 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
734 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100735} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200736
Hans de Goede66344aa2009-12-09 20:35:59 +0100737/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100738static struct sensor_device_attribute_2 f8000_fan_attr[] = {
739 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100740};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100741
Hans de Goede66344aa2009-12-09 20:35:59 +0100742/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
743 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
744 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
745static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
746 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_channel,
748 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100749 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
751 0, 2),
752 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
754 1, 2),
755 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
757 2, 2),
758 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
759 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
760 3, 2),
761 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
762 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
763 4, 2),
764 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
766 0, 2),
767 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
769 1, 2),
770 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
772 2, 2),
773 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
775 3, 2),
776 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_temp_hyst,
778 store_pwm_auto_point_temp_hyst,
779 0, 2),
780 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
781 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
782 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
783 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
784 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
785 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
786
Hans de Goede66344aa2009-12-09 20:35:59 +0100787 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_channel,
789 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100790 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
791 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
792 0, 0),
793 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
794 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
795 1, 0),
796 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
797 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
798 2, 0),
799 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
800 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
801 3, 0),
802 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
803 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
804 4, 0),
805 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
807 0, 0),
808 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
810 1, 0),
811 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
813 2, 0),
814 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
816 3, 0),
817 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_temp_hyst,
819 store_pwm_auto_point_temp_hyst,
820 0, 0),
821 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
822 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
823 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
824 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
825 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
826 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
827
Hans de Goede66344aa2009-12-09 20:35:59 +0100828 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_channel,
830 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100831 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
832 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
833 0, 1),
834 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
835 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
836 1, 1),
837 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
838 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
839 2, 1),
840 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
841 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
842 3, 1),
843 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
844 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
845 4, 1),
846 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
847 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
848 0, 1),
849 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
851 1, 1),
852 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
854 2, 1),
855 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
857 3, 1),
858 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_temp_hyst,
860 store_pwm_auto_point_temp_hyst,
861 0, 1),
862 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
863 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
864 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
865 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
866 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
867 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
868};
Hans de Goede45fb3662007-07-13 14:34:19 +0200869
870/* Super I/O functions */
871static inline int superio_inb(int base, int reg)
872{
873 outb(reg, base);
874 return inb(base + 1);
875}
876
877static int superio_inw(int base, int reg)
878{
879 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200880 val = superio_inb(base, reg) << 8;
881 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200882 return val;
883}
884
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400885static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200886{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400887 /* Don't step on other drivers' I/O space by accident */
888 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000889 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400890 return -EBUSY;
891 }
892
Hans de Goede45fb3662007-07-13 14:34:19 +0200893 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200894 outb(SIO_UNLOCK_KEY, base);
895 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400896
897 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200898}
899
Giel van Schijndel162bb592010-05-27 19:58:40 +0200900static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200901{
902 outb(SIO_REG_LDSEL, base);
903 outb(ld, base + 1);
904}
905
906static inline void superio_exit(int base)
907{
908 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400909 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200910}
911
Hans de Goede2f650632009-01-07 16:37:31 +0100912static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200913{
914 return reg ? (1500000 / reg) : 0;
915}
916
Hans de Goede2f650632009-01-07 16:37:31 +0100917static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100918{
919 return fan ? (1500000 / fan) : 0;
920}
921
Hans de Goede45fb3662007-07-13 14:34:19 +0200922static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
923{
924 u8 val;
925
926 outb(reg, data->addr + ADDR_REG_OFFSET);
927 val = inb(data->addr + DATA_REG_OFFSET);
928
929 return val;
930}
931
932static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
933{
934 u16 val;
935
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200936 val = f71882fg_read8(data, reg) << 8;
937 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200938
939 return val;
940}
941
942static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
943{
944 outb(reg, data->addr + ADDR_REG_OFFSET);
945 outb(val, data->addr + DATA_REG_OFFSET);
946}
947
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100948static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
949{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200950 f71882fg_write8(data, reg, val >> 8);
951 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100952}
953
Hans de Goede09475d32009-06-15 18:39:52 +0200954static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
955{
956 if (data->type == f71858fg)
957 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
958 else
959 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
960}
961
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100962static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200963{
964 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100965 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100966 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +0200967
968 mutex_lock(&data->update_lock);
969
970 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200971 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200972 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +0100973 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +0100974 data->in1_max =
975 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
976 data->in_beep =
977 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
978 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200979
980 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200981 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200982 data->temp_ovt[nr] = f71882fg_read8(data,
983 F71882FG_REG_TEMP_OVT(nr));
984 data->temp_high[nr] = f71882fg_read8(data,
985 F71882FG_REG_TEMP_HIGH(nr));
986 }
987
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100988 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100989 data->temp_hyst[0] = f71882fg_read8(data,
990 F71882FG_REG_TEMP_HYST(0));
991 data->temp_hyst[1] = f71882fg_read8(data,
992 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200993 }
994
Hans de Goede76698962009-12-09 20:36:01 +0100995 if (data->type == f71862fg || data->type == f71882fg ||
996 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200997 data->fan_beep = f71882fg_read8(data,
998 F71882FG_REG_FAN_BEEP);
999 data->temp_beep = f71882fg_read8(data,
1000 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001001 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001002 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001003 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1004 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1005 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001006
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001007 data->pwm_enable = f71882fg_read8(data,
1008 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001009 data->pwm_auto_point_hyst[0] =
1010 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1011 data->pwm_auto_point_hyst[1] =
1012 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1013
Hans de Goede498be962009-01-07 16:37:28 +01001014 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001015 data->pwm_auto_point_mapping[nr] =
1016 f71882fg_read8(data,
1017 F71882FG_REG_POINT_MAPPING(nr));
1018
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001019 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001020 int point;
1021 for (point = 0; point < 5; point++) {
1022 data->pwm_auto_point_pwm[nr][point] =
1023 f71882fg_read8(data,
1024 F71882FG_REG_POINT_PWM
1025 (nr, point));
1026 }
1027 for (point = 0; point < 4; point++) {
1028 data->pwm_auto_point_temp[nr][point] =
1029 f71882fg_read8(data,
1030 F71882FG_REG_POINT_TEMP
1031 (nr, point));
1032 }
1033 } else {
1034 data->pwm_auto_point_pwm[nr][1] =
1035 f71882fg_read8(data,
1036 F71882FG_REG_POINT_PWM
1037 (nr, 1));
1038 data->pwm_auto_point_pwm[nr][4] =
1039 f71882fg_read8(data,
1040 F71882FG_REG_POINT_PWM
1041 (nr, 4));
1042 data->pwm_auto_point_temp[nr][0] =
1043 f71882fg_read8(data,
1044 F71882FG_REG_POINT_TEMP
1045 (nr, 0));
1046 data->pwm_auto_point_temp[nr][3] =
1047 f71882fg_read8(data,
1048 F71882FG_REG_POINT_TEMP
1049 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001050 }
1051 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001052 data->last_limits = jiffies;
1053 }
1054
1055 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001056 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001057 data->temp_status = f71882fg_read8(data,
1058 F71882FG_REG_TEMP_STATUS);
1059 data->temp_diode_open = f71882fg_read8(data,
1060 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001061 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1062 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001063
1064 data->fan_status = f71882fg_read8(data,
1065 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001066 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001067 data->fan[nr] = f71882fg_read16(data,
1068 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001069 data->fan_target[nr] =
1070 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1071 data->fan_full_speed[nr] =
1072 f71882fg_read16(data,
1073 F71882FG_REG_FAN_FULL_SPEED(nr));
1074 data->pwm[nr] =
1075 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1076 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001077 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1078 if (data->type == f8000)
1079 data->fan[3] = f71882fg_read16(data,
1080 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001081
1082 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001083 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001084 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001085 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1086 if (f71882fg_has_in[data->type][nr])
1087 data->in[nr] = f71882fg_read8(data,
1088 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001089
1090 data->last_updated = jiffies;
1091 data->valid = 1;
1092 }
1093
1094 mutex_unlock(&data->update_lock);
1095
1096 return data;
1097}
1098
1099/* Sysfs Interface */
1100static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1101 char *buf)
1102{
1103 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001104 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001105 int speed = fan_from_reg(data->fan[nr]);
1106
1107 if (speed == FAN_MIN_DETECT)
1108 speed = 0;
1109
1110 return sprintf(buf, "%d\n", speed);
1111}
1112
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001113static ssize_t show_fan_full_speed(struct device *dev,
1114 struct device_attribute *devattr, char *buf)
1115{
1116 struct f71882fg_data *data = f71882fg_update_device(dev);
1117 int nr = to_sensor_dev_attr_2(devattr)->index;
1118 int speed = fan_from_reg(data->fan_full_speed[nr]);
1119 return sprintf(buf, "%d\n", speed);
1120}
1121
1122static ssize_t store_fan_full_speed(struct device *dev,
1123 struct device_attribute *devattr,
1124 const char *buf, size_t count)
1125{
1126 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001127 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1128 long val;
1129
1130 err = strict_strtol(buf, 10, &val);
1131 if (err)
1132 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001133
1134 val = SENSORS_LIMIT(val, 23, 1500000);
1135 val = fan_to_reg(val);
1136
1137 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001138 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1139 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001140 mutex_unlock(&data->update_lock);
1141
1142 return count;
1143}
1144
Hans de Goede45fb3662007-07-13 14:34:19 +02001145static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1146 *devattr, char *buf)
1147{
1148 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001149 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001150
1151 if (data->fan_beep & (1 << nr))
1152 return sprintf(buf, "1\n");
1153 else
1154 return sprintf(buf, "0\n");
1155}
1156
1157static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1158 *devattr, const char *buf, size_t count)
1159{
1160 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001161 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1162 unsigned long val;
1163
1164 err = strict_strtoul(buf, 10, &val);
1165 if (err)
1166 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001167
1168 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001169 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001170 if (val)
1171 data->fan_beep |= 1 << nr;
1172 else
1173 data->fan_beep &= ~(1 << nr);
1174
1175 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1176 mutex_unlock(&data->update_lock);
1177
1178 return count;
1179}
1180
1181static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1182 *devattr, char *buf)
1183{
1184 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001185 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001186
1187 if (data->fan_status & (1 << nr))
1188 return sprintf(buf, "1\n");
1189 else
1190 return sprintf(buf, "0\n");
1191}
1192
1193static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1194 char *buf)
1195{
1196 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001197 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001198
1199 return sprintf(buf, "%d\n", data->in[nr] * 8);
1200}
1201
1202static ssize_t show_in_max(struct device *dev, struct device_attribute
1203 *devattr, char *buf)
1204{
1205 struct f71882fg_data *data = f71882fg_update_device(dev);
1206
1207 return sprintf(buf, "%d\n", data->in1_max * 8);
1208}
1209
1210static ssize_t store_in_max(struct device *dev, struct device_attribute
1211 *devattr, const char *buf, size_t count)
1212{
1213 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001214 int err;
1215 long val;
1216
1217 err = strict_strtol(buf, 10, &val);
1218 if (err)
1219 return err;
1220
1221 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001222 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001223
1224 mutex_lock(&data->update_lock);
1225 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1226 data->in1_max = val;
1227 mutex_unlock(&data->update_lock);
1228
1229 return count;
1230}
1231
1232static ssize_t show_in_beep(struct device *dev, struct device_attribute
1233 *devattr, char *buf)
1234{
1235 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001236 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001237
1238 if (data->in_beep & (1 << nr))
1239 return sprintf(buf, "1\n");
1240 else
1241 return sprintf(buf, "0\n");
1242}
1243
1244static ssize_t store_in_beep(struct device *dev, struct device_attribute
1245 *devattr, const char *buf, size_t count)
1246{
1247 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001248 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1249 unsigned long val;
1250
1251 err = strict_strtoul(buf, 10, &val);
1252 if (err)
1253 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001254
1255 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001256 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001257 if (val)
1258 data->in_beep |= 1 << nr;
1259 else
1260 data->in_beep &= ~(1 << nr);
1261
1262 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1263 mutex_unlock(&data->update_lock);
1264
1265 return count;
1266}
1267
1268static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1269 *devattr, char *buf)
1270{
1271 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001272 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001273
1274 if (data->in_status & (1 << nr))
1275 return sprintf(buf, "1\n");
1276 else
1277 return sprintf(buf, "0\n");
1278}
1279
1280static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1281 char *buf)
1282{
1283 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001284 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001285 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001286
Hans de Goede09475d32009-06-15 18:39:52 +02001287 if (data->type == f71858fg) {
1288 /* TEMP_TABLE_SEL 1 or 3 ? */
1289 if (data->temp_config & 1) {
1290 sign = data->temp[nr] & 0x0001;
1291 temp = (data->temp[nr] >> 5) & 0x7ff;
1292 } else {
1293 sign = data->temp[nr] & 0x8000;
1294 temp = (data->temp[nr] >> 5) & 0x3ff;
1295 }
1296 temp *= 125;
1297 if (sign)
1298 temp -= 128000;
1299 } else
1300 temp = data->temp[nr] * 1000;
1301
1302 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001303}
1304
1305static ssize_t show_temp_max(struct device *dev, struct device_attribute
1306 *devattr, char *buf)
1307{
1308 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001309 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001310
1311 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1312}
1313
1314static ssize_t store_temp_max(struct device *dev, struct device_attribute
1315 *devattr, const char *buf, size_t count)
1316{
1317 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001318 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1319 long val;
1320
1321 err = strict_strtol(buf, 10, &val);
1322 if (err)
1323 return err;
1324
1325 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001326 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001327
1328 mutex_lock(&data->update_lock);
1329 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1330 data->temp_high[nr] = val;
1331 mutex_unlock(&data->update_lock);
1332
1333 return count;
1334}
1335
1336static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1337 *devattr, char *buf)
1338{
1339 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001340 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001341 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001342
Hans de Goedece0bfa52009-01-07 16:37:28 +01001343 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001344 if (nr & 1)
1345 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1346 else
1347 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1348 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001349 mutex_unlock(&data->update_lock);
1350
1351 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001352}
1353
1354static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1355 *devattr, const char *buf, size_t count)
1356{
1357 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001358 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001359 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001360 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001361 long val;
1362
1363 err = strict_strtol(buf, 10, &val);
1364 if (err)
1365 return err;
1366
1367 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001368
1369 mutex_lock(&data->update_lock);
1370
1371 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001372 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1373 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1374 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001375 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001376
1377 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001378 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1379 if (nr & 1)
1380 reg = (reg & 0x0f) | (val << 4);
1381 else
1382 reg = (reg & 0xf0) | val;
1383 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1384 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001385
Hans de Goede45fb3662007-07-13 14:34:19 +02001386 mutex_unlock(&data->update_lock);
1387 return ret;
1388}
1389
1390static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1391 *devattr, char *buf)
1392{
1393 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001394 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001395
1396 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1397}
1398
1399static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1400 *devattr, const char *buf, size_t count)
1401{
1402 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001403 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1404 long val;
1405
1406 err = strict_strtol(buf, 10, &val);
1407 if (err)
1408 return err;
1409
1410 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001411 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001412
1413 mutex_lock(&data->update_lock);
1414 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1415 data->temp_ovt[nr] = val;
1416 mutex_unlock(&data->update_lock);
1417
1418 return count;
1419}
1420
1421static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1422 *devattr, char *buf)
1423{
1424 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001425 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001426 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001427
Hans de Goedece0bfa52009-01-07 16:37:28 +01001428 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001429 if (nr & 1)
1430 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1431 else
1432 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1433 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001434 mutex_unlock(&data->update_lock);
1435
1436 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001437}
1438
1439static ssize_t show_temp_type(struct device *dev, struct device_attribute
1440 *devattr, char *buf)
1441{
1442 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001443 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001444
1445 return sprintf(buf, "%d\n", data->temp_type[nr]);
1446}
1447
1448static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1449 *devattr, char *buf)
1450{
1451 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001452 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001453
Hans de Goede7567a042009-01-07 16:37:28 +01001454 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001455 return sprintf(buf, "1\n");
1456 else
1457 return sprintf(buf, "0\n");
1458}
1459
1460static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1461 *devattr, const char *buf, size_t count)
1462{
1463 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001464 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1465 unsigned long val;
1466
1467 err = strict_strtoul(buf, 10, &val);
1468 if (err)
1469 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001470
1471 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001472 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001473 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001474 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001475 else
Hans de Goede7567a042009-01-07 16:37:28 +01001476 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001477
1478 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1479 mutex_unlock(&data->update_lock);
1480
1481 return count;
1482}
1483
1484static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1485 *devattr, char *buf)
1486{
1487 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001488 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001489
Hans de Goede7567a042009-01-07 16:37:28 +01001490 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001491 return sprintf(buf, "1\n");
1492 else
1493 return sprintf(buf, "0\n");
1494}
1495
1496static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1497 *devattr, char *buf)
1498{
1499 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001500 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001501
Hans de Goede7567a042009-01-07 16:37:28 +01001502 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001503 return sprintf(buf, "1\n");
1504 else
1505 return sprintf(buf, "0\n");
1506}
1507
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001508static ssize_t show_pwm(struct device *dev,
1509 struct device_attribute *devattr, char *buf)
1510{
1511 struct f71882fg_data *data = f71882fg_update_device(dev);
1512 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001513 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001514 if (data->pwm_enable & (1 << (2 * nr)))
1515 /* PWM mode */
1516 val = data->pwm[nr];
1517 else {
1518 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001519 val = 255 * fan_from_reg(data->fan_target[nr])
1520 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001521 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001522 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001523 return sprintf(buf, "%d\n", val);
1524}
1525
1526static ssize_t store_pwm(struct device *dev,
1527 struct device_attribute *devattr, const char *buf,
1528 size_t count)
1529{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001530 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001531 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1532 long val;
1533
1534 err = strict_strtol(buf, 10, &val);
1535 if (err)
1536 return err;
1537
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001538 val = SENSORS_LIMIT(val, 0, 255);
1539
1540 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001541 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001542 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1543 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1544 count = -EROFS;
1545 goto leave;
1546 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001547 if (data->pwm_enable & (1 << (2 * nr))) {
1548 /* PWM mode */
1549 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1550 data->pwm[nr] = val;
1551 } else {
1552 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001553 int target, full_speed;
1554 full_speed = f71882fg_read16(data,
1555 F71882FG_REG_FAN_FULL_SPEED(nr));
1556 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1557 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1558 data->fan_target[nr] = target;
1559 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001560 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001561leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001562 mutex_unlock(&data->update_lock);
1563
1564 return count;
1565}
1566
1567static ssize_t show_pwm_enable(struct device *dev,
1568 struct device_attribute *devattr, char *buf)
1569{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001570 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001571 struct f71882fg_data *data = f71882fg_update_device(dev);
1572 int nr = to_sensor_dev_attr_2(devattr)->index;
1573
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001574 switch ((data->pwm_enable >> 2 * nr) & 3) {
1575 case 0:
1576 case 1:
1577 result = 2; /* Normal auto mode */
1578 break;
1579 case 2:
1580 result = 1; /* Manual mode */
1581 break;
1582 case 3:
1583 if (data->type == f8000)
1584 result = 3; /* Thermostat mode */
1585 else
1586 result = 1; /* Manual mode */
1587 break;
1588 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001589
1590 return sprintf(buf, "%d\n", result);
1591}
1592
1593static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1594 *devattr, const char *buf, size_t count)
1595{
1596 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001597 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1598 long val;
1599
1600 err = strict_strtol(buf, 10, &val);
1601 if (err)
1602 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001603
Hans de Goede3fc78382009-06-15 18:39:50 +02001604 /* Special case for F8000 pwm channel 3 which only does auto mode */
1605 if (data->type == f8000 && nr == 2 && val != 2)
1606 return -EINVAL;
1607
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001608 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001609 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001610 /* Special case for F8000 auto PWM mode / Thermostat mode */
1611 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1612 switch (val) {
1613 case 2:
1614 data->pwm_enable &= ~(2 << (2 * nr));
1615 break; /* Normal auto mode */
1616 case 3:
1617 data->pwm_enable |= 2 << (2 * nr);
1618 break; /* Thermostat mode */
1619 default:
1620 count = -EINVAL;
1621 goto leave;
1622 }
1623 } else {
1624 switch (val) {
1625 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001626 /* The f71858fg does not support manual RPM mode */
1627 if (data->type == f71858fg &&
1628 ((data->pwm_enable >> (2 * nr)) & 1)) {
1629 count = -EINVAL;
1630 goto leave;
1631 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001632 data->pwm_enable |= 2 << (2 * nr);
1633 break; /* Manual */
1634 case 2:
1635 data->pwm_enable &= ~(2 << (2 * nr));
1636 break; /* Normal auto mode */
1637 default:
1638 count = -EINVAL;
1639 goto leave;
1640 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001641 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001642 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001643leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001644 mutex_unlock(&data->update_lock);
1645
1646 return count;
1647}
1648
1649static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1650 struct device_attribute *devattr,
1651 char *buf)
1652{
1653 int result;
1654 struct f71882fg_data *data = f71882fg_update_device(dev);
1655 int pwm = to_sensor_dev_attr_2(devattr)->index;
1656 int point = to_sensor_dev_attr_2(devattr)->nr;
1657
Hans de Goedece0bfa52009-01-07 16:37:28 +01001658 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001659 if (data->pwm_enable & (1 << (2 * pwm))) {
1660 /* PWM mode */
1661 result = data->pwm_auto_point_pwm[pwm][point];
1662 } else {
1663 /* RPM mode */
1664 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1665 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001666 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001667
1668 return sprintf(buf, "%d\n", result);
1669}
1670
1671static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1672 struct device_attribute *devattr,
1673 const char *buf, size_t count)
1674{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001675 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001676 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001677 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001678 long val;
1679
1680 err = strict_strtol(buf, 10, &val);
1681 if (err)
1682 return err;
1683
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001684 val = SENSORS_LIMIT(val, 0, 255);
1685
1686 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001687 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001688 if (data->pwm_enable & (1 << (2 * pwm))) {
1689 /* PWM mode */
1690 } else {
1691 /* RPM mode */
1692 if (val < 29) /* Prevent negative numbers */
1693 val = 255;
1694 else
1695 val = (255 - val) * 32 / val;
1696 }
1697 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1698 data->pwm_auto_point_pwm[pwm][point] = val;
1699 mutex_unlock(&data->update_lock);
1700
1701 return count;
1702}
1703
1704static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1705 struct device_attribute *devattr,
1706 char *buf)
1707{
1708 int result = 0;
1709 struct f71882fg_data *data = f71882fg_update_device(dev);
1710 int nr = to_sensor_dev_attr_2(devattr)->index;
1711 int point = to_sensor_dev_attr_2(devattr)->nr;
1712
1713 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001714 if (nr & 1)
1715 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1716 else
1717 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001718 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1719 mutex_unlock(&data->update_lock);
1720
1721 return sprintf(buf, "%d\n", result);
1722}
1723
1724static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1725 struct device_attribute *devattr,
1726 const char *buf, size_t count)
1727{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001728 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001729 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001730 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001731 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001732 long val;
1733
1734 err = strict_strtol(buf, 10, &val);
1735 if (err)
1736 return err;
1737
1738 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001739
1740 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001741 data->pwm_auto_point_temp[nr][point] =
1742 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001743 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1744 data->pwm_auto_point_temp[nr][point]);
1745 val = data->pwm_auto_point_temp[nr][point] - val;
1746
Hans de Goedebc274902009-01-07 16:37:29 +01001747 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1748 if (nr & 1)
1749 reg = (reg & 0x0f) | (val << 4);
1750 else
1751 reg = (reg & 0xf0) | val;
1752
1753 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1754 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001755 mutex_unlock(&data->update_lock);
1756
1757 return count;
1758}
1759
1760static ssize_t show_pwm_interpolate(struct device *dev,
1761 struct device_attribute *devattr, char *buf)
1762{
1763 int result;
1764 struct f71882fg_data *data = f71882fg_update_device(dev);
1765 int nr = to_sensor_dev_attr_2(devattr)->index;
1766
1767 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1768
1769 return sprintf(buf, "%d\n", result);
1770}
1771
1772static ssize_t store_pwm_interpolate(struct device *dev,
1773 struct device_attribute *devattr,
1774 const char *buf, size_t count)
1775{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001776 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001777 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1778 unsigned long val;
1779
1780 err = strict_strtoul(buf, 10, &val);
1781 if (err)
1782 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001783
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001784 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001785 data->pwm_auto_point_mapping[nr] =
1786 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001787 if (val)
1788 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1789 else
1790 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1791 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1792 data->pwm_auto_point_mapping[nr] = val;
1793 mutex_unlock(&data->update_lock);
1794
1795 return count;
1796}
1797
1798static ssize_t show_pwm_auto_point_channel(struct device *dev,
1799 struct device_attribute *devattr,
1800 char *buf)
1801{
1802 int result;
1803 struct f71882fg_data *data = f71882fg_update_device(dev);
1804 int nr = to_sensor_dev_attr_2(devattr)->index;
1805
Hans de Goede09475d32009-06-15 18:39:52 +02001806 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1807 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001808
1809 return sprintf(buf, "%d\n", result);
1810}
1811
1812static ssize_t store_pwm_auto_point_channel(struct device *dev,
1813 struct device_attribute *devattr,
1814 const char *buf, size_t count)
1815{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001816 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001817 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1818 long val;
1819
1820 err = strict_strtol(buf, 10, &val);
1821 if (err)
1822 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001823
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001824 switch (val) {
1825 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001826 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001827 break;
1828 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001829 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001830 break;
1831 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001832 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001833 break;
1834 default:
1835 return -EINVAL;
1836 }
Hans de Goede09475d32009-06-15 18:39:52 +02001837 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001838 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001839 data->pwm_auto_point_mapping[nr] =
1840 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1842 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1843 data->pwm_auto_point_mapping[nr] = val;
1844 mutex_unlock(&data->update_lock);
1845
1846 return count;
1847}
1848
1849static ssize_t show_pwm_auto_point_temp(struct device *dev,
1850 struct device_attribute *devattr,
1851 char *buf)
1852{
1853 int result;
1854 struct f71882fg_data *data = f71882fg_update_device(dev);
1855 int pwm = to_sensor_dev_attr_2(devattr)->index;
1856 int point = to_sensor_dev_attr_2(devattr)->nr;
1857
1858 result = data->pwm_auto_point_temp[pwm][point];
1859 return sprintf(buf, "%d\n", 1000 * result);
1860}
1861
1862static ssize_t store_pwm_auto_point_temp(struct device *dev,
1863 struct device_attribute *devattr,
1864 const char *buf, size_t count)
1865{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001866 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001867 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001868 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001869 long val;
1870
1871 err = strict_strtol(buf, 10, &val);
1872 if (err)
1873 return err;
1874
1875 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001876
Hans de Goede98f7ba12011-03-09 20:57:09 +01001877 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001878 val = SENSORS_LIMIT(val, -128, 127);
1879 else
1880 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001881
1882 mutex_lock(&data->update_lock);
1883 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1884 data->pwm_auto_point_temp[pwm][point] = val;
1885 mutex_unlock(&data->update_lock);
1886
1887 return count;
1888}
1889
Hans de Goede45fb3662007-07-13 14:34:19 +02001890static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1891 char *buf)
1892{
Hans de Goede498be962009-01-07 16:37:28 +01001893 struct f71882fg_data *data = dev_get_drvdata(dev);
1894 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001895}
1896
Hans de Goedec13548c2009-01-07 16:37:27 +01001897static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1898 struct sensor_device_attribute_2 *attr, int count)
1899{
1900 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001901
Hans de Goedec13548c2009-01-07 16:37:27 +01001902 for (i = 0; i < count; i++) {
1903 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1904 if (err)
1905 return err;
1906 }
1907 return 0;
1908}
1909
Hans de Goedefc16c562009-12-09 20:36:01 +01001910static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1911 struct sensor_device_attribute_2 *attr, int count)
1912{
1913 int i;
1914
1915 for (i = 0; i < count; i++)
1916 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1917}
1918
Hans de Goedec13548c2009-01-07 16:37:27 +01001919static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001920{
1921 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001922 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001923 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01001924 int nr_temps = 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01001925 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001926
Hans de Goedec13548c2009-01-07 16:37:27 +01001927 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1928 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001929 return -ENOMEM;
1930
1931 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001932 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001933 data->temp_start =
1934 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001935 mutex_init(&data->update_lock);
1936 platform_set_drvdata(pdev, data);
1937
Hans de Goede3cc74752009-01-07 16:37:28 +01001938 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001939 if (start_reg & 0x04) {
1940 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1941 err = -ENODEV;
1942 goto exit_free;
1943 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001944 if (!(start_reg & 0x03)) {
1945 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1946 err = -ENODEV;
1947 goto exit_free;
1948 }
1949
Hans de Goede45fb3662007-07-13 14:34:19 +02001950 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001951 err = device_create_file(&pdev->dev, &dev_attr_name);
1952 if (err)
1953 goto exit_unregister_sysfs;
1954
Hans de Goedec13548c2009-01-07 16:37:27 +01001955 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001956 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001957 case f71858fg:
1958 data->temp_config =
1959 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1960 if (data->temp_config & 0x10)
1961 /* The f71858fg temperature alarms behave as
1962 the f8000 alarms in this mode */
1963 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001964 f8000_temp_attr,
1965 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001966 else
1967 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001968 f71858fg_temp_attr,
1969 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001970 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01001971 case f8000:
1972 err = f71882fg_create_sysfs_files(pdev,
1973 f8000_temp_attr,
1974 ARRAY_SIZE(f8000_temp_attr));
1975 break;
1976 default:
1977 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01001978 &fxxxx_temp_attr[0][0],
1979 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01001980 }
1981 if (err)
1982 goto exit_unregister_sysfs;
1983
1984 for (i = 0; i < F71882FG_MAX_INS; i++) {
1985 if (f71882fg_has_in[data->type][i]) {
1986 err = device_create_file(&pdev->dev,
1987 &fxxxx_in_attr[i].dev_attr);
1988 if (err)
1989 goto exit_unregister_sysfs;
1990 }
1991 }
1992 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001993 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001994 fxxxx_in1_alarm_attr,
1995 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001996 if (err)
1997 goto exit_unregister_sysfs;
1998 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001999 }
2000
Hans de Goede45fb3662007-07-13 14:34:19 +02002001 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002002 switch (data->type) {
2003 case f71889fg:
2004 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2005 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2006 data->auto_point_temp_signed = 1;
2007 break;
2008 default:
2009 break;
2010 }
2011
Hans de Goede996cadb2009-06-15 18:39:51 +02002012 data->pwm_enable =
2013 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2014
2015 /* Sanity check the pwm settings */
2016 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002017 case f71858fg:
2018 err = 0;
2019 for (i = 0; i < nr_fans; i++)
2020 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2021 err = 1;
2022 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002023 case f71862fg:
2024 err = (data->pwm_enable & 0x15) != 0x15;
2025 break;
2026 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002027 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002028 err = 0;
2029 break;
2030 case f8000:
2031 err = data->pwm_enable & 0x20;
2032 break;
2033 }
2034 if (err) {
2035 dev_err(&pdev->dev,
2036 "Invalid (reserved) pwm settings: 0x%02x\n",
2037 (unsigned int)data->pwm_enable);
2038 err = -ENODEV;
2039 goto exit_unregister_sysfs;
2040 }
2041
Hans de Goedeb69b0392009-12-09 20:36:00 +01002042 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2043 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002044 if (err)
2045 goto exit_unregister_sysfs;
2046
Hans de Goede76698962009-12-09 20:36:01 +01002047 if (data->type == f71862fg || data->type == f71882fg ||
2048 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002049 err = f71882fg_create_sysfs_files(pdev,
2050 fxxxx_fan_beep_attr, nr_fans);
2051 if (err)
2052 goto exit_unregister_sysfs;
2053 }
2054
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002055 switch (data->type) {
2056 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002057 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002058 f71862fg_auto_pwm_attr,
2059 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002060 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002061 case f8000:
2062 err = f71882fg_create_sysfs_files(pdev,
2063 f8000_fan_attr,
2064 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002065 if (err)
2066 goto exit_unregister_sysfs;
2067 err = f71882fg_create_sysfs_files(pdev,
2068 f8000_auto_pwm_attr,
2069 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002070 break;
Hans de Goede76698962009-12-09 20:36:01 +01002071 case f71889fg:
2072 for (i = 0; i < nr_fans; i++) {
2073 data->pwm_auto_point_mapping[i] =
2074 f71882fg_read8(data,
2075 F71882FG_REG_POINT_MAPPING(i));
2076 if (data->pwm_auto_point_mapping[i] & 0x80)
2077 break;
2078 }
2079 if (i != nr_fans) {
2080 dev_warn(&pdev->dev,
2081 "Auto pwm controlled by raw digital "
2082 "data, disabling pwm auto_point "
2083 "sysfs attributes\n");
2084 break;
2085 }
2086 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002087 default: /* f71858fg / f71882fg */
2088 err = f71882fg_create_sysfs_files(pdev,
2089 &fxxxx_auto_pwm_attr[0][0],
2090 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002091 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002092 if (err)
2093 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002094
2095 for (i = 0; i < nr_fans; i++)
2096 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2097 (data->pwm_enable & (1 << 2 * i)) ?
2098 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002099 }
2100
Tony Jones1beeffe2007-08-20 13:46:20 -07002101 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2102 if (IS_ERR(data->hwmon_dev)) {
2103 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002104 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002105 goto exit_unregister_sysfs;
2106 }
2107
2108 return 0;
2109
2110exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002111 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002112 return err; /* f71882fg_remove() also frees our data */
2113exit_free:
2114 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002115 return err;
2116}
2117
Hans de Goedec13548c2009-01-07 16:37:27 +01002118static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002119{
Hans de Goede45fb3662007-07-13 14:34:19 +02002120 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002121 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01002122 int nr_temps = 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002123 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002124
Hans de Goedec13548c2009-01-07 16:37:27 +01002125 if (data->hwmon_dev)
2126 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002127
Hans de Goedec13548c2009-01-07 16:37:27 +01002128 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002129
Hans de Goedefc16c562009-12-09 20:36:01 +01002130 if (start_reg & 0x01) {
2131 switch (data->type) {
2132 case f71858fg:
2133 if (data->temp_config & 0x10)
2134 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002135 f8000_temp_attr,
2136 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002137 else
2138 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002139 f71858fg_temp_attr,
2140 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002141 break;
2142 case f8000:
2143 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002144 f8000_temp_attr,
2145 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002146 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002147 default:
2148 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002149 &fxxxx_temp_attr[0][0],
2150 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002151 }
2152 for (i = 0; i < F71882FG_MAX_INS; i++) {
2153 if (f71882fg_has_in[data->type][i]) {
2154 device_remove_file(&pdev->dev,
2155 &fxxxx_in_attr[i].dev_attr);
2156 }
2157 }
2158 if (f71882fg_has_in1_alarm[data->type]) {
2159 f71882fg_remove_sysfs_files(pdev,
2160 fxxxx_in1_alarm_attr,
2161 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002162 }
2163 }
Hans de Goede498be962009-01-07 16:37:28 +01002164
Hans de Goedefc16c562009-12-09 20:36:01 +01002165 if (start_reg & 0x02) {
2166 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2167 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002168
Hans de Goede76698962009-12-09 20:36:01 +01002169 if (data->type == f71862fg || data->type == f71882fg ||
2170 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002171 f71882fg_remove_sysfs_files(pdev,
2172 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002173
Hans de Goedefc16c562009-12-09 20:36:01 +01002174 switch (data->type) {
2175 case f71862fg:
2176 f71882fg_remove_sysfs_files(pdev,
2177 f71862fg_auto_pwm_attr,
2178 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2179 break;
2180 case f8000:
2181 f71882fg_remove_sysfs_files(pdev,
2182 f8000_fan_attr,
2183 ARRAY_SIZE(f8000_fan_attr));
2184 f71882fg_remove_sysfs_files(pdev,
2185 f8000_auto_pwm_attr,
2186 ARRAY_SIZE(f8000_auto_pwm_attr));
2187 break;
2188 default: /* f71858fg / f71882fg / f71889fg */
2189 f71882fg_remove_sysfs_files(pdev,
2190 &fxxxx_auto_pwm_attr[0][0],
2191 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2192 }
2193 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002194
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002195 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002196 kfree(data);
2197
2198 return 0;
2199}
2200
Hans de Goede498be962009-01-07 16:37:28 +01002201static int __init f71882fg_find(int sioaddr, unsigned short *address,
2202 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002203{
Hans de Goede45fb3662007-07-13 14:34:19 +02002204 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002205 int err = superio_enter(sioaddr);
2206 if (err)
2207 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002208
2209 devid = superio_inw(sioaddr, SIO_REG_MANID);
2210 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002211 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002212 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002213 goto exit;
2214 }
2215
Jean Delvare67b671b2007-12-06 23:13:42 +01002216 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002217 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002218 case SIO_F71858_ID:
2219 sio_data->type = f71858fg;
2220 break;
Hans de Goede498be962009-01-07 16:37:28 +01002221 case SIO_F71862_ID:
2222 sio_data->type = f71862fg;
2223 break;
2224 case SIO_F71882_ID:
2225 sio_data->type = f71882fg;
2226 break;
Hans de Goede76698962009-12-09 20:36:01 +01002227 case SIO_F71889_ID:
2228 sio_data->type = f71889fg;
2229 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002230 case SIO_F8000_ID:
2231 sio_data->type = f8000;
2232 break;
Hans de Goede498be962009-01-07 16:37:28 +01002233 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002234 pr_info("Unsupported Fintek device: %04x\n",
2235 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002236 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002237 goto exit;
2238 }
2239
Hans de Goede09475d32009-06-15 18:39:52 +02002240 if (sio_data->type == f71858fg)
2241 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2242 else
2243 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2244
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002245 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002246 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002247 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002248 goto exit;
2249 }
2250
2251 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002252 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002253 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002254 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002255 goto exit;
2256 }
2257 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2258
Hans de Goede45fb3662007-07-13 14:34:19 +02002259 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002260 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002261 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002262 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2263exit:
2264 superio_exit(sioaddr);
2265 return err;
2266}
2267
Hans de Goede498be962009-01-07 16:37:28 +01002268static int __init f71882fg_device_add(unsigned short address,
2269 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002270{
2271 struct resource res = {
2272 .start = address,
2273 .end = address + REGION_LENGTH - 1,
2274 .flags = IORESOURCE_IO,
2275 };
2276 int err;
2277
2278 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002279 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002280 return -ENOMEM;
2281
2282 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002283 err = acpi_check_resource_conflict(&res);
2284 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002285 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002286
Hans de Goede45fb3662007-07-13 14:34:19 +02002287 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002288 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002289 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002290 goto exit_device_put;
2291 }
2292
Hans de Goede498be962009-01-07 16:37:28 +01002293 err = platform_device_add_data(f71882fg_pdev, sio_data,
2294 sizeof(struct f71882fg_sio_data));
2295 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002296 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002297 goto exit_device_put;
2298 }
2299
Hans de Goede45fb3662007-07-13 14:34:19 +02002300 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002301 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002302 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002303 goto exit_device_put;
2304 }
2305
2306 return 0;
2307
2308exit_device_put:
2309 platform_device_put(f71882fg_pdev);
2310
2311 return err;
2312}
2313
2314static int __init f71882fg_init(void)
2315{
2316 int err = -ENODEV;
2317 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002318 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002319
Hans de Goede498be962009-01-07 16:37:28 +01002320 memset(&sio_data, 0, sizeof(sio_data));
2321
2322 if (f71882fg_find(0x2e, &address, &sio_data) &&
2323 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002324 goto exit;
2325
Hans de Goedec13548c2009-01-07 16:37:27 +01002326 err = platform_driver_register(&f71882fg_driver);
2327 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002328 goto exit;
2329
Hans de Goede498be962009-01-07 16:37:28 +01002330 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002331 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002332 goto exit_driver;
2333
2334 return 0;
2335
2336exit_driver:
2337 platform_driver_unregister(&f71882fg_driver);
2338exit:
2339 return err;
2340}
2341
2342static void __exit f71882fg_exit(void)
2343{
2344 platform_device_unregister(f71882fg_pdev);
2345 platform_driver_unregister(&f71882fg_driver);
2346}
2347
2348MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002349MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002350MODULE_LICENSE("GPL");
2351
2352module_init(f71882fg_init);
2353module_exit(f71882fg_exit);