blob: 593ed2a0555c8c87cd2d772f5e8bc6728bd88763 [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 */
46#define SIO_F71882_ID 0x0541 /* Chipset ID */
47
48#define REGION_LENGTH 8
49#define ADDR_REG_OFFSET 5
50#define DATA_REG_OFFSET 6
51
52#define F71882FG_REG_PECI 0x0A
53
54#define F71882FG_REG_IN_STATUS 0x12
55#define F71882FG_REG_IN_BEEP 0x13
56#define F71882FG_REG_IN(nr) (0x20 + (nr))
57#define F71882FG_REG_IN1_HIGH 0x32
58
59#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010060#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
61#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_FAN_STATUS 0x92
63#define F71882FG_REG_FAN_BEEP 0x93
64
65#define F71882FG_REG_TEMP(nr) (0x72 + 2 * (nr))
66#define F71882FG_REG_TEMP_OVT(nr) (0x82 + 2 * (nr))
67#define F71882FG_REG_TEMP_HIGH(nr) (0x83 + 2 * (nr))
68#define F71882FG_REG_TEMP_STATUS 0x62
69#define F71882FG_REG_TEMP_BEEP 0x63
70#define F71882FG_REG_TEMP_HYST1 0x6C
71#define F71882FG_REG_TEMP_HYST23 0x6D
72#define F71882FG_REG_TEMP_TYPE 0x6B
73#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
74
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010075#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
76#define F71882FG_REG_PWM_TYPE 0x94
77#define F71882FG_REG_PWM_ENABLE 0x96
78
79#define F71882FG_REG_FAN_HYST0 0x98
80#define F71882FG_REG_FAN_HYST1 0x99
81
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
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010094static int fan_mode[4] = { 0, 0, 0, 0 };
95module_param_array(fan_mode, int, NULL, 0644);
96MODULE_PARM_DESC(fan_mode, "List of fan control modes (f71882fg only) "
97 "(0=don't change, 1=pwm, 2=rpm)\n"
98 "Note: this needs a write to pwm#_enable to take effect");
99
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100100static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200101
102/* Super-I/O Function prototypes */
103static inline int superio_inb(int base, int reg);
104static inline int superio_inw(int base, int reg);
105static inline void superio_enter(int base);
106static inline void superio_select(int base, int ld);
107static inline void superio_exit(int base);
108
Hans de Goede45fb3662007-07-13 14:34:19 +0200109struct f71882fg_data {
110 unsigned short addr;
Tony Jones1beeffe2007-08-20 13:46:20 -0700111 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200112
113 struct mutex update_lock;
114 char valid; /* !=0 if following fields are valid */
115 unsigned long last_updated; /* In jiffies */
116 unsigned long last_limits; /* In jiffies */
117
118 /* Register Values */
119 u8 in[9];
120 u8 in1_max;
121 u8 in_status;
122 u8 in_beep;
123 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100124 u16 fan_target[4];
125 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200126 u8 fan_status;
127 u8 fan_beep;
128 u8 temp[3];
129 u8 temp_ovt[3];
130 u8 temp_high[3];
131 u8 temp_hyst[3];
132 u8 temp_type[3];
133 u8 temp_status;
134 u8 temp_beep;
135 u8 temp_diode_open;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100136 u8 pwm[4];
137 u8 pwm_enable;
138 u8 pwm_auto_point_hyst[2];
139 u8 pwm_auto_point_mapping[4];
140 u8 pwm_auto_point_pwm[4][5];
141 u8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200142};
143
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100144/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200145static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
146 char *buf);
147static ssize_t show_in_max(struct device *dev, struct device_attribute
148 *devattr, char *buf);
149static ssize_t store_in_max(struct device *dev, struct device_attribute
150 *devattr, const char *buf, size_t count);
151static ssize_t show_in_beep(struct device *dev, struct device_attribute
152 *devattr, char *buf);
153static ssize_t store_in_beep(struct device *dev, struct device_attribute
154 *devattr, const char *buf, size_t count);
155static ssize_t show_in_alarm(struct device *dev, struct device_attribute
156 *devattr, char *buf);
157/* Sysfs Fan */
158static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
159 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100160static ssize_t show_fan_full_speed(struct device *dev,
161 struct device_attribute *devattr, char *buf);
162static ssize_t store_fan_full_speed(struct device *dev,
163 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200164static ssize_t show_fan_beep(struct device *dev, struct device_attribute
165 *devattr, char *buf);
166static ssize_t store_fan_beep(struct device *dev, struct device_attribute
167 *devattr, const char *buf, size_t count);
168static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
169 *devattr, char *buf);
170/* Sysfs Temp */
171static ssize_t show_temp(struct device *dev, struct device_attribute
172 *devattr, char *buf);
173static ssize_t show_temp_max(struct device *dev, struct device_attribute
174 *devattr, char *buf);
175static ssize_t store_temp_max(struct device *dev, struct device_attribute
176 *devattr, const char *buf, size_t count);
177static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
178 *devattr, char *buf);
179static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
180 *devattr, const char *buf, size_t count);
181static ssize_t show_temp_crit(struct device *dev, struct device_attribute
182 *devattr, char *buf);
183static ssize_t store_temp_crit(struct device *dev, struct device_attribute
184 *devattr, const char *buf, size_t count);
185static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
186 *devattr, char *buf);
187static ssize_t show_temp_type(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189static ssize_t show_temp_beep(struct device *dev, struct device_attribute
190 *devattr, char *buf);
191static ssize_t store_temp_beep(struct device *dev, struct device_attribute
192 *devattr, const char *buf, size_t count);
193static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
194 *devattr, char *buf);
195static ssize_t show_temp_fault(struct device *dev, struct device_attribute
196 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100197/* PWM and Auto point control */
198static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
199 char *buf);
200static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
201 const char *buf, size_t count);
202static ssize_t show_pwm_enable(struct device *dev,
203 struct device_attribute *devattr, char *buf);
204static ssize_t store_pwm_enable(struct device *dev,
205 struct device_attribute *devattr, const char *buf, size_t count);
206static ssize_t show_pwm_interpolate(struct device *dev,
207 struct device_attribute *devattr, char *buf);
208static ssize_t store_pwm_interpolate(struct device *dev,
209 struct device_attribute *devattr, const char *buf, size_t count);
210static ssize_t show_pwm_auto_point_channel(struct device *dev,
211 struct device_attribute *devattr, char *buf);
212static ssize_t store_pwm_auto_point_channel(struct device *dev,
213 struct device_attribute *devattr, const char *buf, size_t count);
214static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
215 struct device_attribute *devattr, char *buf);
216static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
217 struct device_attribute *devattr, const char *buf, size_t count);
218static ssize_t show_pwm_auto_point_pwm(struct device *dev,
219 struct device_attribute *devattr, char *buf);
220static ssize_t store_pwm_auto_point_pwm(struct device *dev,
221 struct device_attribute *devattr, const char *buf, size_t count);
222static ssize_t show_pwm_auto_point_temp(struct device *dev,
223 struct device_attribute *devattr, char *buf);
224static ssize_t store_pwm_auto_point_temp(struct device *dev,
225 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200226/* Sysfs misc */
227static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
228 char *buf);
229
230static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100231static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200232
233static struct platform_driver f71882fg_driver = {
234 .driver = {
235 .owner = THIS_MODULE,
236 .name = DRVNAME,
237 },
238 .probe = f71882fg_probe,
239 .remove = __devexit_p(f71882fg_remove),
240};
241
Hans de Goedec13548c2009-01-07 16:37:27 +0100242static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200243
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100244static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = {
245 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
246 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
247 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
248 0, 1),
249 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
250 0, 1),
251 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
252 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
253 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
254 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
255 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
256 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
257 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
258 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
259 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
260 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
261 store_temp_max, 0, 0),
262 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
263 store_temp_max_hyst, 0, 0),
264 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
265 store_temp_crit, 0, 0),
266 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
267 0, 0),
268 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 0),
269 SENSOR_ATTR_2(temp1_beep, S_IRUGO|S_IWUSR, show_temp_beep,
270 store_temp_beep, 0, 0),
271 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
272 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
273 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
274 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
275 store_temp_max, 0, 1),
276 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
277 store_temp_max_hyst, 0, 1),
278 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
279 store_temp_crit, 0, 1),
280 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
281 0, 1),
282 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
283 SENSOR_ATTR_2(temp2_beep, S_IRUGO|S_IWUSR, show_temp_beep,
284 store_temp_beep, 0, 1),
285 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
286 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
287 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
288 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
289 store_temp_max, 0, 2),
290 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
291 store_temp_max_hyst, 0, 2),
292 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
293 store_temp_crit, 0, 2),
294 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
295 0, 2),
296 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 2),
297 SENSOR_ATTR_2(temp3_beep, S_IRUGO|S_IWUSR, show_temp_beep,
298 store_temp_beep, 0, 2),
299 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
300 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede45fb3662007-07-13 14:34:19 +0200301};
302
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100303static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
304 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100305 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
306 show_fan_full_speed,
307 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100308 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
309 store_fan_beep, 0, 0),
310 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
311 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100312 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
313 show_fan_full_speed,
314 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100315 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
316 store_fan_beep, 0, 1),
317 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
318 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100319 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
320 show_fan_full_speed,
321 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100322 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
323 store_fan_beep, 0, 2),
324 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
325 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100326 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
327 show_fan_full_speed,
328 store_fan_full_speed, 0, 3),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100329 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
330 store_fan_beep, 0, 3),
331 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100332
333 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
334 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
335 store_pwm_enable, 0, 0),
336 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
337 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
338 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
339 show_pwm_auto_point_channel,
340 store_pwm_auto_point_channel, 0, 0),
341 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
342 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
343 0, 0),
344 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
345 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
346 1, 0),
347 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
348 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
349 2, 0),
350 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
351 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
352 3, 0),
353 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
354 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
355 4, 0),
356 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
357 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
358 0, 0),
359 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
360 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
361 1, 0),
362 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
363 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
364 2, 0),
365 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
366 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
367 3, 0),
368 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
369 show_pwm_auto_point_temp_hyst,
370 store_pwm_auto_point_temp_hyst,
371 0, 0),
372 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
373 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
374 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
375 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
376 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
377 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
378
379 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
380 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
381 store_pwm_enable, 0, 1),
382 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
383 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
384 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
385 show_pwm_auto_point_channel,
386 store_pwm_auto_point_channel, 0, 1),
387 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
388 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
389 0, 1),
390 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
391 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
392 1, 1),
393 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
394 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
395 2, 1),
396 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
397 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
398 3, 1),
399 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
400 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
401 4, 1),
402 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
403 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
404 0, 1),
405 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
406 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
407 1, 1),
408 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
409 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
410 2, 1),
411 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
412 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
413 3, 1),
414 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
415 show_pwm_auto_point_temp_hyst,
416 store_pwm_auto_point_temp_hyst,
417 0, 1),
418 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
419 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
420 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
421 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
422 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
423 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
424
425 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
426 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
427 store_pwm_enable, 0, 2),
428 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
429 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
430 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
431 show_pwm_auto_point_channel,
432 store_pwm_auto_point_channel, 0, 2),
433 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
434 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
435 0, 2),
436 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
437 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
438 1, 2),
439 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
440 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
441 2, 2),
442 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
443 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
444 3, 2),
445 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
446 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
447 4, 2),
448 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
449 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
450 0, 2),
451 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
452 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
453 1, 2),
454 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
455 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
456 2, 2),
457 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
458 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
459 3, 2),
460 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
461 show_pwm_auto_point_temp_hyst,
462 store_pwm_auto_point_temp_hyst,
463 0, 2),
464 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
465 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
466 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
467 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
468 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
469 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
470
471 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
472 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
473 store_pwm_enable, 0, 3),
474 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
475 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
476 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
477 show_pwm_auto_point_channel,
478 store_pwm_auto_point_channel, 0, 3),
479 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
480 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
481 0, 3),
482 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
483 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
484 1, 3),
485 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
486 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
487 2, 3),
488 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
489 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
490 3, 3),
491 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
492 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
493 4, 3),
494 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
495 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
496 0, 3),
497 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
498 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
499 1, 3),
500 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
501 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
502 2, 3),
503 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
504 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
505 3, 3),
506 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
507 show_pwm_auto_point_temp_hyst,
508 store_pwm_auto_point_temp_hyst,
509 0, 3),
510 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
511 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
512 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
513 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
514 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
515 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200516};
517
518
519/* Super I/O functions */
520static inline int superio_inb(int base, int reg)
521{
522 outb(reg, base);
523 return inb(base + 1);
524}
525
526static int superio_inw(int base, int reg)
527{
528 int val;
529 outb(reg++, base);
530 val = inb(base + 1) << 8;
531 outb(reg, base);
532 val |= inb(base + 1);
533 return val;
534}
535
536static inline void superio_enter(int base)
537{
538 /* according to the datasheet the key must be send twice! */
539 outb( SIO_UNLOCK_KEY, base);
540 outb( SIO_UNLOCK_KEY, base);
541}
542
543static inline void superio_select( int base, int ld)
544{
545 outb(SIO_REG_LDSEL, base);
546 outb(ld, base + 1);
547}
548
549static inline void superio_exit(int base)
550{
551 outb(SIO_LOCK_KEY, base);
552}
553
554static inline u16 fan_from_reg(u16 reg)
555{
556 return reg ? (1500000 / reg) : 0;
557}
558
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100559static inline u16 fan_to_reg(u16 fan)
560{
561 return fan ? (1500000 / fan) : 0;
562}
563
Hans de Goede45fb3662007-07-13 14:34:19 +0200564static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
565{
566 u8 val;
567
568 outb(reg, data->addr + ADDR_REG_OFFSET);
569 val = inb(data->addr + DATA_REG_OFFSET);
570
571 return val;
572}
573
574static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
575{
576 u16 val;
577
578 outb(reg++, data->addr + ADDR_REG_OFFSET);
579 val = inb(data->addr + DATA_REG_OFFSET) << 8;
580 outb(reg, data->addr + ADDR_REG_OFFSET);
581 val |= inb(data->addr + DATA_REG_OFFSET);
582
583 return val;
584}
585
586static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
587{
588 outb(reg, data->addr + ADDR_REG_OFFSET);
589 outb(val, data->addr + DATA_REG_OFFSET);
590}
591
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100592static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
593{
594 outb(reg++, data->addr + ADDR_REG_OFFSET);
595 outb(val >> 8, data->addr + DATA_REG_OFFSET);
596 outb(reg, data->addr + ADDR_REG_OFFSET);
597 outb(val & 255, data->addr + DATA_REG_OFFSET);
598}
599
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100600static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200601{
602 struct f71882fg_data *data = dev_get_drvdata(dev);
603 int nr, reg, reg2;
604
605 mutex_lock(&data->update_lock);
606
607 /* Update once every 60 seconds */
608 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
609 !data->valid) {
610 data->in1_max = f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
611 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
612
613 /* Get High & boundary temps*/
614 for (nr = 0; nr < 3; nr++) {
615 data->temp_ovt[nr] = f71882fg_read8(data,
616 F71882FG_REG_TEMP_OVT(nr));
617 data->temp_high[nr] = f71882fg_read8(data,
618 F71882FG_REG_TEMP_HIGH(nr));
619 }
620
621 /* Have to hardcode hyst*/
622 data->temp_hyst[0] = f71882fg_read8(data,
623 F71882FG_REG_TEMP_HYST1) >> 4;
624 /* Hyst temps 2 & 3 stored in same register */
625 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST23);
626 data->temp_hyst[1] = reg & 0x0F;
627 data->temp_hyst[2] = reg >> 4;
628
629 /* Have to hardcode type, because temp1 is special */
630 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
631 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
632 if ((reg2 & 0x03) == 0x01)
633 data->temp_type[0] = 6 /* PECI */;
634 else if ((reg2 & 0x03) == 0x02)
635 data->temp_type[0] = 5 /* AMDSI */;
636 else
637 data->temp_type[0] = (reg & 0x02) ? 2 : 4;
638
639 data->temp_type[1] = (reg & 0x04) ? 2 : 4;
640 data->temp_type[2] = (reg & 0x08) ? 2 : 4;
641
642 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
643
644 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
645
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100646 data->pwm_enable = f71882fg_read8(data,
647 F71882FG_REG_PWM_ENABLE);
648 data->pwm_auto_point_hyst[0] = f71882fg_read8(data,
649 F71882FG_REG_FAN_HYST0);
650 data->pwm_auto_point_hyst[1] = f71882fg_read8(data,
651 F71882FG_REG_FAN_HYST1);
652 for (nr = 0; nr < 4; nr++) {
653 int point;
654
655 data->pwm_auto_point_mapping[nr] =
656 f71882fg_read8(data,
657 F71882FG_REG_POINT_MAPPING(nr));
658
659 for (point = 0; point < 5; point++) {
660 data->pwm_auto_point_pwm[nr][point] =
661 f71882fg_read8(data,
662 F71882FG_REG_POINT_PWM
663 (nr, point));
664 }
665 for (point = 0; point < 4; point++) {
666 data->pwm_auto_point_temp[nr][point] =
667 f71882fg_read8(data,
668 F71882FG_REG_POINT_TEMP
669 (nr, point));
670 }
671 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200672 data->last_limits = jiffies;
673 }
674
675 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400676 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200677 data->temp_status = f71882fg_read8(data,
678 F71882FG_REG_TEMP_STATUS);
679 data->temp_diode_open = f71882fg_read8(data,
680 F71882FG_REG_TEMP_DIODE_OPEN);
681 for (nr = 0; nr < 3; nr++)
682 data->temp[nr] = f71882fg_read8(data,
683 F71882FG_REG_TEMP(nr));
684
685 data->fan_status = f71882fg_read8(data,
686 F71882FG_REG_FAN_STATUS);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100687 for (nr = 0; nr < 4; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200688 data->fan[nr] = f71882fg_read16(data,
689 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100690 data->fan_target[nr] =
691 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
692 data->fan_full_speed[nr] =
693 f71882fg_read16(data,
694 F71882FG_REG_FAN_FULL_SPEED(nr));
695 data->pwm[nr] =
696 f71882fg_read8(data, F71882FG_REG_PWM(nr));
697 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200698
699 data->in_status = f71882fg_read8(data,
700 F71882FG_REG_IN_STATUS);
701 for (nr = 0; nr < 9; nr++)
702 data->in[nr] = f71882fg_read8(data,
703 F71882FG_REG_IN(nr));
704
705 data->last_updated = jiffies;
706 data->valid = 1;
707 }
708
709 mutex_unlock(&data->update_lock);
710
711 return data;
712}
713
714/* Sysfs Interface */
715static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
716 char *buf)
717{
718 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100719 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200720 int speed = fan_from_reg(data->fan[nr]);
721
722 if (speed == FAN_MIN_DETECT)
723 speed = 0;
724
725 return sprintf(buf, "%d\n", speed);
726}
727
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100728static ssize_t show_fan_full_speed(struct device *dev,
729 struct device_attribute *devattr, char *buf)
730{
731 struct f71882fg_data *data = f71882fg_update_device(dev);
732 int nr = to_sensor_dev_attr_2(devattr)->index;
733 int speed = fan_from_reg(data->fan_full_speed[nr]);
734 return sprintf(buf, "%d\n", speed);
735}
736
737static ssize_t store_fan_full_speed(struct device *dev,
738 struct device_attribute *devattr,
739 const char *buf, size_t count)
740{
741 struct f71882fg_data *data = dev_get_drvdata(dev);
742 int nr = to_sensor_dev_attr_2(devattr)->index;
743 long val = simple_strtol(buf, NULL, 10);
744
745 val = SENSORS_LIMIT(val, 23, 1500000);
746 val = fan_to_reg(val);
747
748 mutex_lock(&data->update_lock);
749 if (data->pwm_enable & (1 << (2 * nr)))
750 /* PWM mode */
751 count = -EINVAL;
752 else {
753 /* RPM mode */
754 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
755 data->fan_full_speed[nr] = val;
756 }
757 mutex_unlock(&data->update_lock);
758
759 return count;
760}
761
Hans de Goede45fb3662007-07-13 14:34:19 +0200762static ssize_t show_fan_beep(struct device *dev, struct device_attribute
763 *devattr, char *buf)
764{
765 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100766 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200767
768 if (data->fan_beep & (1 << nr))
769 return sprintf(buf, "1\n");
770 else
771 return sprintf(buf, "0\n");
772}
773
774static ssize_t store_fan_beep(struct device *dev, struct device_attribute
775 *devattr, const char *buf, size_t count)
776{
777 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100778 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200779 int val = simple_strtoul(buf, NULL, 10);
780
781 mutex_lock(&data->update_lock);
782 if (val)
783 data->fan_beep |= 1 << nr;
784 else
785 data->fan_beep &= ~(1 << nr);
786
787 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
788 mutex_unlock(&data->update_lock);
789
790 return count;
791}
792
793static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
794 *devattr, char *buf)
795{
796 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100797 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200798
799 if (data->fan_status & (1 << nr))
800 return sprintf(buf, "1\n");
801 else
802 return sprintf(buf, "0\n");
803}
804
805static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
806 char *buf)
807{
808 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100809 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200810
811 return sprintf(buf, "%d\n", data->in[nr] * 8);
812}
813
814static ssize_t show_in_max(struct device *dev, struct device_attribute
815 *devattr, char *buf)
816{
817 struct f71882fg_data *data = f71882fg_update_device(dev);
818
819 return sprintf(buf, "%d\n", data->in1_max * 8);
820}
821
822static ssize_t store_in_max(struct device *dev, struct device_attribute
823 *devattr, const char *buf, size_t count)
824{
825 struct f71882fg_data *data = dev_get_drvdata(dev);
826 int val = simple_strtoul(buf, NULL, 10) / 8;
827
828 if (val > 255)
829 val = 255;
830
831 mutex_lock(&data->update_lock);
832 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
833 data->in1_max = val;
834 mutex_unlock(&data->update_lock);
835
836 return count;
837}
838
839static ssize_t show_in_beep(struct device *dev, struct device_attribute
840 *devattr, char *buf)
841{
842 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100843 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200844
845 if (data->in_beep & (1 << nr))
846 return sprintf(buf, "1\n");
847 else
848 return sprintf(buf, "0\n");
849}
850
851static ssize_t store_in_beep(struct device *dev, struct device_attribute
852 *devattr, const char *buf, size_t count)
853{
854 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100855 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200856 int val = simple_strtoul(buf, NULL, 10);
857
858 mutex_lock(&data->update_lock);
859 if (val)
860 data->in_beep |= 1 << nr;
861 else
862 data->in_beep &= ~(1 << nr);
863
864 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
865 mutex_unlock(&data->update_lock);
866
867 return count;
868}
869
870static ssize_t show_in_alarm(struct device *dev, struct device_attribute
871 *devattr, char *buf)
872{
873 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100874 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200875
876 if (data->in_status & (1 << nr))
877 return sprintf(buf, "1\n");
878 else
879 return sprintf(buf, "0\n");
880}
881
882static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
883 char *buf)
884{
885 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100886 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200887
888 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
889}
890
891static ssize_t show_temp_max(struct device *dev, struct device_attribute
892 *devattr, char *buf)
893{
894 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100895 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200896
897 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
898}
899
900static ssize_t store_temp_max(struct device *dev, struct device_attribute
901 *devattr, const char *buf, size_t count)
902{
903 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100904 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200905 int val = simple_strtoul(buf, NULL, 10) / 1000;
906
907 if (val > 255)
908 val = 255;
909
910 mutex_lock(&data->update_lock);
911 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
912 data->temp_high[nr] = val;
913 mutex_unlock(&data->update_lock);
914
915 return count;
916}
917
918static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
919 *devattr, char *buf)
920{
921 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100922 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200923
924 return sprintf(buf, "%d\n",
925 (data->temp_high[nr] - data->temp_hyst[nr]) * 1000);
926}
927
928static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
929 *devattr, const char *buf, size_t count)
930{
931 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100932 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200933 int val = simple_strtoul(buf, NULL, 10) / 1000;
934 ssize_t ret = count;
935
936 mutex_lock(&data->update_lock);
937
938 /* convert abs to relative and check */
939 val = data->temp_high[nr] - val;
940 if (val < 0 || val > 15) {
941 ret = -EINVAL;
942 goto store_temp_max_hyst_exit;
943 }
944
945 data->temp_hyst[nr] = val;
946
947 /* convert value to register contents */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400948 switch (nr) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200949 case 0:
950 val = val << 4;
951 break;
952 case 1:
953 val = val | (data->temp_hyst[2] << 4);
954 break;
955 case 2:
956 val = data->temp_hyst[1] | (val << 4);
957 break;
958 }
959
960 f71882fg_write8(data, nr ? F71882FG_REG_TEMP_HYST23 :
961 F71882FG_REG_TEMP_HYST1, val);
962
963store_temp_max_hyst_exit:
964 mutex_unlock(&data->update_lock);
965 return ret;
966}
967
968static ssize_t show_temp_crit(struct device *dev, struct device_attribute
969 *devattr, char *buf)
970{
971 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100972 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200973
974 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
975}
976
977static ssize_t store_temp_crit(struct device *dev, struct device_attribute
978 *devattr, const char *buf, size_t count)
979{
980 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100981 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +0200982 int val = simple_strtoul(buf, NULL, 10) / 1000;
983
984 if (val > 255)
985 val = 255;
986
987 mutex_lock(&data->update_lock);
988 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
989 data->temp_ovt[nr] = val;
990 mutex_unlock(&data->update_lock);
991
992 return count;
993}
994
995static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
996 *devattr, char *buf)
997{
998 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100999 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001000
1001 return sprintf(buf, "%d\n",
1002 (data->temp_ovt[nr] - data->temp_hyst[nr]) * 1000);
1003}
1004
1005static ssize_t show_temp_type(struct device *dev, struct device_attribute
1006 *devattr, char *buf)
1007{
1008 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001009 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001010
1011 return sprintf(buf, "%d\n", data->temp_type[nr]);
1012}
1013
1014static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1015 *devattr, char *buf)
1016{
1017 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001018 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001019
1020 if (data->temp_beep & (1 << (nr + 1)))
1021 return sprintf(buf, "1\n");
1022 else
1023 return sprintf(buf, "0\n");
1024}
1025
1026static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1027 *devattr, const char *buf, size_t count)
1028{
1029 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001030 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001031 int val = simple_strtoul(buf, NULL, 10);
1032
1033 mutex_lock(&data->update_lock);
1034 if (val)
1035 data->temp_beep |= 1 << (nr + 1);
1036 else
1037 data->temp_beep &= ~(1 << (nr + 1));
1038
1039 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1040 mutex_unlock(&data->update_lock);
1041
1042 return count;
1043}
1044
1045static ssize_t show_temp_alarm(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->temp_status & (1 << (nr + 1)))
1052 return sprintf(buf, "1\n");
1053 else
1054 return sprintf(buf, "0\n");
1055}
1056
1057static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1058 *devattr, char *buf)
1059{
1060 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001061 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001062
1063 if (data->temp_diode_open & (1 << (nr + 1)))
1064 return sprintf(buf, "1\n");
1065 else
1066 return sprintf(buf, "0\n");
1067}
1068
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001069static ssize_t show_pwm(struct device *dev,
1070 struct device_attribute *devattr, char *buf)
1071{
1072 struct f71882fg_data *data = f71882fg_update_device(dev);
1073 int val, nr = to_sensor_dev_attr_2(devattr)->index;
1074 if (data->pwm_enable & (1 << (2 * nr)))
1075 /* PWM mode */
1076 val = data->pwm[nr];
1077 else {
1078 /* RPM mode */
1079 mutex_lock(&data->update_lock);
1080 val = 255 * fan_from_reg(data->fan_target[nr])
1081 / fan_from_reg(data->fan_full_speed[nr]);
1082 mutex_unlock(&data->update_lock);
1083 }
1084 return sprintf(buf, "%d\n", val);
1085}
1086
1087static ssize_t store_pwm(struct device *dev,
1088 struct device_attribute *devattr, const char *buf,
1089 size_t count)
1090{
1091 /* struct f71882fg_data *data = dev_get_drvdata(dev); */
1092 struct f71882fg_data *data = f71882fg_update_device(dev);
1093 int nr = to_sensor_dev_attr_2(devattr)->index;
1094 long val = simple_strtol(buf, NULL, 10);
1095 val = SENSORS_LIMIT(val, 0, 255);
1096
1097 mutex_lock(&data->update_lock);
1098 if (data->pwm_enable & (1 << (2 * nr))) {
1099 /* PWM mode */
1100 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1101 data->pwm[nr] = val;
1102 } else {
1103 /* RPM mode */
1104 int target = val * fan_from_reg(data->fan_full_speed[nr]) / 255;
1105 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr),
1106 fan_to_reg(target));
1107 data->fan_target[nr] = fan_to_reg(target);
1108 }
1109 mutex_unlock(&data->update_lock);
1110
1111 return count;
1112}
1113
1114static ssize_t show_pwm_enable(struct device *dev,
1115 struct device_attribute *devattr, char *buf)
1116{
1117 int result;
1118 struct f71882fg_data *data = f71882fg_update_device(dev);
1119 int nr = to_sensor_dev_attr_2(devattr)->index;
1120
1121 if (data->pwm_enable & (2 << (2 * nr)))
1122 result = 1;
1123 else
1124 result = 2;
1125
1126 return sprintf(buf, "%d\n", result);
1127}
1128
1129static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1130 *devattr, const char *buf, size_t count)
1131{
1132 struct f71882fg_data *data = dev_get_drvdata(dev);
1133 int nr = to_sensor_dev_attr_2(devattr)->index;
1134 long val = simple_strtol(buf, NULL, 10);
1135 if (val < 1 || val > 2)
1136 return -EINVAL;
1137
1138 mutex_lock(&data->update_lock);
1139 switch (val) {
1140 case 1:
1141 data->pwm_enable |= 2 << (2 * nr);
1142 break; /* Manual */
1143 case 2:
1144 data->pwm_enable &= ~(2 << (2 * nr));
1145 break; /* Temperature ctrl */
1146 }
1147 switch (fan_mode[nr]) {
1148 case 1:
1149 data->pwm_enable |= 1 << (2 * nr);
1150 break; /* Duty cycle mode */
1151 case 2:
1152 data->pwm_enable &= ~(1 << (2 * nr));
1153 break; /* RPM mode */
1154 }
1155 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
1156 mutex_unlock(&data->update_lock);
1157
1158 return count;
1159}
1160
1161static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1162 struct device_attribute *devattr,
1163 char *buf)
1164{
1165 int result;
1166 struct f71882fg_data *data = f71882fg_update_device(dev);
1167 int pwm = to_sensor_dev_attr_2(devattr)->index;
1168 int point = to_sensor_dev_attr_2(devattr)->nr;
1169
1170 if (data->pwm_enable & (1 << (2 * pwm))) {
1171 /* PWM mode */
1172 result = data->pwm_auto_point_pwm[pwm][point];
1173 } else {
1174 /* RPM mode */
1175 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1176 }
1177
1178 return sprintf(buf, "%d\n", result);
1179}
1180
1181static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1182 struct device_attribute *devattr,
1183 const char *buf, size_t count)
1184{
1185 /* struct f71882fg_data *data = dev_get_drvdata(dev); */
1186 struct f71882fg_data *data = f71882fg_update_device(dev);
1187 int pwm = to_sensor_dev_attr_2(devattr)->index;
1188 int point = to_sensor_dev_attr_2(devattr)->nr;
1189 int val = simple_strtoul(buf, NULL, 10);
1190 val = SENSORS_LIMIT(val, 0, 255);
1191
1192 mutex_lock(&data->update_lock);
1193 if (data->pwm_enable & (1 << (2 * pwm))) {
1194 /* PWM mode */
1195 } else {
1196 /* RPM mode */
1197 if (val < 29) /* Prevent negative numbers */
1198 val = 255;
1199 else
1200 val = (255 - val) * 32 / val;
1201 }
1202 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1203 data->pwm_auto_point_pwm[pwm][point] = val;
1204 mutex_unlock(&data->update_lock);
1205
1206 return count;
1207}
1208
1209static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1210 struct device_attribute *devattr,
1211 char *buf)
1212{
1213 int result = 0;
1214 struct f71882fg_data *data = f71882fg_update_device(dev);
1215 int nr = to_sensor_dev_attr_2(devattr)->index;
1216 int point = to_sensor_dev_attr_2(devattr)->nr;
1217
1218 mutex_lock(&data->update_lock);
1219 switch (nr) {
1220 case 0:
1221 result = data->pwm_auto_point_hyst[0] & 0x0f;
1222 break;
1223 case 1:
1224 result = data->pwm_auto_point_hyst[0] >> 4;
1225 break;
1226 case 2:
1227 result = data->pwm_auto_point_hyst[1] & 0x0f;
1228 break;
1229 case 3:
1230 result = data->pwm_auto_point_hyst[1] >> 4;
1231 break;
1232 }
1233 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1234 mutex_unlock(&data->update_lock);
1235
1236 return sprintf(buf, "%d\n", result);
1237}
1238
1239static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1240 struct device_attribute *devattr,
1241 const char *buf, size_t count)
1242{
1243 struct f71882fg_data *data = f71882fg_update_device(dev);
1244 int nr = to_sensor_dev_attr_2(devattr)->index;
1245 int point = to_sensor_dev_attr_2(devattr)->nr;
1246 long val = simple_strtol(buf, NULL, 10) / 1000;
1247
1248 mutex_lock(&data->update_lock);
1249 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1250 data->pwm_auto_point_temp[nr][point]);
1251 val = data->pwm_auto_point_temp[nr][point] - val;
1252
1253 switch (nr) {
1254 case 0:
1255 val = (data->pwm_auto_point_hyst[0] & 0xf0) | val;
1256 break;
1257 case 1:
1258 val = (data->pwm_auto_point_hyst[0] & 0x0f) | (val << 4);
1259 break;
1260 case 2:
1261 val = (data->pwm_auto_point_hyst[1] & 0xf0) | val;
1262 break;
1263 case 3:
1264 val = (data->pwm_auto_point_hyst[1] & 0x0f) | (val << 4);
1265 break;
1266 }
1267 if (nr == 0 || nr == 1) {
1268 f71882fg_write8(data, F71882FG_REG_FAN_HYST0, val);
1269 data->pwm_auto_point_hyst[0] = val;
1270 } else {
1271 f71882fg_write8(data, F71882FG_REG_FAN_HYST1, val);
1272 data->pwm_auto_point_hyst[1] = val;
1273 }
1274 mutex_unlock(&data->update_lock);
1275
1276 return count;
1277}
1278
1279static ssize_t show_pwm_interpolate(struct device *dev,
1280 struct device_attribute *devattr, char *buf)
1281{
1282 int result;
1283 struct f71882fg_data *data = f71882fg_update_device(dev);
1284 int nr = to_sensor_dev_attr_2(devattr)->index;
1285
1286 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1287
1288 return sprintf(buf, "%d\n", result);
1289}
1290
1291static ssize_t store_pwm_interpolate(struct device *dev,
1292 struct device_attribute *devattr,
1293 const char *buf, size_t count)
1294{
1295 /* struct f71882fg_data *data = dev_get_drvdata(dev); */
1296 struct f71882fg_data *data = f71882fg_update_device(dev);
1297 int nr = to_sensor_dev_attr_2(devattr)->index;
1298 int val = simple_strtoul(buf, NULL, 10);
1299 mutex_lock(&data->update_lock);
1300 if (val)
1301 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1302 else
1303 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1304 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1305 data->pwm_auto_point_mapping[nr] = val;
1306 mutex_unlock(&data->update_lock);
1307
1308 return count;
1309}
1310
1311static ssize_t show_pwm_auto_point_channel(struct device *dev,
1312 struct device_attribute *devattr,
1313 char *buf)
1314{
1315 int result;
1316 struct f71882fg_data *data = f71882fg_update_device(dev);
1317 int nr = to_sensor_dev_attr_2(devattr)->index;
1318
1319 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - 1);
1320
1321 return sprintf(buf, "%d\n", result);
1322}
1323
1324static ssize_t store_pwm_auto_point_channel(struct device *dev,
1325 struct device_attribute *devattr,
1326 const char *buf, size_t count)
1327{
1328 /* struct f71882fg_data *data = dev_get_drvdata(dev); */
1329 struct f71882fg_data *data = f71882fg_update_device(dev);
1330 int nr = to_sensor_dev_attr_2(devattr)->index;
1331 long val = simple_strtol(buf, NULL, 10);
1332 switch (val) {
1333 case 1:
1334 val = 1;
1335 break;
1336 case 2:
1337 val = 2;
1338 break;
1339 case 4:
1340 val = 3;
1341 break;
1342 default:
1343 return -EINVAL;
1344 }
1345 mutex_lock(&data->update_lock);
1346 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1347 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1348 data->pwm_auto_point_mapping[nr] = val;
1349 mutex_unlock(&data->update_lock);
1350
1351 return count;
1352}
1353
1354static ssize_t show_pwm_auto_point_temp(struct device *dev,
1355 struct device_attribute *devattr,
1356 char *buf)
1357{
1358 int result;
1359 struct f71882fg_data *data = f71882fg_update_device(dev);
1360 int pwm = to_sensor_dev_attr_2(devattr)->index;
1361 int point = to_sensor_dev_attr_2(devattr)->nr;
1362
1363 result = data->pwm_auto_point_temp[pwm][point];
1364 return sprintf(buf, "%d\n", 1000 * result);
1365}
1366
1367static ssize_t store_pwm_auto_point_temp(struct device *dev,
1368 struct device_attribute *devattr,
1369 const char *buf, size_t count)
1370{
1371 /* struct f71882fg_data *data = dev_get_drvdata(dev); */
1372 struct f71882fg_data *data = f71882fg_update_device(dev);
1373 int pwm = to_sensor_dev_attr_2(devattr)->index;
1374 int point = to_sensor_dev_attr_2(devattr)->nr;
1375 long val = simple_strtol(buf, NULL, 10) / 1000;
1376 val = SENSORS_LIMIT(val, 0, 255);
1377
1378 mutex_lock(&data->update_lock);
1379 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1380 data->pwm_auto_point_temp[pwm][point] = val;
1381 mutex_unlock(&data->update_lock);
1382
1383 return count;
1384}
1385
Hans de Goede45fb3662007-07-13 14:34:19 +02001386static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1387 char *buf)
1388{
1389 return sprintf(buf, DRVNAME "\n");
1390}
1391
Hans de Goedec13548c2009-01-07 16:37:27 +01001392static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1393 struct sensor_device_attribute_2 *attr, int count)
1394{
1395 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001396
Hans de Goedec13548c2009-01-07 16:37:27 +01001397 for (i = 0; i < count; i++) {
1398 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1399 if (err)
1400 return err;
1401 }
1402 return 0;
1403}
1404
1405static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001406{
1407 struct f71882fg_data *data;
Hans de Goedec13548c2009-01-07 16:37:27 +01001408 int err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001409 u8 start_reg;
1410
Hans de Goedec13548c2009-01-07 16:37:27 +01001411 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1412 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001413 return -ENOMEM;
1414
1415 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
1416 mutex_init(&data->update_lock);
1417 platform_set_drvdata(pdev, data);
1418
1419 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001420 err = device_create_file(&pdev->dev, &dev_attr_name);
1421 if (err)
1422 goto exit_unregister_sysfs;
1423
1424 start_reg = f71882fg_read8(data, F71882FG_REG_START);
1425 if (start_reg & 0x01) {
1426 err = f71882fg_create_sysfs_files(pdev, f71882fg_in_temp_attr,
1427 ARRAY_SIZE(f71882fg_in_temp_attr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001428 if (err)
1429 goto exit_unregister_sysfs;
1430 }
1431
Hans de Goede45fb3662007-07-13 14:34:19 +02001432 if (start_reg & 0x02) {
Hans de Goedec13548c2009-01-07 16:37:27 +01001433 err = f71882fg_create_sysfs_files(pdev, f71882fg_fan_attr,
1434 ARRAY_SIZE(f71882fg_fan_attr));
1435 if (err)
1436 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001437 }
1438
Tony Jones1beeffe2007-08-20 13:46:20 -07001439 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1440 if (IS_ERR(data->hwmon_dev)) {
1441 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001442 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001443 goto exit_unregister_sysfs;
1444 }
1445
1446 return 0;
1447
1448exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001449 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede45fb3662007-07-13 14:34:19 +02001450
1451 return err;
1452}
1453
Hans de Goedec13548c2009-01-07 16:37:27 +01001454static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001455{
1456 int i;
1457 struct f71882fg_data *data = platform_get_drvdata(pdev);
1458
1459 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001460 if (data->hwmon_dev)
1461 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001462
Hans de Goedec13548c2009-01-07 16:37:27 +01001463 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001464
1465 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1466 device_remove_file(&pdev->dev,
1467 &f71882fg_in_temp_attr[i].dev_attr);
1468
1469 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1470 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1471
1472 kfree(data);
1473
1474 return 0;
1475}
1476
1477static int __init f71882fg_find(int sioaddr, unsigned short *address)
1478{
1479 int err = -ENODEV;
1480 u16 devid;
1481 u8 start_reg;
1482 struct f71882fg_data data;
1483
1484 superio_enter(sioaddr);
1485
1486 devid = superio_inw(sioaddr, SIO_REG_MANID);
1487 if (devid != SIO_FINTEK_ID) {
1488 printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
1489 goto exit;
1490 }
1491
Jean Delvare67b671b2007-12-06 23:13:42 +01001492 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede45fb3662007-07-13 14:34:19 +02001493 if (devid != SIO_F71882_ID) {
1494 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
1495 goto exit;
1496 }
1497
1498 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001499 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001500 printk(KERN_WARNING DRVNAME ": Device not activated\n");
1501 goto exit;
1502 }
1503
1504 *address = superio_inw(sioaddr, SIO_REG_ADDR);
1505 if (*address == 0)
1506 {
1507 printk(KERN_WARNING DRVNAME ": Base address not set\n");
1508 goto exit;
1509 }
1510 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
1511
1512 data.addr = *address;
1513 start_reg = f71882fg_read8(&data, F71882FG_REG_START);
1514 if (!(start_reg & 0x03)) {
1515 printk(KERN_WARNING DRVNAME
1516 ": Hardware monitoring not activated\n");
1517 goto exit;
1518 }
1519
1520 err = 0;
1521 printk(KERN_INFO DRVNAME ": Found F71882FG chip at %#x, revision %d\n",
1522 (unsigned int)*address,
1523 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
1524exit:
1525 superio_exit(sioaddr);
1526 return err;
1527}
1528
1529static int __init f71882fg_device_add(unsigned short address)
1530{
1531 struct resource res = {
1532 .start = address,
1533 .end = address + REGION_LENGTH - 1,
1534 .flags = IORESOURCE_IO,
1535 };
1536 int err;
1537
1538 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001539 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001540 return -ENOMEM;
1541
1542 res.name = f71882fg_pdev->name;
1543 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001544 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001545 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
1546 goto exit_device_put;
1547 }
1548
1549 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001550 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001551 printk(KERN_ERR DRVNAME ": Device addition failed\n");
1552 goto exit_device_put;
1553 }
1554
1555 return 0;
1556
1557exit_device_put:
1558 platform_device_put(f71882fg_pdev);
1559
1560 return err;
1561}
1562
1563static int __init f71882fg_init(void)
1564{
1565 int err = -ENODEV;
1566 unsigned short address;
1567
1568 if (f71882fg_find(0x2e, &address) && f71882fg_find(0x4e, &address))
1569 goto exit;
1570
Hans de Goedec13548c2009-01-07 16:37:27 +01001571 err = platform_driver_register(&f71882fg_driver);
1572 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001573 goto exit;
1574
Hans de Goedec13548c2009-01-07 16:37:27 +01001575 err = f71882fg_device_add(address);
1576 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001577 goto exit_driver;
1578
1579 return 0;
1580
1581exit_driver:
1582 platform_driver_unregister(&f71882fg_driver);
1583exit:
1584 return err;
1585}
1586
1587static void __exit f71882fg_exit(void)
1588{
1589 platform_device_unregister(f71882fg_pdev);
1590 platform_driver_unregister(&f71882fg_driver);
1591}
1592
1593MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01001594MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02001595MODULE_LICENSE("GPL");
1596
1597module_init(f71882fg_init);
1598module_exit(f71882fg_exit);