blob: d867b377d4e961291bae51dd7cc0cf6fcfa57c34 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goedec13548c2009-01-07 16:37:27 +01003 * Copyright (C) 2007,2008 by 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
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/jiffies.h>
25#include <linux/platform_device.h>
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h>
29#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010030#include <linux/io.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020031
32#define DRVNAME "f71882fg"
33
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010034#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020035#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
36#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
37
38#define SIO_REG_LDSEL 0x07 /* Logical device select */
39#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
40#define SIO_REG_DEVREV 0x22 /* Device revision */
41#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
42#define SIO_REG_ENABLE 0x30 /* Logical device enable */
43#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
44
45#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede498be962009-01-07 16:37:28 +010046#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020047#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010048#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020049
50#define REGION_LENGTH 8
51#define ADDR_REG_OFFSET 5
52#define DATA_REG_OFFSET 6
53
54#define F71882FG_REG_PECI 0x0A
55
Hans de Goede498be962009-01-07 16:37:28 +010056#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
57#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020058#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010059#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020060
61#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010062#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
63#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020064#define F71882FG_REG_FAN_STATUS 0x92
65#define F71882FG_REG_FAN_BEEP 0x93
66
Hans de Goede7567a042009-01-07 16:37:28 +010067#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
68#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
69#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020070#define F71882FG_REG_TEMP_STATUS 0x62
71#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goedebc274902009-01-07 16:37:29 +010072#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020073#define F71882FG_REG_TEMP_TYPE 0x6B
74#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
75
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010076#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
77#define F71882FG_REG_PWM_TYPE 0x94
78#define F71882FG_REG_PWM_ENABLE 0x96
79
Hans de Goedebc274902009-01-07 16:37:29 +010080#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081
82#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
83#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
84#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
85
Hans de Goede45fb3662007-07-13 14:34:19 +020086#define F71882FG_REG_START 0x01
87
88#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
89
Jean Delvare67b671b2007-12-06 23:13:42 +010090static unsigned short force_id;
91module_param(force_id, ushort, 0);
92MODULE_PARM_DESC(force_id, "Override the detected device ID");
93
Hans de Goedeed4f7c22009-01-07 16:37:30 +010094enum chips { f71862fg, f71882fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +010095
96static const char *f71882fg_names[] = {
97 "f71862fg",
98 "f71882fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +010099 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100100};
101
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100102static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200103
104/* Super-I/O Function prototypes */
105static inline int superio_inb(int base, int reg);
106static inline int superio_inw(int base, int reg);
107static inline void superio_enter(int base);
108static inline void superio_select(int base, int ld);
109static inline void superio_exit(int base);
110
Hans de Goede498be962009-01-07 16:37:28 +0100111struct f71882fg_sio_data {
112 enum chips type;
113};
114
Hans de Goede45fb3662007-07-13 14:34:19 +0200115struct f71882fg_data {
116 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100117 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700118 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200119
120 struct mutex update_lock;
121 char valid; /* !=0 if following fields are valid */
122 unsigned long last_updated; /* In jiffies */
123 unsigned long last_limits; /* In jiffies */
124
125 /* Register Values */
126 u8 in[9];
127 u8 in1_max;
128 u8 in_status;
129 u8 in_beep;
130 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100131 u16 fan_target[4];
132 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200133 u8 fan_status;
134 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100135 /* Note: all models have only 3 temperature channels, but on some
136 they are addressed as 0-2 and on others as 1-3, so for coding
137 convenience we reserve space for 4 channels */
138 u8 temp[4];
139 u8 temp_ovt[4];
140 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100141 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100142 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200143 u8 temp_status;
144 u8 temp_beep;
145 u8 temp_diode_open;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100146 u8 pwm[4];
147 u8 pwm_enable;
148 u8 pwm_auto_point_hyst[2];
149 u8 pwm_auto_point_mapping[4];
150 u8 pwm_auto_point_pwm[4][5];
151 u8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200152};
153
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100154/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200155static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
156 char *buf);
157static ssize_t show_in_max(struct device *dev, struct device_attribute
158 *devattr, char *buf);
159static ssize_t store_in_max(struct device *dev, struct device_attribute
160 *devattr, const char *buf, size_t count);
161static ssize_t show_in_beep(struct device *dev, struct device_attribute
162 *devattr, char *buf);
163static ssize_t store_in_beep(struct device *dev, struct device_attribute
164 *devattr, const char *buf, size_t count);
165static ssize_t show_in_alarm(struct device *dev, struct device_attribute
166 *devattr, char *buf);
167/* Sysfs Fan */
168static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
169 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100170static ssize_t show_fan_full_speed(struct device *dev,
171 struct device_attribute *devattr, char *buf);
172static ssize_t store_fan_full_speed(struct device *dev,
173 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200174static ssize_t show_fan_beep(struct device *dev, struct device_attribute
175 *devattr, char *buf);
176static ssize_t store_fan_beep(struct device *dev, struct device_attribute
177 *devattr, const char *buf, size_t count);
178static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
179 *devattr, char *buf);
180/* Sysfs Temp */
181static ssize_t show_temp(struct device *dev, struct device_attribute
182 *devattr, char *buf);
183static ssize_t show_temp_max(struct device *dev, struct device_attribute
184 *devattr, char *buf);
185static ssize_t store_temp_max(struct device *dev, struct device_attribute
186 *devattr, const char *buf, size_t count);
187static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
190 *devattr, const char *buf, size_t count);
191static ssize_t show_temp_crit(struct device *dev, struct device_attribute
192 *devattr, char *buf);
193static ssize_t store_temp_crit(struct device *dev, struct device_attribute
194 *devattr, const char *buf, size_t count);
195static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
196 *devattr, char *buf);
197static ssize_t show_temp_type(struct device *dev, struct device_attribute
198 *devattr, char *buf);
199static ssize_t show_temp_beep(struct device *dev, struct device_attribute
200 *devattr, char *buf);
201static ssize_t store_temp_beep(struct device *dev, struct device_attribute
202 *devattr, const char *buf, size_t count);
203static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
204 *devattr, char *buf);
205static ssize_t show_temp_fault(struct device *dev, struct device_attribute
206 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100207/* PWM and Auto point control */
208static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
209 char *buf);
210static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
211 const char *buf, size_t count);
212static ssize_t show_pwm_enable(struct device *dev,
213 struct device_attribute *devattr, char *buf);
214static ssize_t store_pwm_enable(struct device *dev,
215 struct device_attribute *devattr, const char *buf, size_t count);
216static ssize_t show_pwm_interpolate(struct device *dev,
217 struct device_attribute *devattr, char *buf);
218static ssize_t store_pwm_interpolate(struct device *dev,
219 struct device_attribute *devattr, const char *buf, size_t count);
220static ssize_t show_pwm_auto_point_channel(struct device *dev,
221 struct device_attribute *devattr, char *buf);
222static ssize_t store_pwm_auto_point_channel(struct device *dev,
223 struct device_attribute *devattr, const char *buf, size_t count);
224static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
225 struct device_attribute *devattr, char *buf);
226static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
227 struct device_attribute *devattr, const char *buf, size_t count);
228static ssize_t show_pwm_auto_point_pwm(struct device *dev,
229 struct device_attribute *devattr, char *buf);
230static ssize_t store_pwm_auto_point_pwm(struct device *dev,
231 struct device_attribute *devattr, const char *buf, size_t count);
232static ssize_t show_pwm_auto_point_temp(struct device *dev,
233 struct device_attribute *devattr, char *buf);
234static ssize_t store_pwm_auto_point_temp(struct device *dev,
235 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200236/* Sysfs misc */
237static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
238 char *buf);
239
240static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100241static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200242
243static struct platform_driver f71882fg_driver = {
244 .driver = {
245 .owner = THIS_MODULE,
246 .name = DRVNAME,
247 },
248 .probe = f71882fg_probe,
249 .remove = __devexit_p(f71882fg_remove),
250};
251
Hans de Goedec13548c2009-01-07 16:37:27 +0100252static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200253
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100254/* Temp and in attr common to both the f71862fg and f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100255static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100256 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
257 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100258 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
259 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
260 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
261 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
262 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
263 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
264 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100265 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100266 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100267 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100268 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100269 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100270 /* Should really be temp1_max_alarm, but older versions did not handle
271 the max and crit alarms separately and lm_sensors v2 depends on the
272 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
273 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
274 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
275 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100276 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100277 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100278 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100279 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100280 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
281 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
282 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100283 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100284 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
285 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
286 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100287 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100288 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100289 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100290 /* Should be temp2_max_alarm, see temp1_alarm note */
291 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
292 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
293 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100294 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100295 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100296 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100297 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100298 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
299 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
300 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100301 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100302 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
303 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
304 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
305 store_temp_max, 0, 3),
306 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
307 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100308 /* Should be temp3_max_alarm, see temp1_alarm note */
309 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
310 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
311 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100312 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
313 store_temp_crit, 0, 3),
314 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
315 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100316 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
317 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
318 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100319 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100320 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200321};
322
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100323/* Temp and in attr found only on the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100324static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = {
325 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
326 0, 1),
327 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
328 0, 1),
329 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
330};
331
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100332/* Temp and in attr for the f8000
333 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
334 is used as hysteresis value to clear alarms
335 */
336static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
337 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
338 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
339 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
340 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
341 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
342 store_temp_crit, 0, 0),
343 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
344 store_temp_max, 0, 0),
345 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
346 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
347 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
348 store_temp_crit, 0, 1),
349 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
350 store_temp_max, 0, 1),
351 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
352 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
353 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
354 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
355 store_temp_crit, 0, 2),
356 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
357 store_temp_max, 0, 2),
358 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
359};
360
361/* Fan / PWM attr common to all models */
362static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100363 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100364 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
365 show_fan_full_speed,
366 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100367 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
368 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100369 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
370 show_fan_full_speed,
371 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100372 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
373 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100374 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
375 show_fan_full_speed,
376 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100377 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100378
379 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
380 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
381 store_pwm_enable, 0, 0),
382 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
383 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
384 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
385 show_pwm_auto_point_channel,
386 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100387
388 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
389 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
390 store_pwm_enable, 0, 1),
391 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
392 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
393 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
394 show_pwm_auto_point_channel,
395 store_pwm_auto_point_channel, 0, 1),
396
Hans de Goede498be962009-01-07 16:37:28 +0100397 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
398 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
399 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
400 show_pwm_auto_point_channel,
401 store_pwm_auto_point_channel, 0, 2),
402};
403
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100404/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
405 f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100406static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100407 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
408 store_fan_beep, 0, 0),
409 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
410 store_fan_beep, 0, 1),
411 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
412 store_fan_beep, 0, 2),
413
Hans de Goede498be962009-01-07 16:37:28 +0100414 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
415 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
416 1, 0),
417 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
418 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
419 4, 0),
420 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
421 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
422 0, 0),
423 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
424 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
425 3, 0),
426 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
427 show_pwm_auto_point_temp_hyst,
428 store_pwm_auto_point_temp_hyst,
429 0, 0),
430 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
431 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
432
433 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
434 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
435 1, 1),
436 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
437 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
438 4, 1),
439 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
440 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
441 0, 1),
442 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
443 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
444 3, 1),
445 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
446 show_pwm_auto_point_temp_hyst,
447 store_pwm_auto_point_temp_hyst,
448 0, 1),
449 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
450 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100451
452 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
453 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
454 store_pwm_enable, 0, 2),
455 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
456 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
457 1, 2),
458 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
459 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
460 4, 2),
461 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
462 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
463 0, 2),
464 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
465 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
466 3, 2),
467 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
468 show_pwm_auto_point_temp_hyst,
469 store_pwm_auto_point_temp_hyst,
470 0, 2),
471 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
472 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100473};
474
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100475/* Fan / PWM attr for the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100476static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100477 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
478 store_fan_beep, 0, 0),
479 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
480 store_fan_beep, 0, 1),
481 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
482 store_fan_beep, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100483 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
484 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
485 show_fan_full_speed,
486 store_fan_full_speed, 0, 3),
487 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
488 store_fan_beep, 0, 3),
489 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
490
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100491 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
492 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
493 0, 0),
494 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
495 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
496 1, 0),
497 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
498 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
499 2, 0),
500 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
501 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
502 3, 0),
503 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
504 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
505 4, 0),
506 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
507 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
508 0, 0),
509 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
510 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
511 1, 0),
512 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
513 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
514 2, 0),
515 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
517 3, 0),
518 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_temp_hyst,
520 store_pwm_auto_point_temp_hyst,
521 0, 0),
522 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
523 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
524 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
525 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
526 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
527 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
528
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100529 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 0, 1),
532 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
534 1, 1),
535 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
537 2, 1),
538 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
540 3, 1),
541 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
543 4, 1),
544 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
545 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
546 0, 1),
547 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
548 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
549 1, 1),
550 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
551 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
552 2, 1),
553 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
554 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
555 3, 1),
556 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
557 show_pwm_auto_point_temp_hyst,
558 store_pwm_auto_point_temp_hyst,
559 0, 1),
560 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
561 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
562 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
563 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
564 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
565 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
566
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100567 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
568 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
569 store_pwm_enable, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100570 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
571 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
572 0, 2),
573 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
575 1, 2),
576 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
578 2, 2),
579 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
581 3, 2),
582 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
584 4, 2),
585 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
587 0, 2),
588 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
589 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
590 1, 2),
591 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
592 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
593 2, 2),
594 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
595 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
596 3, 2),
597 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
598 show_pwm_auto_point_temp_hyst,
599 store_pwm_auto_point_temp_hyst,
600 0, 2),
601 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
602 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
603 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
604 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
605 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
606 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
607
608 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
609 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
610 store_pwm_enable, 0, 3),
611 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
612 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
613 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_channel,
615 store_pwm_auto_point_channel, 0, 3),
616 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
618 0, 3),
619 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
621 1, 3),
622 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
624 2, 3),
625 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
627 3, 3),
628 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 4, 3),
631 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
633 0, 3),
634 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
636 1, 3),
637 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
639 2, 3),
640 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 3, 3),
643 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp_hyst,
645 store_pwm_auto_point_temp_hyst,
646 0, 3),
647 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
648 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
649 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
650 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
651 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
652 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200653};
654
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100655/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm!
656 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
657 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
658static struct sensor_device_attribute_2 f8000_fan_attr[] = {
659 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
660
661 SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2),
662
663 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
665 0, 2),
666 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
667 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
668 1, 2),
669 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
670 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
671 2, 2),
672 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
674 3, 2),
675 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
677 4, 2),
678 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
680 0, 2),
681 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
683 1, 2),
684 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
686 2, 2),
687 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
689 3, 2),
690 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp_hyst,
692 store_pwm_auto_point_temp_hyst,
693 0, 2),
694 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
695 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
696 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
697 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
698 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
699 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
700
701 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
703 0, 0),
704 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
706 1, 0),
707 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
708 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
709 2, 0),
710 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
711 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
712 3, 0),
713 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
714 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
715 4, 0),
716 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
718 0, 0),
719 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
721 1, 0),
722 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
724 2, 0),
725 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
727 3, 0),
728 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_temp_hyst,
730 store_pwm_auto_point_temp_hyst,
731 0, 0),
732 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
733 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
734 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
735 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
736 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
737 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
738
739 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
740 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
741 0, 1),
742 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
743 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
744 1, 1),
745 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
746 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
747 2, 1),
748 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
749 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
750 3, 1),
751 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
752 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
753 4, 1),
754 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
755 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
756 0, 1),
757 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
759 1, 1),
760 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
761 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
762 2, 1),
763 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
764 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
765 3, 1),
766 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_temp_hyst,
768 store_pwm_auto_point_temp_hyst,
769 0, 1),
770 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
771 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
772 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
773 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
774 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
775 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
776};
Hans de Goede45fb3662007-07-13 14:34:19 +0200777
778/* Super I/O functions */
779static inline int superio_inb(int base, int reg)
780{
781 outb(reg, base);
782 return inb(base + 1);
783}
784
785static int superio_inw(int base, int reg)
786{
787 int val;
788 outb(reg++, base);
789 val = inb(base + 1) << 8;
790 outb(reg, base);
791 val |= inb(base + 1);
792 return val;
793}
794
795static inline void superio_enter(int base)
796{
797 /* according to the datasheet the key must be send twice! */
798 outb( SIO_UNLOCK_KEY, base);
799 outb( SIO_UNLOCK_KEY, base);
800}
801
802static inline void superio_select( int base, int ld)
803{
804 outb(SIO_REG_LDSEL, base);
805 outb(ld, base + 1);
806}
807
808static inline void superio_exit(int base)
809{
810 outb(SIO_LOCK_KEY, base);
811}
812
Hans de Goede2f650632009-01-07 16:37:31 +0100813static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200814{
815 return reg ? (1500000 / reg) : 0;
816}
817
Hans de Goede2f650632009-01-07 16:37:31 +0100818static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100819{
820 return fan ? (1500000 / fan) : 0;
821}
822
Hans de Goede45fb3662007-07-13 14:34:19 +0200823static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
824{
825 u8 val;
826
827 outb(reg, data->addr + ADDR_REG_OFFSET);
828 val = inb(data->addr + DATA_REG_OFFSET);
829
830 return val;
831}
832
833static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
834{
835 u16 val;
836
837 outb(reg++, data->addr + ADDR_REG_OFFSET);
838 val = inb(data->addr + DATA_REG_OFFSET) << 8;
839 outb(reg, data->addr + ADDR_REG_OFFSET);
840 val |= inb(data->addr + DATA_REG_OFFSET);
841
842 return val;
843}
844
845static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
846{
847 outb(reg, data->addr + ADDR_REG_OFFSET);
848 outb(val, data->addr + DATA_REG_OFFSET);
849}
850
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100851static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
852{
853 outb(reg++, data->addr + ADDR_REG_OFFSET);
854 outb(val >> 8, data->addr + DATA_REG_OFFSET);
855 outb(reg, data->addr + ADDR_REG_OFFSET);
856 outb(val & 255, data->addr + DATA_REG_OFFSET);
857}
858
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100859static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200860{
861 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100862 int nr, reg = 0, reg2;
863 int nr_fans = (data->type == f71882fg) ? 4 : 3;
864 int nr_ins = (data->type == f8000) ? 3 : 9;
865 int temp_start = (data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +0200866
867 mutex_lock(&data->update_lock);
868
869 /* Update once every 60 seconds */
870 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
871 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100872 if (data->type == f71882fg) {
873 data->in1_max =
874 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
875 data->in_beep =
876 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
877 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200878
879 /* Get High & boundary temps*/
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100880 for (nr = temp_start; nr < 3 + temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200881 data->temp_ovt[nr] = f71882fg_read8(data,
882 F71882FG_REG_TEMP_OVT(nr));
883 data->temp_high[nr] = f71882fg_read8(data,
884 F71882FG_REG_TEMP_HIGH(nr));
885 }
886
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100887 if (data->type != f8000) {
888 data->fan_beep = f71882fg_read8(data,
889 F71882FG_REG_FAN_BEEP);
890 data->temp_beep = f71882fg_read8(data,
891 F71882FG_REG_TEMP_BEEP);
892 data->temp_hyst[0] = f71882fg_read8(data,
893 F71882FG_REG_TEMP_HYST(0));
894 data->temp_hyst[1] = f71882fg_read8(data,
895 F71882FG_REG_TEMP_HYST(1));
896 /* Have to hardcode type, because temp1 is special */
897 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
898 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
899 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
900 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200901 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
902 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100903 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200904 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100905 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100906 else if (data->type != f8000)
Hans de Goede7567a042009-01-07 16:37:28 +0100907 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100908 else
909 data->temp_type[1] = 2; /* F8000 only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200910
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100911 data->pwm_enable = f71882fg_read8(data,
912 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100913 data->pwm_auto_point_hyst[0] =
914 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
915 data->pwm_auto_point_hyst[1] =
916 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
917
Hans de Goede498be962009-01-07 16:37:28 +0100918 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100919 data->pwm_auto_point_mapping[nr] =
920 f71882fg_read8(data,
921 F71882FG_REG_POINT_MAPPING(nr));
922
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100923 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100924 int point;
925 for (point = 0; point < 5; point++) {
926 data->pwm_auto_point_pwm[nr][point] =
927 f71882fg_read8(data,
928 F71882FG_REG_POINT_PWM
929 (nr, point));
930 }
931 for (point = 0; point < 4; point++) {
932 data->pwm_auto_point_temp[nr][point] =
933 f71882fg_read8(data,
934 F71882FG_REG_POINT_TEMP
935 (nr, point));
936 }
937 } else {
938 data->pwm_auto_point_pwm[nr][1] =
939 f71882fg_read8(data,
940 F71882FG_REG_POINT_PWM
941 (nr, 1));
942 data->pwm_auto_point_pwm[nr][4] =
943 f71882fg_read8(data,
944 F71882FG_REG_POINT_PWM
945 (nr, 4));
946 data->pwm_auto_point_temp[nr][0] =
947 f71882fg_read8(data,
948 F71882FG_REG_POINT_TEMP
949 (nr, 0));
950 data->pwm_auto_point_temp[nr][3] =
951 f71882fg_read8(data,
952 F71882FG_REG_POINT_TEMP
953 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100954 }
955 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200956 data->last_limits = jiffies;
957 }
958
959 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400960 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200961 data->temp_status = f71882fg_read8(data,
962 F71882FG_REG_TEMP_STATUS);
963 data->temp_diode_open = f71882fg_read8(data,
964 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100965 for (nr = temp_start; nr < 3 + temp_start; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200966 data->temp[nr] = f71882fg_read8(data,
967 F71882FG_REG_TEMP(nr));
968
969 data->fan_status = f71882fg_read8(data,
970 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +0100971 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200972 data->fan[nr] = f71882fg_read16(data,
973 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100974 data->fan_target[nr] =
975 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
976 data->fan_full_speed[nr] =
977 f71882fg_read16(data,
978 F71882FG_REG_FAN_FULL_SPEED(nr));
979 data->pwm[nr] =
980 f71882fg_read8(data, F71882FG_REG_PWM(nr));
981 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200982
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100983 /* The f8000 can monitor 1 more fan, but has no pwm for it */
984 if (data->type == f8000)
985 data->fan[3] = f71882fg_read16(data,
986 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +0100987 if (data->type == f71882fg)
988 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +0200989 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100990 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200991 data->in[nr] = f71882fg_read8(data,
992 F71882FG_REG_IN(nr));
993
994 data->last_updated = jiffies;
995 data->valid = 1;
996 }
997
998 mutex_unlock(&data->update_lock);
999
1000 return data;
1001}
1002
1003/* Sysfs Interface */
1004static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1005 char *buf)
1006{
1007 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001008 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001009 int speed = fan_from_reg(data->fan[nr]);
1010
1011 if (speed == FAN_MIN_DETECT)
1012 speed = 0;
1013
1014 return sprintf(buf, "%d\n", speed);
1015}
1016
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001017static ssize_t show_fan_full_speed(struct device *dev,
1018 struct device_attribute *devattr, char *buf)
1019{
1020 struct f71882fg_data *data = f71882fg_update_device(dev);
1021 int nr = to_sensor_dev_attr_2(devattr)->index;
1022 int speed = fan_from_reg(data->fan_full_speed[nr]);
1023 return sprintf(buf, "%d\n", speed);
1024}
1025
1026static ssize_t store_fan_full_speed(struct device *dev,
1027 struct device_attribute *devattr,
1028 const char *buf, size_t count)
1029{
1030 struct f71882fg_data *data = dev_get_drvdata(dev);
1031 int nr = to_sensor_dev_attr_2(devattr)->index;
1032 long val = simple_strtol(buf, NULL, 10);
1033
1034 val = SENSORS_LIMIT(val, 23, 1500000);
1035 val = fan_to_reg(val);
1036
1037 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001038 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1039 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001040 mutex_unlock(&data->update_lock);
1041
1042 return count;
1043}
1044
Hans de Goede45fb3662007-07-13 14:34:19 +02001045static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1046 *devattr, char *buf)
1047{
1048 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001049 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001050
1051 if (data->fan_beep & (1 << nr))
1052 return sprintf(buf, "1\n");
1053 else
1054 return sprintf(buf, "0\n");
1055}
1056
1057static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1058 *devattr, const char *buf, size_t count)
1059{
1060 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001061 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001062 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001063
1064 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001065 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001066 if (val)
1067 data->fan_beep |= 1 << nr;
1068 else
1069 data->fan_beep &= ~(1 << nr);
1070
1071 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1072 mutex_unlock(&data->update_lock);
1073
1074 return count;
1075}
1076
1077static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1078 *devattr, char *buf)
1079{
1080 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001081 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001082
1083 if (data->fan_status & (1 << nr))
1084 return sprintf(buf, "1\n");
1085 else
1086 return sprintf(buf, "0\n");
1087}
1088
1089static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1090 char *buf)
1091{
1092 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001093 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001094
1095 return sprintf(buf, "%d\n", data->in[nr] * 8);
1096}
1097
1098static ssize_t show_in_max(struct device *dev, struct device_attribute
1099 *devattr, char *buf)
1100{
1101 struct f71882fg_data *data = f71882fg_update_device(dev);
1102
1103 return sprintf(buf, "%d\n", data->in1_max * 8);
1104}
1105
1106static ssize_t store_in_max(struct device *dev, struct device_attribute
1107 *devattr, const char *buf, size_t count)
1108{
1109 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001110 long val = simple_strtol(buf, NULL, 10) / 8;
1111 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001112
1113 mutex_lock(&data->update_lock);
1114 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1115 data->in1_max = val;
1116 mutex_unlock(&data->update_lock);
1117
1118 return count;
1119}
1120
1121static ssize_t show_in_beep(struct device *dev, struct device_attribute
1122 *devattr, char *buf)
1123{
1124 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001125 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001126
1127 if (data->in_beep & (1 << nr))
1128 return sprintf(buf, "1\n");
1129 else
1130 return sprintf(buf, "0\n");
1131}
1132
1133static ssize_t store_in_beep(struct device *dev, struct device_attribute
1134 *devattr, const char *buf, size_t count)
1135{
1136 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001137 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001138 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001139
1140 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001141 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001142 if (val)
1143 data->in_beep |= 1 << nr;
1144 else
1145 data->in_beep &= ~(1 << nr);
1146
1147 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1148 mutex_unlock(&data->update_lock);
1149
1150 return count;
1151}
1152
1153static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1154 *devattr, char *buf)
1155{
1156 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001157 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001158
1159 if (data->in_status & (1 << nr))
1160 return sprintf(buf, "1\n");
1161 else
1162 return sprintf(buf, "0\n");
1163}
1164
1165static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1166 char *buf)
1167{
1168 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001169 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001170
1171 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
1172}
1173
1174static ssize_t show_temp_max(struct device *dev, struct device_attribute
1175 *devattr, char *buf)
1176{
1177 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001178 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001179
1180 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1181}
1182
1183static ssize_t store_temp_max(struct device *dev, struct device_attribute
1184 *devattr, const char *buf, size_t count)
1185{
1186 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001187 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001188 long val = simple_strtol(buf, NULL, 10) / 1000;
1189 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001190
1191 mutex_lock(&data->update_lock);
1192 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1193 data->temp_high[nr] = val;
1194 mutex_unlock(&data->update_lock);
1195
1196 return count;
1197}
1198
1199static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1200 *devattr, char *buf)
1201{
1202 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001203 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001204 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001205
Hans de Goedece0bfa52009-01-07 16:37:28 +01001206 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001207 if (nr & 1)
1208 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1209 else
1210 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1211 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001212 mutex_unlock(&data->update_lock);
1213
1214 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001215}
1216
1217static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1218 *devattr, const char *buf, size_t count)
1219{
1220 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001221 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001222 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001223 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001224 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001225
1226 mutex_lock(&data->update_lock);
1227
1228 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001229 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1230 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1231 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001232 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001233
1234 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001235 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1236 if (nr & 1)
1237 reg = (reg & 0x0f) | (val << 4);
1238 else
1239 reg = (reg & 0xf0) | val;
1240 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1241 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001242
Hans de Goede45fb3662007-07-13 14:34:19 +02001243 mutex_unlock(&data->update_lock);
1244 return ret;
1245}
1246
1247static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1248 *devattr, char *buf)
1249{
1250 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001251 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001252
1253 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1254}
1255
1256static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1257 *devattr, const char *buf, size_t count)
1258{
1259 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001260 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001261 long val = simple_strtol(buf, NULL, 10) / 1000;
1262 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001263
1264 mutex_lock(&data->update_lock);
1265 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1266 data->temp_ovt[nr] = val;
1267 mutex_unlock(&data->update_lock);
1268
1269 return count;
1270}
1271
1272static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1273 *devattr, char *buf)
1274{
1275 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001276 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001277 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001278
Hans de Goedece0bfa52009-01-07 16:37:28 +01001279 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001280 if (nr & 1)
1281 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1282 else
1283 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1284 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001285 mutex_unlock(&data->update_lock);
1286
1287 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001288}
1289
1290static ssize_t show_temp_type(struct device *dev, struct device_attribute
1291 *devattr, char *buf)
1292{
1293 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001294 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001295
1296 return sprintf(buf, "%d\n", data->temp_type[nr]);
1297}
1298
1299static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1300 *devattr, char *buf)
1301{
1302 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001303 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001304
Hans de Goede7567a042009-01-07 16:37:28 +01001305 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001306 return sprintf(buf, "1\n");
1307 else
1308 return sprintf(buf, "0\n");
1309}
1310
1311static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1312 *devattr, const char *buf, size_t count)
1313{
1314 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001315 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001316 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001317
1318 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001319 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001320 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001321 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001322 else
Hans de Goede7567a042009-01-07 16:37:28 +01001323 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001324
1325 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1326 mutex_unlock(&data->update_lock);
1327
1328 return count;
1329}
1330
1331static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1332 *devattr, char *buf)
1333{
1334 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001335 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001336
Hans de Goede7567a042009-01-07 16:37:28 +01001337 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001338 return sprintf(buf, "1\n");
1339 else
1340 return sprintf(buf, "0\n");
1341}
1342
1343static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1344 *devattr, char *buf)
1345{
1346 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001347 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001348
Hans de Goede7567a042009-01-07 16:37:28 +01001349 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001350 return sprintf(buf, "1\n");
1351 else
1352 return sprintf(buf, "0\n");
1353}
1354
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001355static ssize_t show_pwm(struct device *dev,
1356 struct device_attribute *devattr, char *buf)
1357{
1358 struct f71882fg_data *data = f71882fg_update_device(dev);
1359 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001360 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001361 if (data->pwm_enable & (1 << (2 * nr)))
1362 /* PWM mode */
1363 val = data->pwm[nr];
1364 else {
1365 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001366 val = 255 * fan_from_reg(data->fan_target[nr])
1367 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001368 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001369 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001370 return sprintf(buf, "%d\n", val);
1371}
1372
1373static ssize_t store_pwm(struct device *dev,
1374 struct device_attribute *devattr, const char *buf,
1375 size_t count)
1376{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001377 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001378 int nr = to_sensor_dev_attr_2(devattr)->index;
1379 long val = simple_strtol(buf, NULL, 10);
1380 val = SENSORS_LIMIT(val, 0, 255);
1381
1382 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001383 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001384 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1385 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1386 count = -EROFS;
1387 goto leave;
1388 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001389 if (data->pwm_enable & (1 << (2 * nr))) {
1390 /* PWM mode */
1391 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1392 data->pwm[nr] = val;
1393 } else {
1394 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001395 int target, full_speed;
1396 full_speed = f71882fg_read16(data,
1397 F71882FG_REG_FAN_FULL_SPEED(nr));
1398 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1399 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1400 data->fan_target[nr] = target;
1401 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001402 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001403leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001404 mutex_unlock(&data->update_lock);
1405
1406 return count;
1407}
1408
1409static ssize_t show_pwm_enable(struct device *dev,
1410 struct device_attribute *devattr, char *buf)
1411{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001412 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001413 struct f71882fg_data *data = f71882fg_update_device(dev);
1414 int nr = to_sensor_dev_attr_2(devattr)->index;
1415
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001416 switch ((data->pwm_enable >> 2 * nr) & 3) {
1417 case 0:
1418 case 1:
1419 result = 2; /* Normal auto mode */
1420 break;
1421 case 2:
1422 result = 1; /* Manual mode */
1423 break;
1424 case 3:
1425 if (data->type == f8000)
1426 result = 3; /* Thermostat mode */
1427 else
1428 result = 1; /* Manual mode */
1429 break;
1430 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001431
1432 return sprintf(buf, "%d\n", result);
1433}
1434
1435static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1436 *devattr, const char *buf, size_t count)
1437{
1438 struct f71882fg_data *data = dev_get_drvdata(dev);
1439 int nr = to_sensor_dev_attr_2(devattr)->index;
1440 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001441
1442 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001443 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001444 /* Special case for F8000 auto PWM mode / Thermostat mode */
1445 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1446 switch (val) {
1447 case 2:
1448 data->pwm_enable &= ~(2 << (2 * nr));
1449 break; /* Normal auto mode */
1450 case 3:
1451 data->pwm_enable |= 2 << (2 * nr);
1452 break; /* Thermostat mode */
1453 default:
1454 count = -EINVAL;
1455 goto leave;
1456 }
1457 } else {
1458 switch (val) {
1459 case 1:
1460 data->pwm_enable |= 2 << (2 * nr);
1461 break; /* Manual */
1462 case 2:
1463 data->pwm_enable &= ~(2 << (2 * nr));
1464 break; /* Normal auto mode */
1465 default:
1466 count = -EINVAL;
1467 goto leave;
1468 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001469 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001470 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001471leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001472 mutex_unlock(&data->update_lock);
1473
1474 return count;
1475}
1476
1477static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1478 struct device_attribute *devattr,
1479 char *buf)
1480{
1481 int result;
1482 struct f71882fg_data *data = f71882fg_update_device(dev);
1483 int pwm = to_sensor_dev_attr_2(devattr)->index;
1484 int point = to_sensor_dev_attr_2(devattr)->nr;
1485
Hans de Goedece0bfa52009-01-07 16:37:28 +01001486 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001487 if (data->pwm_enable & (1 << (2 * pwm))) {
1488 /* PWM mode */
1489 result = data->pwm_auto_point_pwm[pwm][point];
1490 } else {
1491 /* RPM mode */
1492 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1493 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001494 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001495
1496 return sprintf(buf, "%d\n", result);
1497}
1498
1499static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1500 struct device_attribute *devattr,
1501 const char *buf, size_t count)
1502{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001503 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001504 int pwm = to_sensor_dev_attr_2(devattr)->index;
1505 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001506 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001507 val = SENSORS_LIMIT(val, 0, 255);
1508
1509 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001510 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001511 if (data->pwm_enable & (1 << (2 * pwm))) {
1512 /* PWM mode */
1513 } else {
1514 /* RPM mode */
1515 if (val < 29) /* Prevent negative numbers */
1516 val = 255;
1517 else
1518 val = (255 - val) * 32 / val;
1519 }
1520 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1521 data->pwm_auto_point_pwm[pwm][point] = val;
1522 mutex_unlock(&data->update_lock);
1523
1524 return count;
1525}
1526
1527static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1528 struct device_attribute *devattr,
1529 char *buf)
1530{
1531 int result = 0;
1532 struct f71882fg_data *data = f71882fg_update_device(dev);
1533 int nr = to_sensor_dev_attr_2(devattr)->index;
1534 int point = to_sensor_dev_attr_2(devattr)->nr;
1535
1536 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001537 if (nr & 1)
1538 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1539 else
1540 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001541 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1542 mutex_unlock(&data->update_lock);
1543
1544 return sprintf(buf, "%d\n", result);
1545}
1546
1547static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1548 struct device_attribute *devattr,
1549 const char *buf, size_t count)
1550{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001551 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001552 int nr = to_sensor_dev_attr_2(devattr)->index;
1553 int point = to_sensor_dev_attr_2(devattr)->nr;
1554 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001555 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001556
1557 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001558 data->pwm_auto_point_temp[nr][point] =
1559 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001560 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1561 data->pwm_auto_point_temp[nr][point]);
1562 val = data->pwm_auto_point_temp[nr][point] - val;
1563
Hans de Goedebc274902009-01-07 16:37:29 +01001564 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1565 if (nr & 1)
1566 reg = (reg & 0x0f) | (val << 4);
1567 else
1568 reg = (reg & 0xf0) | val;
1569
1570 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1571 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001572 mutex_unlock(&data->update_lock);
1573
1574 return count;
1575}
1576
1577static ssize_t show_pwm_interpolate(struct device *dev,
1578 struct device_attribute *devattr, char *buf)
1579{
1580 int result;
1581 struct f71882fg_data *data = f71882fg_update_device(dev);
1582 int nr = to_sensor_dev_attr_2(devattr)->index;
1583
1584 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1585
1586 return sprintf(buf, "%d\n", result);
1587}
1588
1589static ssize_t store_pwm_interpolate(struct device *dev,
1590 struct device_attribute *devattr,
1591 const char *buf, size_t count)
1592{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001593 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001594 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001595 unsigned long val = simple_strtoul(buf, NULL, 10);
1596
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001597 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001598 data->pwm_auto_point_mapping[nr] =
1599 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001600 if (val)
1601 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1602 else
1603 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1604 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1605 data->pwm_auto_point_mapping[nr] = val;
1606 mutex_unlock(&data->update_lock);
1607
1608 return count;
1609}
1610
1611static ssize_t show_pwm_auto_point_channel(struct device *dev,
1612 struct device_attribute *devattr,
1613 char *buf)
1614{
1615 int result;
1616 struct f71882fg_data *data = f71882fg_update_device(dev);
1617 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001618 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001619
Hans de Goede30453012009-01-07 16:37:30 +01001620 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001621
1622 return sprintf(buf, "%d\n", result);
1623}
1624
1625static ssize_t store_pwm_auto_point_channel(struct device *dev,
1626 struct device_attribute *devattr,
1627 const char *buf, size_t count)
1628{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001629 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001630 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001631 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001632 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001633
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001634 switch (val) {
1635 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001636 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001637 break;
1638 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001639 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001640 break;
1641 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001642 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001643 break;
1644 default:
1645 return -EINVAL;
1646 }
Hans de Goede30453012009-01-07 16:37:30 +01001647 val += temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001648 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001649 data->pwm_auto_point_mapping[nr] =
1650 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001651 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1652 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1653 data->pwm_auto_point_mapping[nr] = val;
1654 mutex_unlock(&data->update_lock);
1655
1656 return count;
1657}
1658
1659static ssize_t show_pwm_auto_point_temp(struct device *dev,
1660 struct device_attribute *devattr,
1661 char *buf)
1662{
1663 int result;
1664 struct f71882fg_data *data = f71882fg_update_device(dev);
1665 int pwm = to_sensor_dev_attr_2(devattr)->index;
1666 int point = to_sensor_dev_attr_2(devattr)->nr;
1667
1668 result = data->pwm_auto_point_temp[pwm][point];
1669 return sprintf(buf, "%d\n", 1000 * result);
1670}
1671
1672static ssize_t store_pwm_auto_point_temp(struct device *dev,
1673 struct device_attribute *devattr,
1674 const char *buf, size_t count)
1675{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001676 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001677 int pwm = to_sensor_dev_attr_2(devattr)->index;
1678 int point = to_sensor_dev_attr_2(devattr)->nr;
1679 long val = simple_strtol(buf, NULL, 10) / 1000;
1680 val = SENSORS_LIMIT(val, 0, 255);
1681
1682 mutex_lock(&data->update_lock);
1683 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1684 data->pwm_auto_point_temp[pwm][point] = val;
1685 mutex_unlock(&data->update_lock);
1686
1687 return count;
1688}
1689
Hans de Goede45fb3662007-07-13 14:34:19 +02001690static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1691 char *buf)
1692{
Hans de Goede498be962009-01-07 16:37:28 +01001693 struct f71882fg_data *data = dev_get_drvdata(dev);
1694 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001695}
1696
Hans de Goedec13548c2009-01-07 16:37:27 +01001697static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1698 struct sensor_device_attribute_2 *attr, int count)
1699{
1700 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001701
Hans de Goedec13548c2009-01-07 16:37:27 +01001702 for (i = 0; i < count; i++) {
1703 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1704 if (err)
1705 return err;
1706 }
1707 return 0;
1708}
1709
1710static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001711{
1712 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001713 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001714 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001715 u8 start_reg;
1716
Hans de Goedec13548c2009-01-07 16:37:27 +01001717 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1718 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001719 return -ENOMEM;
1720
1721 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001722 data->type = sio_data->type;
Hans de Goede45fb3662007-07-13 14:34:19 +02001723 mutex_init(&data->update_lock);
1724 platform_set_drvdata(pdev, data);
1725
Hans de Goede3cc74752009-01-07 16:37:28 +01001726 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001727 if (start_reg & 0x04) {
1728 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1729 err = -ENODEV;
1730 goto exit_free;
1731 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001732 if (!(start_reg & 0x03)) {
1733 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1734 err = -ENODEV;
1735 goto exit_free;
1736 }
1737
Hans de Goede28ba8582009-01-07 16:37:31 +01001738 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goede3cc74752009-01-07 16:37:28 +01001739 /* If it is a 71862 and the fan / pwm part is enabled sanity check
1740 the pwm settings */
1741 if (data->type == f71862fg && (start_reg & 0x02)) {
Hans de Goede28ba8582009-01-07 16:37:31 +01001742 if ((data->pwm_enable & 0x15) != 0x15) {
Hans de Goede3cc74752009-01-07 16:37:28 +01001743 dev_err(&pdev->dev,
1744 "Invalid (reserved) pwm settings: 0x%02x\n",
Hans de Goede28ba8582009-01-07 16:37:31 +01001745 (unsigned int)data->pwm_enable);
Hans de Goede3cc74752009-01-07 16:37:28 +01001746 err = -ENODEV;
1747 goto exit_free;
1748 }
1749 }
1750
Hans de Goede45fb3662007-07-13 14:34:19 +02001751 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001752 err = device_create_file(&pdev->dev, &dev_attr_name);
1753 if (err)
1754 goto exit_unregister_sysfs;
1755
Hans de Goedec13548c2009-01-07 16:37:27 +01001756 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001757 switch (data->type) {
1758 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001759 err = f71882fg_create_sysfs_files(pdev,
1760 f71882fg_in_temp_attr,
1761 ARRAY_SIZE(f71882fg_in_temp_attr));
1762 if (err)
1763 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001764 /* fall through! */
1765 case f71862fg:
1766 err = f71882fg_create_sysfs_files(pdev,
1767 f718x2fg_in_temp_attr,
1768 ARRAY_SIZE(f718x2fg_in_temp_attr));
1769 break;
1770 case f8000:
1771 err = f71882fg_create_sysfs_files(pdev,
1772 f8000_in_temp_attr,
1773 ARRAY_SIZE(f8000_in_temp_attr));
1774 break;
Hans de Goede498be962009-01-07 16:37:28 +01001775 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001776 if (err)
1777 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001778 }
1779
Hans de Goede45fb3662007-07-13 14:34:19 +02001780 if (start_reg & 0x02) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001781 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1782 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001783 if (err)
1784 goto exit_unregister_sysfs;
1785
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001786 switch (data->type) {
1787 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001788 err = f71882fg_create_sysfs_files(pdev,
1789 f71862fg_fan_attr,
1790 ARRAY_SIZE(f71862fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001791 break;
1792 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001793 err = f71882fg_create_sysfs_files(pdev,
1794 f71882fg_fan_attr,
Hans de Goedec13548c2009-01-07 16:37:27 +01001795 ARRAY_SIZE(f71882fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001796 break;
1797 case f8000:
1798 err = f71882fg_create_sysfs_files(pdev,
1799 f8000_fan_attr,
1800 ARRAY_SIZE(f8000_fan_attr));
1801 break;
Hans de Goede498be962009-01-07 16:37:28 +01001802 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001803 if (err)
1804 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001805
1806 for (i = 0; i < nr_fans; i++)
1807 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1808 (data->pwm_enable & (1 << 2 * i)) ?
1809 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001810 }
1811
Tony Jones1beeffe2007-08-20 13:46:20 -07001812 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1813 if (IS_ERR(data->hwmon_dev)) {
1814 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001815 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001816 goto exit_unregister_sysfs;
1817 }
1818
1819 return 0;
1820
1821exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001822 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001823 return err; /* f71882fg_remove() also frees our data */
1824exit_free:
1825 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001826 return err;
1827}
1828
Hans de Goedec13548c2009-01-07 16:37:27 +01001829static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001830{
1831 int i;
1832 struct f71882fg_data *data = platform_get_drvdata(pdev);
1833
1834 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001835 if (data->hwmon_dev)
1836 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001837
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001838 /* Note we are not looping over all attr arrays we have as the ones
1839 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001840 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001841
Hans de Goede498be962009-01-07 16:37:28 +01001842 for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
1843 device_remove_file(&pdev->dev,
1844 &f718x2fg_in_temp_attr[i].dev_attr);
1845
Hans de Goede45fb3662007-07-13 14:34:19 +02001846 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1847 device_remove_file(&pdev->dev,
1848 &f71882fg_in_temp_attr[i].dev_attr);
1849
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001850 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
1851 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001852
Hans de Goede45fb3662007-07-13 14:34:19 +02001853 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1854 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1855
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001856 for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
1857 device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
1858
Hans de Goede45fb3662007-07-13 14:34:19 +02001859 kfree(data);
1860
1861 return 0;
1862}
1863
Hans de Goede498be962009-01-07 16:37:28 +01001864static int __init f71882fg_find(int sioaddr, unsigned short *address,
1865 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001866{
1867 int err = -ENODEV;
1868 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02001869
1870 superio_enter(sioaddr);
1871
1872 devid = superio_inw(sioaddr, SIO_REG_MANID);
1873 if (devid != SIO_FINTEK_ID) {
1874 printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
1875 goto exit;
1876 }
1877
Jean Delvare67b671b2007-12-06 23:13:42 +01001878 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01001879 switch (devid) {
1880 case SIO_F71862_ID:
1881 sio_data->type = f71862fg;
1882 break;
1883 case SIO_F71882_ID:
1884 sio_data->type = f71882fg;
1885 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001886 case SIO_F8000_ID:
1887 sio_data->type = f8000;
1888 break;
Hans de Goede498be962009-01-07 16:37:28 +01001889 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02001890 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
1891 goto exit;
1892 }
1893
1894 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001895 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001896 printk(KERN_WARNING DRVNAME ": Device not activated\n");
1897 goto exit;
1898 }
1899
1900 *address = superio_inw(sioaddr, SIO_REG_ADDR);
1901 if (*address == 0)
1902 {
1903 printk(KERN_WARNING DRVNAME ": Base address not set\n");
1904 goto exit;
1905 }
1906 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
1907
Hans de Goede45fb3662007-07-13 14:34:19 +02001908 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01001909 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
1910 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02001911 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
1912exit:
1913 superio_exit(sioaddr);
1914 return err;
1915}
1916
Hans de Goede498be962009-01-07 16:37:28 +01001917static int __init f71882fg_device_add(unsigned short address,
1918 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001919{
1920 struct resource res = {
1921 .start = address,
1922 .end = address + REGION_LENGTH - 1,
1923 .flags = IORESOURCE_IO,
1924 };
1925 int err;
1926
1927 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001928 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001929 return -ENOMEM;
1930
1931 res.name = f71882fg_pdev->name;
1932 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001933 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001934 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
1935 goto exit_device_put;
1936 }
1937
Hans de Goede498be962009-01-07 16:37:28 +01001938 err = platform_device_add_data(f71882fg_pdev, sio_data,
1939 sizeof(struct f71882fg_sio_data));
1940 if (err) {
1941 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1942 goto exit_device_put;
1943 }
1944
Hans de Goede45fb3662007-07-13 14:34:19 +02001945 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001946 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001947 printk(KERN_ERR DRVNAME ": Device addition failed\n");
1948 goto exit_device_put;
1949 }
1950
1951 return 0;
1952
1953exit_device_put:
1954 platform_device_put(f71882fg_pdev);
1955
1956 return err;
1957}
1958
1959static int __init f71882fg_init(void)
1960{
1961 int err = -ENODEV;
1962 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01001963 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02001964
Hans de Goede498be962009-01-07 16:37:28 +01001965 memset(&sio_data, 0, sizeof(sio_data));
1966
1967 if (f71882fg_find(0x2e, &address, &sio_data) &&
1968 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02001969 goto exit;
1970
Hans de Goedec13548c2009-01-07 16:37:27 +01001971 err = platform_driver_register(&f71882fg_driver);
1972 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001973 goto exit;
1974
Hans de Goede498be962009-01-07 16:37:28 +01001975 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01001976 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001977 goto exit_driver;
1978
1979 return 0;
1980
1981exit_driver:
1982 platform_driver_unregister(&f71882fg_driver);
1983exit:
1984 return err;
1985}
1986
1987static void __exit f71882fg_exit(void)
1988{
1989 platform_device_unregister(f71882fg_pdev);
1990 platform_driver_unregister(&f71882fg_driver);
1991}
1992
1993MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01001994MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02001995MODULE_LICENSE("GPL");
1996
1997module_init(f71882fg_init);
1998module_exit(f71882fg_exit);