blob: 4c17f12054a22e15c21cb91be660c8a5a4696da7 [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
Hans de Goede78aa4f72011-03-09 20:57:12 +0100130static const char f71882fg_has_beep[5] = {
131 0, /* f71858fg */
132 1, /* f71862fg */
133 1, /* f71882fg */
134 1, /* f71889fg */
135 0, /* f8000 */
136};
137
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100138static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200139
140/* Super-I/O Function prototypes */
141static inline int superio_inb(int base, int reg);
142static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400143static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200144static inline void superio_select(int base, int ld);
145static inline void superio_exit(int base);
146
Hans de Goede498be962009-01-07 16:37:28 +0100147struct f71882fg_sio_data {
148 enum chips type;
149};
150
Hans de Goede45fb3662007-07-13 14:34:19 +0200151struct f71882fg_data {
152 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100153 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700154 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200155
156 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200157 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200158 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100159 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200160 unsigned long last_updated; /* In jiffies */
161 unsigned long last_limits; /* In jiffies */
162
163 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100164 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200165 u8 in1_max;
166 u8 in_status;
167 u8 in_beep;
168 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100169 u16 fan_target[4];
170 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200171 u8 fan_status;
172 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100173 /* Note: all models have only 3 temperature channels, but on some
174 they are addressed as 0-2 and on others as 1-3, so for coding
175 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200176 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100177 u8 temp_ovt[4];
178 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100179 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100180 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200181 u8 temp_status;
182 u8 temp_beep;
183 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200184 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100185 u8 pwm[4];
186 u8 pwm_enable;
187 u8 pwm_auto_point_hyst[2];
188 u8 pwm_auto_point_mapping[4];
189 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100190 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200191};
192
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100193/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200194static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
195 char *buf);
196static ssize_t show_in_max(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t store_in_max(struct device *dev, struct device_attribute
199 *devattr, const char *buf, size_t count);
200static ssize_t show_in_beep(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_in_beep(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_in_alarm(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206/* Sysfs Fan */
207static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
208 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100209static ssize_t show_fan_full_speed(struct device *dev,
210 struct device_attribute *devattr, char *buf);
211static ssize_t store_fan_full_speed(struct device *dev,
212 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200213static ssize_t show_fan_beep(struct device *dev, struct device_attribute
214 *devattr, char *buf);
215static ssize_t store_fan_beep(struct device *dev, struct device_attribute
216 *devattr, const char *buf, size_t count);
217static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
218 *devattr, char *buf);
219/* Sysfs Temp */
220static ssize_t show_temp(struct device *dev, struct device_attribute
221 *devattr, char *buf);
222static ssize_t show_temp_max(struct device *dev, struct device_attribute
223 *devattr, char *buf);
224static ssize_t store_temp_max(struct device *dev, struct device_attribute
225 *devattr, const char *buf, size_t count);
226static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
227 *devattr, char *buf);
228static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
229 *devattr, const char *buf, size_t count);
230static ssize_t show_temp_crit(struct device *dev, struct device_attribute
231 *devattr, char *buf);
232static ssize_t store_temp_crit(struct device *dev, struct device_attribute
233 *devattr, const char *buf, size_t count);
234static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
235 *devattr, char *buf);
236static ssize_t show_temp_type(struct device *dev, struct device_attribute
237 *devattr, char *buf);
238static ssize_t show_temp_beep(struct device *dev, struct device_attribute
239 *devattr, char *buf);
240static ssize_t store_temp_beep(struct device *dev, struct device_attribute
241 *devattr, const char *buf, size_t count);
242static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
243 *devattr, char *buf);
244static ssize_t show_temp_fault(struct device *dev, struct device_attribute
245 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100246/* PWM and Auto point control */
247static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
248 char *buf);
249static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
250 const char *buf, size_t count);
251static ssize_t show_pwm_enable(struct device *dev,
252 struct device_attribute *devattr, char *buf);
253static ssize_t store_pwm_enable(struct device *dev,
254 struct device_attribute *devattr, const char *buf, size_t count);
255static ssize_t show_pwm_interpolate(struct device *dev,
256 struct device_attribute *devattr, char *buf);
257static ssize_t store_pwm_interpolate(struct device *dev,
258 struct device_attribute *devattr, const char *buf, size_t count);
259static ssize_t show_pwm_auto_point_channel(struct device *dev,
260 struct device_attribute *devattr, char *buf);
261static ssize_t store_pwm_auto_point_channel(struct device *dev,
262 struct device_attribute *devattr, const char *buf, size_t count);
263static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
264 struct device_attribute *devattr, char *buf);
265static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
266 struct device_attribute *devattr, const char *buf, size_t count);
267static ssize_t show_pwm_auto_point_pwm(struct device *dev,
268 struct device_attribute *devattr, char *buf);
269static ssize_t store_pwm_auto_point_pwm(struct device *dev,
270 struct device_attribute *devattr, const char *buf, size_t count);
271static ssize_t show_pwm_auto_point_temp(struct device *dev,
272 struct device_attribute *devattr, char *buf);
273static ssize_t store_pwm_auto_point_temp(struct device *dev,
274 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200275/* Sysfs misc */
276static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
277 char *buf);
278
279static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100280static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200281
282static struct platform_driver f71882fg_driver = {
283 .driver = {
284 .owner = THIS_MODULE,
285 .name = DRVNAME,
286 },
287 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200288 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200289};
290
Hans de Goedec13548c2009-01-07 16:37:27 +0100291static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200292
Hans de Goede0bae6402011-03-09 20:57:10 +0100293/* Temp attr for the f71858fg, the f71858fg is special as it has its
294 temperature indexes start at 0 (the others start at 1) */
295static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200296 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
297 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
298 store_temp_max, 0, 0),
299 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
300 store_temp_max_hyst, 0, 0),
301 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
302 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
303 store_temp_crit, 0, 0),
304 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
305 0, 0),
306 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
307 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
308 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
309 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
310 store_temp_max, 0, 1),
311 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
312 store_temp_max_hyst, 0, 1),
313 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
314 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
315 store_temp_crit, 0, 1),
316 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
317 0, 1),
318 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200319 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
320 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
321 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
322 store_temp_max, 0, 2),
323 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
324 store_temp_max_hyst, 0, 2),
325 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
326 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
327 store_temp_crit, 0, 2),
328 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
329 0, 2),
330 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
331 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
332};
333
Hans de Goede0bae6402011-03-09 20:57:10 +0100334/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100335static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100336 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100337 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100338 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100339 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100340 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100341 /* Should really be temp1_max_alarm, but older versions did not handle
342 the max and crit alarms separately and lm_sensors v2 depends on the
343 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
344 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100345 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100346 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100348 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100349 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100350 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100352}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
354 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100355 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100357 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100358 /* Should be temp2_max_alarm, see temp1_alarm note */
359 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100360 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100361 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100362 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100363 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100364 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100365 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100366 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100367}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100368 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
369 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
370 store_temp_max, 0, 3),
371 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
372 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100373 /* Should be temp3_max_alarm, see temp1_alarm note */
374 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
376 store_temp_crit, 0, 3),
377 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
378 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100379 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100380 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100381 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100382} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200383
Hans de Goede78aa4f72011-03-09 20:57:12 +0100384/* Temp attr for models which can beep on temp alarm */
385static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
386 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
387 store_temp_beep, 0, 1),
388 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
389 store_temp_beep, 0, 5),
390}, {
391 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
392 store_temp_beep, 0, 2),
393 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
394 store_temp_beep, 0, 6),
395}, {
396 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
397 store_temp_beep, 0, 3),
398 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
399 store_temp_beep, 0, 7),
400} };
401
Hans de Goede0bae6402011-03-09 20:57:10 +0100402/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100403 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
404 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100405 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100406 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100407static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100408 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
409 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
410 store_temp_crit, 0, 0),
411 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
412 store_temp_max, 0, 0),
413 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200414 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100415 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
416 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
417 store_temp_crit, 0, 1),
418 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
419 store_temp_max, 0, 1),
420 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200421 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100422 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
423 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
424 store_temp_crit, 0, 2),
425 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
426 store_temp_max, 0, 2),
427 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200428 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100429};
430
Hans de Goede0bae6402011-03-09 20:57:10 +0100431/* in attr for all models */
432static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
433 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
434 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
435 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
436 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
437 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
438 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
439 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
440 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
441 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
442};
443
444/* For models with in1 alarm capability */
445static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
446 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
447 0, 1),
448 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
449 0, 1),
450 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
451};
452
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100453/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100454static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100455 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100456 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
457 show_fan_full_speed,
458 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100459 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100460 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
461 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
462 store_pwm_enable, 0, 0),
463 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
464 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100465}, {
466 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
467 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
468 show_fan_full_speed,
469 store_fan_full_speed, 0, 1),
470 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100471 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
472 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
473 store_pwm_enable, 0, 1),
474 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
475 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100476}, {
477 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
478 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
479 show_fan_full_speed,
480 store_fan_full_speed, 0, 2),
481 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200482 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
483 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
484 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100485 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
486 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100487}, {
488 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
489 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
490 show_fan_full_speed,
491 store_fan_full_speed, 0, 3),
492 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
493 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
494 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
495 store_pwm_enable, 0, 3),
496 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
497 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
498} };
Hans de Goede498be962009-01-07 16:37:28 +0100499
Hans de Goede66344aa2009-12-09 20:35:59 +0100500/* Attr for models which can beep on Fan alarm */
501static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100502 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
503 store_fan_beep, 0, 0),
504 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
505 store_fan_beep, 0, 1),
506 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
507 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100508 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
509 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100510};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100511
Hans de Goede66344aa2009-12-09 20:35:59 +0100512/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
513 f71858fg / f71882fg / f71889fg */
514static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
515 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_channel,
517 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100518 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
520 1, 0),
521 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
522 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
523 4, 0),
524 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
525 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
526 0, 0),
527 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
528 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
529 3, 0),
530 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
531 show_pwm_auto_point_temp_hyst,
532 store_pwm_auto_point_temp_hyst,
533 0, 0),
534 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
535 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
536
Hans de Goede66344aa2009-12-09 20:35:59 +0100537 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
538 show_pwm_auto_point_channel,
539 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100540 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
541 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
542 1, 1),
543 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
544 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
545 4, 1),
546 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
547 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
548 0, 1),
549 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
550 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
551 3, 1),
552 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
553 show_pwm_auto_point_temp_hyst,
554 store_pwm_auto_point_temp_hyst,
555 0, 1),
556 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
557 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100558
Hans de Goede66344aa2009-12-09 20:35:59 +0100559 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
560 show_pwm_auto_point_channel,
561 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100562 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
563 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
564 1, 2),
565 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
566 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
567 4, 2),
568 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
569 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
570 0, 2),
571 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
572 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
573 3, 2),
574 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
575 show_pwm_auto_point_temp_hyst,
576 store_pwm_auto_point_temp_hyst,
577 0, 2),
578 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
579 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100580};
581
Hans de Goede66344aa2009-12-09 20:35:59 +0100582/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100583static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100584 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
585 show_pwm_auto_point_channel,
586 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100587 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
588 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
589 0, 0),
590 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
592 1, 0),
593 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
595 2, 0),
596 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
598 3, 0),
599 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
601 4, 0),
602 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
604 0, 0),
605 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
606 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
607 1, 0),
608 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
609 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
610 2, 0),
611 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
613 3, 0),
614 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_temp_hyst,
616 store_pwm_auto_point_temp_hyst,
617 0, 0),
618 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
619 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
620 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
621 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
622 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
623 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100624}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100625 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_channel,
627 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100628 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 0, 1),
631 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
633 1, 1),
634 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 2, 1),
637 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 3, 1),
640 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
642 4, 1),
643 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
645 0, 1),
646 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
648 1, 1),
649 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
651 2, 1),
652 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
653 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
654 3, 1),
655 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_temp_hyst,
657 store_pwm_auto_point_temp_hyst,
658 0, 1),
659 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
660 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
661 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
662 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
663 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
664 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100665}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100666 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
667 show_pwm_auto_point_channel,
668 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100669 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
670 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
671 0, 2),
672 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
674 1, 2),
675 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
677 2, 2),
678 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 3, 2),
681 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 4, 2),
684 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
686 0, 2),
687 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
689 1, 2),
690 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
692 2, 2),
693 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
695 3, 2),
696 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_temp_hyst,
698 store_pwm_auto_point_temp_hyst,
699 0, 2),
700 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
701 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
702 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
703 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
704 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
705 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100706}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100707 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
708 show_pwm_auto_point_channel,
709 store_pwm_auto_point_channel, 0, 3),
710 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
711 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
712 0, 3),
713 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
714 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
715 1, 3),
716 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
718 2, 3),
719 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
721 3, 3),
722 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
724 4, 3),
725 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
727 0, 3),
728 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
730 1, 3),
731 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
733 2, 3),
734 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
736 3, 3),
737 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_temp_hyst,
739 store_pwm_auto_point_temp_hyst,
740 0, 3),
741 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
742 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
743 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
744 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
745 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
746 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100747} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200748
Hans de Goede66344aa2009-12-09 20:35:59 +0100749/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100750static struct sensor_device_attribute_2 f8000_fan_attr[] = {
751 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100752};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100753
Hans de Goede66344aa2009-12-09 20:35:59 +0100754/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
755 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
756 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
757static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
758 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
759 show_pwm_auto_point_channel,
760 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100761 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
762 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
763 0, 2),
764 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
766 1, 2),
767 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
769 2, 2),
770 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
772 3, 2),
773 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
775 4, 2),
776 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
778 0, 2),
779 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
780 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
781 1, 2),
782 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
783 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
784 2, 2),
785 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
787 3, 2),
788 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_temp_hyst,
790 store_pwm_auto_point_temp_hyst,
791 0, 2),
792 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
793 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
794 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
795 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
796 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
797 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
798
Hans de Goede66344aa2009-12-09 20:35:59 +0100799 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
800 show_pwm_auto_point_channel,
801 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100802 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
803 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
804 0, 0),
805 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
807 1, 0),
808 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
810 2, 0),
811 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
813 3, 0),
814 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 4, 0),
817 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
819 0, 0),
820 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
822 1, 0),
823 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
825 2, 0),
826 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
828 3, 0),
829 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp_hyst,
831 store_pwm_auto_point_temp_hyst,
832 0, 0),
833 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
834 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
835 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
836 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
837 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
838 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
839
Hans de Goede66344aa2009-12-09 20:35:59 +0100840 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
841 show_pwm_auto_point_channel,
842 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100843 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
844 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
845 0, 1),
846 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
847 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
848 1, 1),
849 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
851 2, 1),
852 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
854 3, 1),
855 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
857 4, 1),
858 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
860 0, 1),
861 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
863 1, 1),
864 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
866 2, 1),
867 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
869 3, 1),
870 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_temp_hyst,
872 store_pwm_auto_point_temp_hyst,
873 0, 1),
874 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
875 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
876 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
877 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
878 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
879 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
880};
Hans de Goede45fb3662007-07-13 14:34:19 +0200881
882/* Super I/O functions */
883static inline int superio_inb(int base, int reg)
884{
885 outb(reg, base);
886 return inb(base + 1);
887}
888
889static int superio_inw(int base, int reg)
890{
891 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200892 val = superio_inb(base, reg) << 8;
893 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200894 return val;
895}
896
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400897static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200898{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400899 /* Don't step on other drivers' I/O space by accident */
900 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000901 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400902 return -EBUSY;
903 }
904
Hans de Goede45fb3662007-07-13 14:34:19 +0200905 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200906 outb(SIO_UNLOCK_KEY, base);
907 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400908
909 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200910}
911
Giel van Schijndel162bb592010-05-27 19:58:40 +0200912static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200913{
914 outb(SIO_REG_LDSEL, base);
915 outb(ld, base + 1);
916}
917
918static inline void superio_exit(int base)
919{
920 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400921 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200922}
923
Hans de Goede2f650632009-01-07 16:37:31 +0100924static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200925{
926 return reg ? (1500000 / reg) : 0;
927}
928
Hans de Goede2f650632009-01-07 16:37:31 +0100929static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100930{
931 return fan ? (1500000 / fan) : 0;
932}
933
Hans de Goede45fb3662007-07-13 14:34:19 +0200934static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
935{
936 u8 val;
937
938 outb(reg, data->addr + ADDR_REG_OFFSET);
939 val = inb(data->addr + DATA_REG_OFFSET);
940
941 return val;
942}
943
944static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
945{
946 u16 val;
947
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200948 val = f71882fg_read8(data, reg) << 8;
949 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200950
951 return val;
952}
953
954static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
955{
956 outb(reg, data->addr + ADDR_REG_OFFSET);
957 outb(val, data->addr + DATA_REG_OFFSET);
958}
959
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100960static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
961{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200962 f71882fg_write8(data, reg, val >> 8);
963 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100964}
965
Hans de Goede09475d32009-06-15 18:39:52 +0200966static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
967{
968 if (data->type == f71858fg)
969 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
970 else
971 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
972}
973
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100974static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200975{
976 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100977 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100978 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +0200979
980 mutex_lock(&data->update_lock);
981
982 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200983 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200984 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +0100985 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +0100986 data->in1_max =
987 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
988 data->in_beep =
989 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
990 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200991
992 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200993 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200994 data->temp_ovt[nr] = f71882fg_read8(data,
995 F71882FG_REG_TEMP_OVT(nr));
996 data->temp_high[nr] = f71882fg_read8(data,
997 F71882FG_REG_TEMP_HIGH(nr));
998 }
999
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001000 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001001 data->temp_hyst[0] = f71882fg_read8(data,
1002 F71882FG_REG_TEMP_HYST(0));
1003 data->temp_hyst[1] = f71882fg_read8(data,
1004 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001005 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001006 /* All but the f71858fg / f8000 have this register */
1007 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001008 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001009 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001010 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1011 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1012 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001013
Hans de Goede78aa4f72011-03-09 20:57:12 +01001014 if (f71882fg_has_beep[data->type]) {
1015 data->fan_beep = f71882fg_read8(data,
1016 F71882FG_REG_FAN_BEEP);
1017 data->temp_beep = f71882fg_read8(data,
1018 F71882FG_REG_TEMP_BEEP);
1019 }
1020
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001021 data->pwm_enable = f71882fg_read8(data,
1022 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001023 data->pwm_auto_point_hyst[0] =
1024 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1025 data->pwm_auto_point_hyst[1] =
1026 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1027
Hans de Goede498be962009-01-07 16:37:28 +01001028 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001029 data->pwm_auto_point_mapping[nr] =
1030 f71882fg_read8(data,
1031 F71882FG_REG_POINT_MAPPING(nr));
1032
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001033 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001034 int point;
1035 for (point = 0; point < 5; point++) {
1036 data->pwm_auto_point_pwm[nr][point] =
1037 f71882fg_read8(data,
1038 F71882FG_REG_POINT_PWM
1039 (nr, point));
1040 }
1041 for (point = 0; point < 4; point++) {
1042 data->pwm_auto_point_temp[nr][point] =
1043 f71882fg_read8(data,
1044 F71882FG_REG_POINT_TEMP
1045 (nr, point));
1046 }
1047 } else {
1048 data->pwm_auto_point_pwm[nr][1] =
1049 f71882fg_read8(data,
1050 F71882FG_REG_POINT_PWM
1051 (nr, 1));
1052 data->pwm_auto_point_pwm[nr][4] =
1053 f71882fg_read8(data,
1054 F71882FG_REG_POINT_PWM
1055 (nr, 4));
1056 data->pwm_auto_point_temp[nr][0] =
1057 f71882fg_read8(data,
1058 F71882FG_REG_POINT_TEMP
1059 (nr, 0));
1060 data->pwm_auto_point_temp[nr][3] =
1061 f71882fg_read8(data,
1062 F71882FG_REG_POINT_TEMP
1063 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001064 }
1065 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001066 data->last_limits = jiffies;
1067 }
1068
1069 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001070 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001071 data->temp_status = f71882fg_read8(data,
1072 F71882FG_REG_TEMP_STATUS);
1073 data->temp_diode_open = f71882fg_read8(data,
1074 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001075 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1076 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001077
1078 data->fan_status = f71882fg_read8(data,
1079 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001080 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001081 data->fan[nr] = f71882fg_read16(data,
1082 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001083 data->fan_target[nr] =
1084 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1085 data->fan_full_speed[nr] =
1086 f71882fg_read16(data,
1087 F71882FG_REG_FAN_FULL_SPEED(nr));
1088 data->pwm[nr] =
1089 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1090 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001091 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1092 if (data->type == f8000)
1093 data->fan[3] = f71882fg_read16(data,
1094 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001095
1096 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001097 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001098 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001099 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1100 if (f71882fg_has_in[data->type][nr])
1101 data->in[nr] = f71882fg_read8(data,
1102 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001103
1104 data->last_updated = jiffies;
1105 data->valid = 1;
1106 }
1107
1108 mutex_unlock(&data->update_lock);
1109
1110 return data;
1111}
1112
1113/* Sysfs Interface */
1114static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1115 char *buf)
1116{
1117 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001118 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001119 int speed = fan_from_reg(data->fan[nr]);
1120
1121 if (speed == FAN_MIN_DETECT)
1122 speed = 0;
1123
1124 return sprintf(buf, "%d\n", speed);
1125}
1126
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001127static ssize_t show_fan_full_speed(struct device *dev,
1128 struct device_attribute *devattr, char *buf)
1129{
1130 struct f71882fg_data *data = f71882fg_update_device(dev);
1131 int nr = to_sensor_dev_attr_2(devattr)->index;
1132 int speed = fan_from_reg(data->fan_full_speed[nr]);
1133 return sprintf(buf, "%d\n", speed);
1134}
1135
1136static ssize_t store_fan_full_speed(struct device *dev,
1137 struct device_attribute *devattr,
1138 const char *buf, size_t count)
1139{
1140 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001141 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1142 long val;
1143
1144 err = strict_strtol(buf, 10, &val);
1145 if (err)
1146 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001147
1148 val = SENSORS_LIMIT(val, 23, 1500000);
1149 val = fan_to_reg(val);
1150
1151 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001152 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1153 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001154 mutex_unlock(&data->update_lock);
1155
1156 return count;
1157}
1158
Hans de Goede45fb3662007-07-13 14:34:19 +02001159static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1160 *devattr, char *buf)
1161{
1162 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001163 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001164
1165 if (data->fan_beep & (1 << nr))
1166 return sprintf(buf, "1\n");
1167 else
1168 return sprintf(buf, "0\n");
1169}
1170
1171static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1172 *devattr, const char *buf, size_t count)
1173{
1174 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001175 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1176 unsigned long val;
1177
1178 err = strict_strtoul(buf, 10, &val);
1179 if (err)
1180 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001181
1182 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001183 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001184 if (val)
1185 data->fan_beep |= 1 << nr;
1186 else
1187 data->fan_beep &= ~(1 << nr);
1188
1189 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1190 mutex_unlock(&data->update_lock);
1191
1192 return count;
1193}
1194
1195static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1196 *devattr, char *buf)
1197{
1198 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001199 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001200
1201 if (data->fan_status & (1 << nr))
1202 return sprintf(buf, "1\n");
1203 else
1204 return sprintf(buf, "0\n");
1205}
1206
1207static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1208 char *buf)
1209{
1210 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001211 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001212
1213 return sprintf(buf, "%d\n", data->in[nr] * 8);
1214}
1215
1216static ssize_t show_in_max(struct device *dev, struct device_attribute
1217 *devattr, char *buf)
1218{
1219 struct f71882fg_data *data = f71882fg_update_device(dev);
1220
1221 return sprintf(buf, "%d\n", data->in1_max * 8);
1222}
1223
1224static ssize_t store_in_max(struct device *dev, struct device_attribute
1225 *devattr, const char *buf, size_t count)
1226{
1227 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001228 int err;
1229 long val;
1230
1231 err = strict_strtol(buf, 10, &val);
1232 if (err)
1233 return err;
1234
1235 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001236 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001237
1238 mutex_lock(&data->update_lock);
1239 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1240 data->in1_max = val;
1241 mutex_unlock(&data->update_lock);
1242
1243 return count;
1244}
1245
1246static ssize_t show_in_beep(struct device *dev, struct device_attribute
1247 *devattr, char *buf)
1248{
1249 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001250 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001251
1252 if (data->in_beep & (1 << nr))
1253 return sprintf(buf, "1\n");
1254 else
1255 return sprintf(buf, "0\n");
1256}
1257
1258static ssize_t store_in_beep(struct device *dev, struct device_attribute
1259 *devattr, const char *buf, size_t count)
1260{
1261 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001262 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1263 unsigned long val;
1264
1265 err = strict_strtoul(buf, 10, &val);
1266 if (err)
1267 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001268
1269 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001270 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001271 if (val)
1272 data->in_beep |= 1 << nr;
1273 else
1274 data->in_beep &= ~(1 << nr);
1275
1276 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1277 mutex_unlock(&data->update_lock);
1278
1279 return count;
1280}
1281
1282static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1283 *devattr, char *buf)
1284{
1285 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001286 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001287
1288 if (data->in_status & (1 << nr))
1289 return sprintf(buf, "1\n");
1290 else
1291 return sprintf(buf, "0\n");
1292}
1293
1294static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1295 char *buf)
1296{
1297 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001298 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001299 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001300
Hans de Goede09475d32009-06-15 18:39:52 +02001301 if (data->type == f71858fg) {
1302 /* TEMP_TABLE_SEL 1 or 3 ? */
1303 if (data->temp_config & 1) {
1304 sign = data->temp[nr] & 0x0001;
1305 temp = (data->temp[nr] >> 5) & 0x7ff;
1306 } else {
1307 sign = data->temp[nr] & 0x8000;
1308 temp = (data->temp[nr] >> 5) & 0x3ff;
1309 }
1310 temp *= 125;
1311 if (sign)
1312 temp -= 128000;
1313 } else
1314 temp = data->temp[nr] * 1000;
1315
1316 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001317}
1318
1319static ssize_t show_temp_max(struct device *dev, struct device_attribute
1320 *devattr, char *buf)
1321{
1322 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001323 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001324
1325 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1326}
1327
1328static ssize_t store_temp_max(struct device *dev, struct device_attribute
1329 *devattr, const char *buf, size_t count)
1330{
1331 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001332 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1333 long val;
1334
1335 err = strict_strtol(buf, 10, &val);
1336 if (err)
1337 return err;
1338
1339 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001340 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001341
1342 mutex_lock(&data->update_lock);
1343 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1344 data->temp_high[nr] = val;
1345 mutex_unlock(&data->update_lock);
1346
1347 return count;
1348}
1349
1350static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1351 *devattr, char *buf)
1352{
1353 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001354 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001355 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001356
Hans de Goedece0bfa52009-01-07 16:37:28 +01001357 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001358 if (nr & 1)
1359 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1360 else
1361 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1362 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001363 mutex_unlock(&data->update_lock);
1364
1365 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001366}
1367
1368static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1369 *devattr, const char *buf, size_t count)
1370{
1371 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001372 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001373 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001374 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001375 long val;
1376
1377 err = strict_strtol(buf, 10, &val);
1378 if (err)
1379 return err;
1380
1381 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001382
1383 mutex_lock(&data->update_lock);
1384
1385 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001386 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1387 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1388 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001389 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001390
1391 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001392 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1393 if (nr & 1)
1394 reg = (reg & 0x0f) | (val << 4);
1395 else
1396 reg = (reg & 0xf0) | val;
1397 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1398 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001399
Hans de Goede45fb3662007-07-13 14:34:19 +02001400 mutex_unlock(&data->update_lock);
1401 return ret;
1402}
1403
1404static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1405 *devattr, char *buf)
1406{
1407 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001408 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001409
1410 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1411}
1412
1413static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1414 *devattr, const char *buf, size_t count)
1415{
1416 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001417 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1418 long val;
1419
1420 err = strict_strtol(buf, 10, &val);
1421 if (err)
1422 return err;
1423
1424 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001425 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001426
1427 mutex_lock(&data->update_lock);
1428 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1429 data->temp_ovt[nr] = val;
1430 mutex_unlock(&data->update_lock);
1431
1432 return count;
1433}
1434
1435static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1436 *devattr, char *buf)
1437{
1438 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001439 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001440 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001441
Hans de Goedece0bfa52009-01-07 16:37:28 +01001442 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001443 if (nr & 1)
1444 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1445 else
1446 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1447 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001448 mutex_unlock(&data->update_lock);
1449
1450 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001451}
1452
1453static ssize_t show_temp_type(struct device *dev, struct device_attribute
1454 *devattr, char *buf)
1455{
1456 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001457 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001458
1459 return sprintf(buf, "%d\n", data->temp_type[nr]);
1460}
1461
1462static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1463 *devattr, char *buf)
1464{
1465 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001466 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001467
Hans de Goede7567a042009-01-07 16:37:28 +01001468 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001469 return sprintf(buf, "1\n");
1470 else
1471 return sprintf(buf, "0\n");
1472}
1473
1474static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1475 *devattr, const char *buf, size_t count)
1476{
1477 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001478 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1479 unsigned long val;
1480
1481 err = strict_strtoul(buf, 10, &val);
1482 if (err)
1483 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001484
1485 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001486 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001487 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001488 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001489 else
Hans de Goede7567a042009-01-07 16:37:28 +01001490 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001491
1492 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1493 mutex_unlock(&data->update_lock);
1494
1495 return count;
1496}
1497
1498static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1499 *devattr, char *buf)
1500{
1501 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001502 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001503
Hans de Goede7567a042009-01-07 16:37:28 +01001504 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001505 return sprintf(buf, "1\n");
1506 else
1507 return sprintf(buf, "0\n");
1508}
1509
1510static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1511 *devattr, char *buf)
1512{
1513 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001514 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001515
Hans de Goede7567a042009-01-07 16:37:28 +01001516 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001517 return sprintf(buf, "1\n");
1518 else
1519 return sprintf(buf, "0\n");
1520}
1521
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001522static ssize_t show_pwm(struct device *dev,
1523 struct device_attribute *devattr, char *buf)
1524{
1525 struct f71882fg_data *data = f71882fg_update_device(dev);
1526 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001527 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001528 if (data->pwm_enable & (1 << (2 * nr)))
1529 /* PWM mode */
1530 val = data->pwm[nr];
1531 else {
1532 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001533 val = 255 * fan_from_reg(data->fan_target[nr])
1534 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001535 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001536 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001537 return sprintf(buf, "%d\n", val);
1538}
1539
1540static ssize_t store_pwm(struct device *dev,
1541 struct device_attribute *devattr, const char *buf,
1542 size_t count)
1543{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001544 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001545 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1546 long val;
1547
1548 err = strict_strtol(buf, 10, &val);
1549 if (err)
1550 return err;
1551
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001552 val = SENSORS_LIMIT(val, 0, 255);
1553
1554 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001555 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001556 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1557 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1558 count = -EROFS;
1559 goto leave;
1560 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001561 if (data->pwm_enable & (1 << (2 * nr))) {
1562 /* PWM mode */
1563 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1564 data->pwm[nr] = val;
1565 } else {
1566 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001567 int target, full_speed;
1568 full_speed = f71882fg_read16(data,
1569 F71882FG_REG_FAN_FULL_SPEED(nr));
1570 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1571 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1572 data->fan_target[nr] = target;
1573 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001574 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001575leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001576 mutex_unlock(&data->update_lock);
1577
1578 return count;
1579}
1580
1581static ssize_t show_pwm_enable(struct device *dev,
1582 struct device_attribute *devattr, char *buf)
1583{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001584 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001585 struct f71882fg_data *data = f71882fg_update_device(dev);
1586 int nr = to_sensor_dev_attr_2(devattr)->index;
1587
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001588 switch ((data->pwm_enable >> 2 * nr) & 3) {
1589 case 0:
1590 case 1:
1591 result = 2; /* Normal auto mode */
1592 break;
1593 case 2:
1594 result = 1; /* Manual mode */
1595 break;
1596 case 3:
1597 if (data->type == f8000)
1598 result = 3; /* Thermostat mode */
1599 else
1600 result = 1; /* Manual mode */
1601 break;
1602 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001603
1604 return sprintf(buf, "%d\n", result);
1605}
1606
1607static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1608 *devattr, const char *buf, size_t count)
1609{
1610 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001611 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1612 long val;
1613
1614 err = strict_strtol(buf, 10, &val);
1615 if (err)
1616 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001617
Hans de Goede3fc78382009-06-15 18:39:50 +02001618 /* Special case for F8000 pwm channel 3 which only does auto mode */
1619 if (data->type == f8000 && nr == 2 && val != 2)
1620 return -EINVAL;
1621
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001622 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001623 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001624 /* Special case for F8000 auto PWM mode / Thermostat mode */
1625 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1626 switch (val) {
1627 case 2:
1628 data->pwm_enable &= ~(2 << (2 * nr));
1629 break; /* Normal auto mode */
1630 case 3:
1631 data->pwm_enable |= 2 << (2 * nr);
1632 break; /* Thermostat mode */
1633 default:
1634 count = -EINVAL;
1635 goto leave;
1636 }
1637 } else {
1638 switch (val) {
1639 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001640 /* The f71858fg does not support manual RPM mode */
1641 if (data->type == f71858fg &&
1642 ((data->pwm_enable >> (2 * nr)) & 1)) {
1643 count = -EINVAL;
1644 goto leave;
1645 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001646 data->pwm_enable |= 2 << (2 * nr);
1647 break; /* Manual */
1648 case 2:
1649 data->pwm_enable &= ~(2 << (2 * nr));
1650 break; /* Normal auto mode */
1651 default:
1652 count = -EINVAL;
1653 goto leave;
1654 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001655 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001656 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001657leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001658 mutex_unlock(&data->update_lock);
1659
1660 return count;
1661}
1662
1663static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1664 struct device_attribute *devattr,
1665 char *buf)
1666{
1667 int result;
1668 struct f71882fg_data *data = f71882fg_update_device(dev);
1669 int pwm = to_sensor_dev_attr_2(devattr)->index;
1670 int point = to_sensor_dev_attr_2(devattr)->nr;
1671
Hans de Goedece0bfa52009-01-07 16:37:28 +01001672 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001673 if (data->pwm_enable & (1 << (2 * pwm))) {
1674 /* PWM mode */
1675 result = data->pwm_auto_point_pwm[pwm][point];
1676 } else {
1677 /* RPM mode */
1678 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1679 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001680 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001681
1682 return sprintf(buf, "%d\n", result);
1683}
1684
1685static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1686 struct device_attribute *devattr,
1687 const char *buf, size_t count)
1688{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001689 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001690 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001691 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001692 long val;
1693
1694 err = strict_strtol(buf, 10, &val);
1695 if (err)
1696 return err;
1697
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001698 val = SENSORS_LIMIT(val, 0, 255);
1699
1700 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001701 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001702 if (data->pwm_enable & (1 << (2 * pwm))) {
1703 /* PWM mode */
1704 } else {
1705 /* RPM mode */
1706 if (val < 29) /* Prevent negative numbers */
1707 val = 255;
1708 else
1709 val = (255 - val) * 32 / val;
1710 }
1711 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1712 data->pwm_auto_point_pwm[pwm][point] = val;
1713 mutex_unlock(&data->update_lock);
1714
1715 return count;
1716}
1717
1718static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1719 struct device_attribute *devattr,
1720 char *buf)
1721{
1722 int result = 0;
1723 struct f71882fg_data *data = f71882fg_update_device(dev);
1724 int nr = to_sensor_dev_attr_2(devattr)->index;
1725 int point = to_sensor_dev_attr_2(devattr)->nr;
1726
1727 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001728 if (nr & 1)
1729 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1730 else
1731 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001732 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1733 mutex_unlock(&data->update_lock);
1734
1735 return sprintf(buf, "%d\n", result);
1736}
1737
1738static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1739 struct device_attribute *devattr,
1740 const char *buf, size_t count)
1741{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001742 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001743 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001744 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001745 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001746 long val;
1747
1748 err = strict_strtol(buf, 10, &val);
1749 if (err)
1750 return err;
1751
1752 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001753
1754 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001755 data->pwm_auto_point_temp[nr][point] =
1756 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001757 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1758 data->pwm_auto_point_temp[nr][point]);
1759 val = data->pwm_auto_point_temp[nr][point] - val;
1760
Hans de Goedebc274902009-01-07 16:37:29 +01001761 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1762 if (nr & 1)
1763 reg = (reg & 0x0f) | (val << 4);
1764 else
1765 reg = (reg & 0xf0) | val;
1766
1767 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1768 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001769 mutex_unlock(&data->update_lock);
1770
1771 return count;
1772}
1773
1774static ssize_t show_pwm_interpolate(struct device *dev,
1775 struct device_attribute *devattr, char *buf)
1776{
1777 int result;
1778 struct f71882fg_data *data = f71882fg_update_device(dev);
1779 int nr = to_sensor_dev_attr_2(devattr)->index;
1780
1781 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1782
1783 return sprintf(buf, "%d\n", result);
1784}
1785
1786static ssize_t store_pwm_interpolate(struct device *dev,
1787 struct device_attribute *devattr,
1788 const char *buf, size_t count)
1789{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001790 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001791 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1792 unsigned long val;
1793
1794 err = strict_strtoul(buf, 10, &val);
1795 if (err)
1796 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001797
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001798 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001799 data->pwm_auto_point_mapping[nr] =
1800 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001801 if (val)
1802 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1803 else
1804 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1805 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1806 data->pwm_auto_point_mapping[nr] = val;
1807 mutex_unlock(&data->update_lock);
1808
1809 return count;
1810}
1811
1812static ssize_t show_pwm_auto_point_channel(struct device *dev,
1813 struct device_attribute *devattr,
1814 char *buf)
1815{
1816 int result;
1817 struct f71882fg_data *data = f71882fg_update_device(dev);
1818 int nr = to_sensor_dev_attr_2(devattr)->index;
1819
Hans de Goede09475d32009-06-15 18:39:52 +02001820 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1821 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001822
1823 return sprintf(buf, "%d\n", result);
1824}
1825
1826static ssize_t store_pwm_auto_point_channel(struct device *dev,
1827 struct device_attribute *devattr,
1828 const char *buf, size_t count)
1829{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001830 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001831 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1832 long val;
1833
1834 err = strict_strtol(buf, 10, &val);
1835 if (err)
1836 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001837
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001838 switch (val) {
1839 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001840 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841 break;
1842 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001843 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001844 break;
1845 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001846 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001847 break;
1848 default:
1849 return -EINVAL;
1850 }
Hans de Goede09475d32009-06-15 18:39:52 +02001851 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001852 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001853 data->pwm_auto_point_mapping[nr] =
1854 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001855 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1856 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1857 data->pwm_auto_point_mapping[nr] = val;
1858 mutex_unlock(&data->update_lock);
1859
1860 return count;
1861}
1862
1863static ssize_t show_pwm_auto_point_temp(struct device *dev,
1864 struct device_attribute *devattr,
1865 char *buf)
1866{
1867 int result;
1868 struct f71882fg_data *data = f71882fg_update_device(dev);
1869 int pwm = to_sensor_dev_attr_2(devattr)->index;
1870 int point = to_sensor_dev_attr_2(devattr)->nr;
1871
1872 result = data->pwm_auto_point_temp[pwm][point];
1873 return sprintf(buf, "%d\n", 1000 * result);
1874}
1875
1876static ssize_t store_pwm_auto_point_temp(struct device *dev,
1877 struct device_attribute *devattr,
1878 const char *buf, size_t count)
1879{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001880 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001881 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001882 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001883 long val;
1884
1885 err = strict_strtol(buf, 10, &val);
1886 if (err)
1887 return err;
1888
1889 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001890
Hans de Goede98f7ba12011-03-09 20:57:09 +01001891 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001892 val = SENSORS_LIMIT(val, -128, 127);
1893 else
1894 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001895
1896 mutex_lock(&data->update_lock);
1897 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1898 data->pwm_auto_point_temp[pwm][point] = val;
1899 mutex_unlock(&data->update_lock);
1900
1901 return count;
1902}
1903
Hans de Goede45fb3662007-07-13 14:34:19 +02001904static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1905 char *buf)
1906{
Hans de Goede498be962009-01-07 16:37:28 +01001907 struct f71882fg_data *data = dev_get_drvdata(dev);
1908 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001909}
1910
Hans de Goedec13548c2009-01-07 16:37:27 +01001911static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1912 struct sensor_device_attribute_2 *attr, int count)
1913{
1914 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001915
Hans de Goedec13548c2009-01-07 16:37:27 +01001916 for (i = 0; i < count; i++) {
1917 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1918 if (err)
1919 return err;
1920 }
1921 return 0;
1922}
1923
Hans de Goedefc16c562009-12-09 20:36:01 +01001924static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1925 struct sensor_device_attribute_2 *attr, int count)
1926{
1927 int i;
1928
1929 for (i = 0; i < count; i++)
1930 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1931}
1932
Hans de Goedec13548c2009-01-07 16:37:27 +01001933static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001934{
1935 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001936 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001937 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01001938 int nr_temps = 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01001939 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001940
Hans de Goedec13548c2009-01-07 16:37:27 +01001941 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1942 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001943 return -ENOMEM;
1944
1945 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001946 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001947 data->temp_start =
1948 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001949 mutex_init(&data->update_lock);
1950 platform_set_drvdata(pdev, data);
1951
Hans de Goede3cc74752009-01-07 16:37:28 +01001952 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001953 if (start_reg & 0x04) {
1954 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1955 err = -ENODEV;
1956 goto exit_free;
1957 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001958 if (!(start_reg & 0x03)) {
1959 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1960 err = -ENODEV;
1961 goto exit_free;
1962 }
1963
Hans de Goede45fb3662007-07-13 14:34:19 +02001964 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001965 err = device_create_file(&pdev->dev, &dev_attr_name);
1966 if (err)
1967 goto exit_unregister_sysfs;
1968
Hans de Goedec13548c2009-01-07 16:37:27 +01001969 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001970 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001971 case f71858fg:
1972 data->temp_config =
1973 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1974 if (data->temp_config & 0x10)
1975 /* The f71858fg temperature alarms behave as
1976 the f8000 alarms in this mode */
1977 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001978 f8000_temp_attr,
1979 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001980 else
1981 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001982 f71858fg_temp_attr,
1983 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001984 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01001985 case f8000:
1986 err = f71882fg_create_sysfs_files(pdev,
1987 f8000_temp_attr,
1988 ARRAY_SIZE(f8000_temp_attr));
1989 break;
1990 default:
1991 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01001992 &fxxxx_temp_attr[0][0],
1993 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01001994 }
1995 if (err)
1996 goto exit_unregister_sysfs;
1997
Hans de Goede78aa4f72011-03-09 20:57:12 +01001998 if (f71882fg_has_beep[data->type]) {
1999 err = f71882fg_create_sysfs_files(pdev,
2000 &fxxxx_temp_beep_attr[0][0],
2001 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2002 * nr_temps);
2003 if (err)
2004 goto exit_unregister_sysfs;
2005 }
2006
Hans de Goede0bae6402011-03-09 20:57:10 +01002007 for (i = 0; i < F71882FG_MAX_INS; i++) {
2008 if (f71882fg_has_in[data->type][i]) {
2009 err = device_create_file(&pdev->dev,
2010 &fxxxx_in_attr[i].dev_attr);
2011 if (err)
2012 goto exit_unregister_sysfs;
2013 }
2014 }
2015 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002016 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002017 fxxxx_in1_alarm_attr,
2018 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002019 if (err)
2020 goto exit_unregister_sysfs;
2021 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002022 }
2023
Hans de Goede45fb3662007-07-13 14:34:19 +02002024 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002025 switch (data->type) {
2026 case f71889fg:
2027 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2028 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2029 data->auto_point_temp_signed = 1;
2030 break;
2031 default:
2032 break;
2033 }
2034
Hans de Goede996cadb2009-06-15 18:39:51 +02002035 data->pwm_enable =
2036 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2037
2038 /* Sanity check the pwm settings */
2039 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002040 case f71858fg:
2041 err = 0;
2042 for (i = 0; i < nr_fans; i++)
2043 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2044 err = 1;
2045 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002046 case f71862fg:
2047 err = (data->pwm_enable & 0x15) != 0x15;
2048 break;
2049 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002050 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002051 err = 0;
2052 break;
2053 case f8000:
2054 err = data->pwm_enable & 0x20;
2055 break;
2056 }
2057 if (err) {
2058 dev_err(&pdev->dev,
2059 "Invalid (reserved) pwm settings: 0x%02x\n",
2060 (unsigned int)data->pwm_enable);
2061 err = -ENODEV;
2062 goto exit_unregister_sysfs;
2063 }
2064
Hans de Goedeb69b0392009-12-09 20:36:00 +01002065 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2066 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002067 if (err)
2068 goto exit_unregister_sysfs;
2069
Hans de Goede78aa4f72011-03-09 20:57:12 +01002070 if (f71882fg_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002071 err = f71882fg_create_sysfs_files(pdev,
2072 fxxxx_fan_beep_attr, nr_fans);
2073 if (err)
2074 goto exit_unregister_sysfs;
2075 }
2076
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002077 switch (data->type) {
Hans de Goedee48a7f12011-03-09 20:57:13 +01002078 case f71889fg:
2079 for (i = 0; i < nr_fans; i++) {
2080 data->pwm_auto_point_mapping[i] =
2081 f71882fg_read8(data,
2082 F71882FG_REG_POINT_MAPPING(i));
2083 if (data->pwm_auto_point_mapping[i] & 0x80)
2084 break;
2085 }
2086 if (i != nr_fans) {
2087 dev_warn(&pdev->dev,
2088 "Auto pwm controlled by raw digital "
2089 "data, disabling pwm auto_point "
2090 "sysfs attributes\n");
2091 goto no_pwm_auto_point;
2092 }
2093 break;
2094 default:
2095 break;
2096 }
2097
2098 switch (data->type) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002099 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002100 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002101 f71862fg_auto_pwm_attr,
2102 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002103 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002104 case f8000:
2105 err = f71882fg_create_sysfs_files(pdev,
2106 f8000_fan_attr,
2107 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002108 if (err)
2109 goto exit_unregister_sysfs;
2110 err = f71882fg_create_sysfs_files(pdev,
2111 f8000_auto_pwm_attr,
2112 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002113 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002114 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002115 err = f71882fg_create_sysfs_files(pdev,
2116 &fxxxx_auto_pwm_attr[0][0],
2117 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002118 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002119 if (err)
2120 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002121
Hans de Goedee48a7f12011-03-09 20:57:13 +01002122no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002123 for (i = 0; i < nr_fans; i++)
2124 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2125 (data->pwm_enable & (1 << 2 * i)) ?
2126 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002127 }
2128
Tony Jones1beeffe2007-08-20 13:46:20 -07002129 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2130 if (IS_ERR(data->hwmon_dev)) {
2131 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002132 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002133 goto exit_unregister_sysfs;
2134 }
2135
2136 return 0;
2137
2138exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002139 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002140 return err; /* f71882fg_remove() also frees our data */
2141exit_free:
2142 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002143 return err;
2144}
2145
Hans de Goedec13548c2009-01-07 16:37:27 +01002146static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002147{
Hans de Goede45fb3662007-07-13 14:34:19 +02002148 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002149 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01002150 int nr_temps = 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002151 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002152
Hans de Goedec13548c2009-01-07 16:37:27 +01002153 if (data->hwmon_dev)
2154 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002155
Hans de Goedec13548c2009-01-07 16:37:27 +01002156 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002157
Hans de Goedefc16c562009-12-09 20:36:01 +01002158 if (start_reg & 0x01) {
2159 switch (data->type) {
2160 case f71858fg:
2161 if (data->temp_config & 0x10)
2162 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002163 f8000_temp_attr,
2164 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002165 else
2166 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002167 f71858fg_temp_attr,
2168 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002169 break;
2170 case f8000:
2171 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002172 f8000_temp_attr,
2173 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002174 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002175 default:
2176 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002177 &fxxxx_temp_attr[0][0],
2178 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002179 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002180 if (f71882fg_has_beep[data->type]) {
2181 f71882fg_remove_sysfs_files(pdev,
2182 &fxxxx_temp_beep_attr[0][0],
2183 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2184 }
2185
Hans de Goede0bae6402011-03-09 20:57:10 +01002186 for (i = 0; i < F71882FG_MAX_INS; i++) {
2187 if (f71882fg_has_in[data->type][i]) {
2188 device_remove_file(&pdev->dev,
2189 &fxxxx_in_attr[i].dev_attr);
2190 }
2191 }
2192 if (f71882fg_has_in1_alarm[data->type]) {
2193 f71882fg_remove_sysfs_files(pdev,
2194 fxxxx_in1_alarm_attr,
2195 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002196 }
2197 }
Hans de Goede498be962009-01-07 16:37:28 +01002198
Hans de Goedefc16c562009-12-09 20:36:01 +01002199 if (start_reg & 0x02) {
2200 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2201 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002202
Hans de Goede78aa4f72011-03-09 20:57:12 +01002203 if (f71882fg_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002204 f71882fg_remove_sysfs_files(pdev,
2205 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002206 }
Hans de Goede498be962009-01-07 16:37:28 +01002207
Hans de Goedefc16c562009-12-09 20:36:01 +01002208 switch (data->type) {
2209 case f71862fg:
2210 f71882fg_remove_sysfs_files(pdev,
2211 f71862fg_auto_pwm_attr,
2212 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2213 break;
2214 case f8000:
2215 f71882fg_remove_sysfs_files(pdev,
2216 f8000_fan_attr,
2217 ARRAY_SIZE(f8000_fan_attr));
2218 f71882fg_remove_sysfs_files(pdev,
2219 f8000_auto_pwm_attr,
2220 ARRAY_SIZE(f8000_auto_pwm_attr));
2221 break;
2222 default: /* f71858fg / f71882fg / f71889fg */
2223 f71882fg_remove_sysfs_files(pdev,
2224 &fxxxx_auto_pwm_attr[0][0],
2225 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2226 }
2227 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002228
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002229 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002230 kfree(data);
2231
2232 return 0;
2233}
2234
Hans de Goede498be962009-01-07 16:37:28 +01002235static int __init f71882fg_find(int sioaddr, unsigned short *address,
2236 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002237{
Hans de Goede45fb3662007-07-13 14:34:19 +02002238 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002239 int err = superio_enter(sioaddr);
2240 if (err)
2241 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002242
2243 devid = superio_inw(sioaddr, SIO_REG_MANID);
2244 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002245 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002246 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002247 goto exit;
2248 }
2249
Jean Delvare67b671b2007-12-06 23:13:42 +01002250 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002251 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002252 case SIO_F71858_ID:
2253 sio_data->type = f71858fg;
2254 break;
Hans de Goede498be962009-01-07 16:37:28 +01002255 case SIO_F71862_ID:
2256 sio_data->type = f71862fg;
2257 break;
2258 case SIO_F71882_ID:
2259 sio_data->type = f71882fg;
2260 break;
Hans de Goede76698962009-12-09 20:36:01 +01002261 case SIO_F71889_ID:
2262 sio_data->type = f71889fg;
2263 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002264 case SIO_F8000_ID:
2265 sio_data->type = f8000;
2266 break;
Hans de Goede498be962009-01-07 16:37:28 +01002267 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002268 pr_info("Unsupported Fintek device: %04x\n",
2269 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002270 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002271 goto exit;
2272 }
2273
Hans de Goede09475d32009-06-15 18:39:52 +02002274 if (sio_data->type == f71858fg)
2275 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2276 else
2277 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2278
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002279 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002280 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002281 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002282 goto exit;
2283 }
2284
2285 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002286 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002287 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002288 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002289 goto exit;
2290 }
2291 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2292
Hans de Goede45fb3662007-07-13 14:34:19 +02002293 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002294 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002295 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002296 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2297exit:
2298 superio_exit(sioaddr);
2299 return err;
2300}
2301
Hans de Goede498be962009-01-07 16:37:28 +01002302static int __init f71882fg_device_add(unsigned short address,
2303 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002304{
2305 struct resource res = {
2306 .start = address,
2307 .end = address + REGION_LENGTH - 1,
2308 .flags = IORESOURCE_IO,
2309 };
2310 int err;
2311
2312 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002313 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002314 return -ENOMEM;
2315
2316 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002317 err = acpi_check_resource_conflict(&res);
2318 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002319 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002320
Hans de Goede45fb3662007-07-13 14:34:19 +02002321 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002322 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002323 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002324 goto exit_device_put;
2325 }
2326
Hans de Goede498be962009-01-07 16:37:28 +01002327 err = platform_device_add_data(f71882fg_pdev, sio_data,
2328 sizeof(struct f71882fg_sio_data));
2329 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002330 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002331 goto exit_device_put;
2332 }
2333
Hans de Goede45fb3662007-07-13 14:34:19 +02002334 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002335 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002336 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002337 goto exit_device_put;
2338 }
2339
2340 return 0;
2341
2342exit_device_put:
2343 platform_device_put(f71882fg_pdev);
2344
2345 return err;
2346}
2347
2348static int __init f71882fg_init(void)
2349{
2350 int err = -ENODEV;
2351 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002352 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002353
Hans de Goede498be962009-01-07 16:37:28 +01002354 memset(&sio_data, 0, sizeof(sio_data));
2355
2356 if (f71882fg_find(0x2e, &address, &sio_data) &&
2357 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002358 goto exit;
2359
Hans de Goedec13548c2009-01-07 16:37:27 +01002360 err = platform_driver_register(&f71882fg_driver);
2361 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002362 goto exit;
2363
Hans de Goede498be962009-01-07 16:37:28 +01002364 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002365 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002366 goto exit_driver;
2367
2368 return 0;
2369
2370exit_driver:
2371 platform_driver_unregister(&f71882fg_driver);
2372exit:
2373 return err;
2374}
2375
2376static void __exit f71882fg_exit(void)
2377{
2378 platform_device_unregister(f71882fg_pdev);
2379 platform_driver_unregister(&f71882fg_driver);
2380}
2381
2382MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002383MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002384MODULE_LICENSE("GPL");
2385
2386module_init(f71882fg_init);
2387module_exit(f71882fg_exit);