blob: 6207120dcd4df05df282b357fc53cabbbde06b61 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede3fc78382009-06-15 18:39:50 +02003 * Copyright (C) 2007-2009 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>
Jean Delvareb9acb642009-01-07 16:37:35 +010031#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020032
33#define DRVNAME "f71882fg"
34
Hans de Goede09475d32009-06-15 18:39:52 +020035#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010036#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020037#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
38#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
39
40#define SIO_REG_LDSEL 0x07 /* Logical device select */
41#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
42#define SIO_REG_DEVREV 0x22 /* Device revision */
43#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
44#define SIO_REG_ENABLE 0x30 /* Logical device enable */
45#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
46
47#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Giel van Schijndel7721fea2010-08-09 17:21:13 -070048#define SIO_F71808_ID 0x0901 /* Chipset ID */
Hans de Goede09475d32009-06-15 18:39:52 +020049#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010050#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020051#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010052#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010053#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020054
55#define REGION_LENGTH 8
56#define ADDR_REG_OFFSET 5
57#define DATA_REG_OFFSET 6
58
59#define F71882FG_REG_PECI 0x0A
60
Hans de Goede498be962009-01-07 16:37:28 +010061#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
62#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020063#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010064#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020065
66#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010067#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
68#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020069#define F71882FG_REG_FAN_STATUS 0x92
70#define F71882FG_REG_FAN_BEEP 0x93
71
Hans de Goede7567a042009-01-07 16:37:28 +010072#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
73#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
74#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020075#define F71882FG_REG_TEMP_STATUS 0x62
76#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020077#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010078#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020079#define F71882FG_REG_TEMP_TYPE 0x6B
80#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
81
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010082#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
83#define F71882FG_REG_PWM_TYPE 0x94
84#define F71882FG_REG_PWM_ENABLE 0x96
85
Hans de Goedebc274902009-01-07 16:37:29 +010086#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010087
88#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
89#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
90#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
91
Hans de Goede45fb3662007-07-13 14:34:19 +020092#define F71882FG_REG_START 0x01
93
94#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
95
Jean Delvare67b671b2007-12-06 23:13:42 +010096static unsigned short force_id;
97module_param(force_id, ushort, 0);
98MODULE_PARM_DESC(force_id, "Override the detected device ID");
99
Giel van Schijndel7721fea2010-08-09 17:21:13 -0700100enum chips { f71808fg, f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100101
102static const char *f71882fg_names[] = {
Giel van Schijndel7721fea2010-08-09 17:21:13 -0700103 "f71808fg",
Hans de Goede09475d32009-06-15 18:39:52 +0200104 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100105 "f71862fg",
106 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100107 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100108 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100109};
110
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100111static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200112
113/* Super-I/O Function prototypes */
114static inline int superio_inb(int base, int reg);
115static inline int superio_inw(int base, int reg);
116static inline void superio_enter(int base);
117static inline void superio_select(int base, int ld);
118static inline void superio_exit(int base);
119
Hans de Goede498be962009-01-07 16:37:28 +0100120struct f71882fg_sio_data {
121 enum chips type;
122};
123
Hans de Goede45fb3662007-07-13 14:34:19 +0200124struct f71882fg_data {
125 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100126 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700127 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200128
129 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200130 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200131 char valid; /* !=0 if following fields are valid */
132 unsigned long last_updated; /* In jiffies */
133 unsigned long last_limits; /* In jiffies */
134
135 /* Register Values */
136 u8 in[9];
137 u8 in1_max;
138 u8 in_status;
139 u8 in_beep;
140 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100141 u16 fan_target[4];
142 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200143 u8 fan_status;
144 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100145 /* Note: all models have only 3 temperature channels, but on some
146 they are addressed as 0-2 and on others as 1-3, so for coding
147 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200148 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100149 u8 temp_ovt[4];
150 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100151 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100152 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200153 u8 temp_status;
154 u8 temp_beep;
155 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200156 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100157 u8 pwm[4];
158 u8 pwm_enable;
159 u8 pwm_auto_point_hyst[2];
160 u8 pwm_auto_point_mapping[4];
161 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100162 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200163};
164
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100165/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200166static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
167 char *buf);
168static ssize_t show_in_max(struct device *dev, struct device_attribute
169 *devattr, char *buf);
170static ssize_t store_in_max(struct device *dev, struct device_attribute
171 *devattr, const char *buf, size_t count);
172static ssize_t show_in_beep(struct device *dev, struct device_attribute
173 *devattr, char *buf);
174static ssize_t store_in_beep(struct device *dev, struct device_attribute
175 *devattr, const char *buf, size_t count);
176static ssize_t show_in_alarm(struct device *dev, struct device_attribute
177 *devattr, char *buf);
178/* Sysfs Fan */
179static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
180 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100181static ssize_t show_fan_full_speed(struct device *dev,
182 struct device_attribute *devattr, char *buf);
183static ssize_t store_fan_full_speed(struct device *dev,
184 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200185static ssize_t show_fan_beep(struct device *dev, struct device_attribute
186 *devattr, char *buf);
187static ssize_t store_fan_beep(struct device *dev, struct device_attribute
188 *devattr, const char *buf, size_t count);
189static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
190 *devattr, char *buf);
191/* Sysfs Temp */
192static ssize_t show_temp(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t show_temp_max(struct device *dev, struct device_attribute
195 *devattr, char *buf);
196static ssize_t store_temp_max(struct device *dev, struct device_attribute
197 *devattr, const char *buf, size_t count);
198static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
199 *devattr, char *buf);
200static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
201 *devattr, const char *buf, size_t count);
202static ssize_t show_temp_crit(struct device *dev, struct device_attribute
203 *devattr, char *buf);
204static ssize_t store_temp_crit(struct device *dev, struct device_attribute
205 *devattr, const char *buf, size_t count);
206static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t show_temp_type(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t show_temp_beep(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212static ssize_t store_temp_beep(struct device *dev, struct device_attribute
213 *devattr, const char *buf, size_t count);
214static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
215 *devattr, char *buf);
216static ssize_t show_temp_fault(struct device *dev, struct device_attribute
217 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100218/* PWM and Auto point control */
219static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
220 char *buf);
221static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
222 const char *buf, size_t count);
223static ssize_t show_pwm_enable(struct device *dev,
224 struct device_attribute *devattr, char *buf);
225static ssize_t store_pwm_enable(struct device *dev,
226 struct device_attribute *devattr, const char *buf, size_t count);
227static ssize_t show_pwm_interpolate(struct device *dev,
228 struct device_attribute *devattr, char *buf);
229static ssize_t store_pwm_interpolate(struct device *dev,
230 struct device_attribute *devattr, const char *buf, size_t count);
231static ssize_t show_pwm_auto_point_channel(struct device *dev,
232 struct device_attribute *devattr, char *buf);
233static ssize_t store_pwm_auto_point_channel(struct device *dev,
234 struct device_attribute *devattr, const char *buf, size_t count);
235static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
236 struct device_attribute *devattr, char *buf);
237static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
238 struct device_attribute *devattr, const char *buf, size_t count);
239static ssize_t show_pwm_auto_point_pwm(struct device *dev,
240 struct device_attribute *devattr, char *buf);
241static ssize_t store_pwm_auto_point_pwm(struct device *dev,
242 struct device_attribute *devattr, const char *buf, size_t count);
243static ssize_t show_pwm_auto_point_temp(struct device *dev,
244 struct device_attribute *devattr, char *buf);
245static ssize_t store_pwm_auto_point_temp(struct device *dev,
246 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200247/* Sysfs misc */
248static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
249 char *buf);
250
251static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100252static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200253
254static struct platform_driver f71882fg_driver = {
255 .driver = {
256 .owner = THIS_MODULE,
257 .name = DRVNAME,
258 },
259 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200260 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200261};
262
Hans de Goedec13548c2009-01-07 16:37:27 +0100263static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200264
Hans de Goede66344aa2009-12-09 20:35:59 +0100265/* Temp and in attr for the f71858fg, the f71858fg is special as it
266 has its temperature indexes start at 0 (the others start at 1) and
267 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200268static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
269 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
270 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
271 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
272 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
273 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
274 store_temp_max, 0, 0),
275 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
276 store_temp_max_hyst, 0, 0),
277 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
278 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
279 store_temp_crit, 0, 0),
280 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
281 0, 0),
282 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
283 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
284 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
285 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
286 store_temp_max, 0, 1),
287 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
288 store_temp_max_hyst, 0, 1),
289 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
290 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
291 store_temp_crit, 0, 1),
292 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
293 0, 1),
294 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
295 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
296 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
297 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
298 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
299 store_temp_max, 0, 2),
300 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
301 store_temp_max_hyst, 0, 2),
302 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
303 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
304 store_temp_crit, 0, 2),
305 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
306 0, 2),
307 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
308 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
309};
310
Giel van Schijndel7721fea2010-08-09 17:21:13 -0700311/* In attr common to the f71862fg, f71882fg and f71889fg */
312static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100313 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
314 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100315 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
316 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
317 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
318 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
319 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
320 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
321 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Giel van Schijndel7721fea2010-08-09 17:21:13 -0700322};
323
324/* In attr for the f71808fg */
325static struct sensor_device_attribute_2 f71808_in_attr[] = {
326 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
327 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
328 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
329 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
330 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
331 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
332 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 7),
333 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 8),
334};
335
336/* Temp attr common to the f71808fg, f71862fg, f71882fg and f71889fg */
337static struct sensor_device_attribute_2 fxxxx_temp_attr[] = {
Hans de Goede7567a042009-01-07 16:37:28 +0100338 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100339 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100340 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100341 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100342 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100343 /* Should really be temp1_max_alarm, but older versions did not handle
344 the max and crit alarms separately and lm_sensors v2 depends on the
345 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
346 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
347 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
348 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100349 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100350 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100353 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
354 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
355 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100357 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
358 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
359 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100360 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100361 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100362 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100363 /* Should be temp2_max_alarm, see temp1_alarm note */
364 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
365 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
366 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100368 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100369 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100370 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100371 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
372 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
373 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100374 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Giel van Schijndel7721fea2010-08-09 17:21:13 -0700376};
377
378/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
379static struct sensor_device_attribute_2 f71862_temp_attr[] = {
Hans de Goede7567a042009-01-07 16:37:28 +0100380 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
381 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
382 store_temp_max, 0, 3),
383 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
384 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100385 /* Should be temp3_max_alarm, see temp1_alarm note */
386 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
387 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
388 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100389 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
390 store_temp_crit, 0, 3),
391 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
392 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100393 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
394 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
395 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100396 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100397 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200398};
399
Hans de Goede66344aa2009-12-09 20:35:59 +0100400/* For models with in1 alarm capability */
401static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100402 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
403 0, 1),
404 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
405 0, 1),
406 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
407};
408
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100409/* Temp and in attr for the f8000
410 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
411 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100412 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100413 */
414static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
415 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
416 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
417 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
418 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
419 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
420 store_temp_crit, 0, 0),
421 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
422 store_temp_max, 0, 0),
423 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200424 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100425 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
426 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
427 store_temp_crit, 0, 1),
428 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
429 store_temp_max, 0, 1),
430 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
431 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200432 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100433 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
434 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
435 store_temp_crit, 0, 2),
436 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
437 store_temp_max, 0, 2),
438 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200439 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100440};
441
442/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100443static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100444 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100445 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
446 show_fan_full_speed,
447 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100448 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100449 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
450 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
451 store_pwm_enable, 0, 0),
452 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
453 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100454}, {
455 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
456 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
457 show_fan_full_speed,
458 store_fan_full_speed, 0, 1),
459 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100460 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
461 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
462 store_pwm_enable, 0, 1),
463 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
464 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100465}, {
466 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
467 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
468 show_fan_full_speed,
469 store_fan_full_speed, 0, 2),
470 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200471 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
472 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
473 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100474 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
475 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100476}, {
477 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
478 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
479 show_fan_full_speed,
480 store_fan_full_speed, 0, 3),
481 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
482 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
483 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
484 store_pwm_enable, 0, 3),
485 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
486 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
487} };
Hans de Goede498be962009-01-07 16:37:28 +0100488
Hans de Goede66344aa2009-12-09 20:35:59 +0100489/* Attr for models which can beep on Fan alarm */
490static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100491 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
492 store_fan_beep, 0, 0),
493 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
494 store_fan_beep, 0, 1),
495 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
496 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100497 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
498 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100499};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100500
Hans de Goede66344aa2009-12-09 20:35:59 +0100501/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
502 f71858fg / f71882fg / f71889fg */
503static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
504 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_channel,
506 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100507 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 1, 0),
510 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
512 4, 0),
513 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 0, 0),
516 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 3, 0),
519 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp_hyst,
521 store_pwm_auto_point_temp_hyst,
522 0, 0),
523 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
524 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
525
Hans de Goede66344aa2009-12-09 20:35:59 +0100526 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_channel,
528 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100529 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 1, 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 4, 1),
535 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 0, 1),
538 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
540 3, 1),
541 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp_hyst,
543 store_pwm_auto_point_temp_hyst,
544 0, 1),
545 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
546 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100547
Hans de Goede66344aa2009-12-09 20:35:59 +0100548 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
549 show_pwm_auto_point_channel,
550 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100551 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
553 1, 2),
554 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
556 4, 2),
557 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
559 0, 2),
560 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
562 3, 2),
563 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_temp_hyst,
565 store_pwm_auto_point_temp_hyst,
566 0, 2),
567 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
568 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100569};
570
Hans de Goede66344aa2009-12-09 20:35:59 +0100571/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100572static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100573 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_channel,
575 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100576 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
578 0, 0),
579 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
581 1, 0),
582 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
584 2, 0),
585 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
587 3, 0),
588 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
589 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
590 4, 0),
591 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
592 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
593 0, 0),
594 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
595 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
596 1, 0),
597 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
598 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
599 2, 0),
600 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
601 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
602 3, 0),
603 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
604 show_pwm_auto_point_temp_hyst,
605 store_pwm_auto_point_temp_hyst,
606 0, 0),
607 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
608 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
609 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
610 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
611 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
612 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100613}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100614 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_channel,
616 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100617 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
619 0, 1),
620 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
622 1, 1),
623 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
625 2, 1),
626 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
628 3, 1),
629 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
630 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
631 4, 1),
632 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
633 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
634 0, 1),
635 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
637 1, 1),
638 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
640 2, 1),
641 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
642 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
643 3, 1),
644 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
645 show_pwm_auto_point_temp_hyst,
646 store_pwm_auto_point_temp_hyst,
647 0, 1),
648 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
649 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
650 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
651 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
652 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
653 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100654}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100655 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_channel,
657 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100658 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
659 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
660 0, 2),
661 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
662 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
663 1, 2),
664 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
665 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
666 2, 2),
667 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
668 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
669 3, 2),
670 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
671 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
672 4, 2),
673 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
674 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
675 0, 2),
676 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
678 1, 2),
679 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
681 2, 2),
682 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
684 3, 2),
685 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
686 show_pwm_auto_point_temp_hyst,
687 store_pwm_auto_point_temp_hyst,
688 0, 2),
689 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
690 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
691 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
692 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
693 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
694 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100695}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100696 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_channel,
698 store_pwm_auto_point_channel, 0, 3),
699 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
701 0, 3),
702 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
704 1, 3),
705 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
707 2, 3),
708 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
710 3, 3),
711 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
712 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
713 4, 3),
714 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
715 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
716 0, 3),
717 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
718 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
719 1, 3),
720 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
721 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
722 2, 3),
723 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
724 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
725 3, 3),
726 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
727 show_pwm_auto_point_temp_hyst,
728 store_pwm_auto_point_temp_hyst,
729 0, 3),
730 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
731 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
732 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
733 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
734 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
735 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100736} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200737
Hans de Goede66344aa2009-12-09 20:35:59 +0100738/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100739static struct sensor_device_attribute_2 f8000_fan_attr[] = {
740 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100741};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100742
Hans de Goede66344aa2009-12-09 20:35:59 +0100743/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
744 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
745 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
746static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
747 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_channel,
749 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100750 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
752 0, 2),
753 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
755 1, 2),
756 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
758 2, 2),
759 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
761 3, 2),
762 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
764 4, 2),
765 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
766 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
767 0, 2),
768 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
770 1, 2),
771 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
773 2, 2),
774 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
776 3, 2),
777 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
778 show_pwm_auto_point_temp_hyst,
779 store_pwm_auto_point_temp_hyst,
780 0, 2),
781 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
782 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
783 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
784 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
785 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
786 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
787
Hans de Goede66344aa2009-12-09 20:35:59 +0100788 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_channel,
790 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100791 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
793 0, 0),
794 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
796 1, 0),
797 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
799 2, 0),
800 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
802 3, 0),
803 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
804 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
805 4, 0),
806 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
807 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
808 0, 0),
809 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
811 1, 0),
812 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
814 2, 0),
815 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
817 3, 0),
818 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
819 show_pwm_auto_point_temp_hyst,
820 store_pwm_auto_point_temp_hyst,
821 0, 0),
822 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
823 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
824 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
825 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
826 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
827 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
828
Hans de Goede66344aa2009-12-09 20:35:59 +0100829 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_channel,
831 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100832 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
834 0, 1),
835 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
837 1, 1),
838 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
840 2, 1),
841 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
843 3, 1),
844 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
845 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
846 4, 1),
847 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
848 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
849 0, 1),
850 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
851 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
852 1, 1),
853 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
854 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
855 2, 1),
856 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
857 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
858 3, 1),
859 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
860 show_pwm_auto_point_temp_hyst,
861 store_pwm_auto_point_temp_hyst,
862 0, 1),
863 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
864 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
865 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
866 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
867 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
868 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
869};
Hans de Goede45fb3662007-07-13 14:34:19 +0200870
871/* Super I/O functions */
872static inline int superio_inb(int base, int reg)
873{
874 outb(reg, base);
875 return inb(base + 1);
876}
877
878static int superio_inw(int base, int reg)
879{
880 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200881 val = superio_inb(base, reg) << 8;
882 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200883 return val;
884}
885
886static inline void superio_enter(int base)
887{
888 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200889 outb(SIO_UNLOCK_KEY, base);
890 outb(SIO_UNLOCK_KEY, base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200891}
892
Giel van Schijndel162bb592010-05-27 19:58:40 +0200893static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200894{
895 outb(SIO_REG_LDSEL, base);
896 outb(ld, base + 1);
897}
898
899static inline void superio_exit(int base)
900{
901 outb(SIO_LOCK_KEY, base);
902}
903
Hans de Goede2f650632009-01-07 16:37:31 +0100904static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200905{
906 return reg ? (1500000 / reg) : 0;
907}
908
Hans de Goede2f650632009-01-07 16:37:31 +0100909static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100910{
911 return fan ? (1500000 / fan) : 0;
912}
913
Hans de Goede45fb3662007-07-13 14:34:19 +0200914static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
915{
916 u8 val;
917
918 outb(reg, data->addr + ADDR_REG_OFFSET);
919 val = inb(data->addr + DATA_REG_OFFSET);
920
921 return val;
922}
923
924static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
925{
926 u16 val;
927
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200928 val = f71882fg_read8(data, reg) << 8;
929 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200930
931 return val;
932}
933
934static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
935{
936 outb(reg, data->addr + ADDR_REG_OFFSET);
937 outb(val, data->addr + DATA_REG_OFFSET);
938}
939
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100940static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
941{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200942 f71882fg_write8(data, reg, val >> 8);
943 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100944}
945
Hans de Goede09475d32009-06-15 18:39:52 +0200946static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
947{
948 if (data->type == f71858fg)
949 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
950 else
951 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
952}
953
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100954static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200955{
956 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100957 int nr, reg = 0, reg2;
958 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200959 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200960
961 mutex_lock(&data->update_lock);
962
963 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200964 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200965 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100966 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100967 data->in1_max =
968 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
969 data->in_beep =
970 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
971 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200972
973 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200974 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200975 data->temp_ovt[nr] = f71882fg_read8(data,
976 F71882FG_REG_TEMP_OVT(nr));
977 data->temp_high[nr] = f71882fg_read8(data,
978 F71882FG_REG_TEMP_HIGH(nr));
979 }
980
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100981 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100982 data->temp_hyst[0] = f71882fg_read8(data,
983 F71882FG_REG_TEMP_HYST(0));
984 data->temp_hyst[1] = f71882fg_read8(data,
985 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200986 }
987
Hans de Goede76698962009-12-09 20:36:01 +0100988 if (data->type == f71862fg || data->type == f71882fg ||
989 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200990 data->fan_beep = f71882fg_read8(data,
991 F71882FG_REG_FAN_BEEP);
992 data->temp_beep = f71882fg_read8(data,
993 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100994 /* Have to hardcode type, because temp1 is special */
995 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
996 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
997 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
998 }
Hans de Goede76698962009-12-09 20:36:01 +0100999 /* Determine temp index 1 sensor type */
1000 if (data->type == f71889fg) {
1001 reg2 = f71882fg_read8(data, F71882FG_REG_START);
1002 switch ((reg2 & 0x60) >> 5) {
1003 case 0x00: /* BJT / Thermistor */
1004 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1005 break;
1006 case 0x01: /* AMDSI */
1007 data->temp_type[1] = 5;
1008 break;
1009 case 0x02: /* PECI */
1010 case 0x03: /* Ibex Peak ?? Report as PECI for now */
1011 data->temp_type[1] = 6;
1012 break;
1013 }
Giel van Schijndel7721fea2010-08-09 17:21:13 -07001014 } else if (data->type == f71808fg) {
1015 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
1016 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1017 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1018
Hans de Goede76698962009-12-09 20:36:01 +01001019 } else {
1020 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
1021 if ((reg2 & 0x03) == 0x01)
1022 data->temp_type[1] = 6; /* PECI */
1023 else if ((reg2 & 0x03) == 0x02)
1024 data->temp_type[1] = 5; /* AMDSI */
1025 else if (data->type == f71862fg ||
1026 data->type == f71882fg)
1027 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1028 else /* f71858fg and f8000 only support BJT */
1029 data->temp_type[1] = 2;
1030 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001031
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001032 data->pwm_enable = f71882fg_read8(data,
1033 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001034 data->pwm_auto_point_hyst[0] =
1035 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1036 data->pwm_auto_point_hyst[1] =
1037 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1038
Hans de Goede498be962009-01-07 16:37:28 +01001039 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001040 data->pwm_auto_point_mapping[nr] =
1041 f71882fg_read8(data,
1042 F71882FG_REG_POINT_MAPPING(nr));
1043
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001044 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001045 int point;
1046 for (point = 0; point < 5; point++) {
1047 data->pwm_auto_point_pwm[nr][point] =
1048 f71882fg_read8(data,
1049 F71882FG_REG_POINT_PWM
1050 (nr, point));
1051 }
1052 for (point = 0; point < 4; point++) {
1053 data->pwm_auto_point_temp[nr][point] =
1054 f71882fg_read8(data,
1055 F71882FG_REG_POINT_TEMP
1056 (nr, point));
1057 }
1058 } else {
1059 data->pwm_auto_point_pwm[nr][1] =
1060 f71882fg_read8(data,
1061 F71882FG_REG_POINT_PWM
1062 (nr, 1));
1063 data->pwm_auto_point_pwm[nr][4] =
1064 f71882fg_read8(data,
1065 F71882FG_REG_POINT_PWM
1066 (nr, 4));
1067 data->pwm_auto_point_temp[nr][0] =
1068 f71882fg_read8(data,
1069 F71882FG_REG_POINT_TEMP
1070 (nr, 0));
1071 data->pwm_auto_point_temp[nr][3] =
1072 f71882fg_read8(data,
1073 F71882FG_REG_POINT_TEMP
1074 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001075 }
1076 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001077 data->last_limits = jiffies;
1078 }
1079
1080 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001081 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001082 data->temp_status = f71882fg_read8(data,
1083 F71882FG_REG_TEMP_STATUS);
1084 data->temp_diode_open = f71882fg_read8(data,
1085 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001086 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1087 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001088
1089 data->fan_status = f71882fg_read8(data,
1090 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001091 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001092 data->fan[nr] = f71882fg_read16(data,
1093 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001094 data->fan_target[nr] =
1095 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1096 data->fan_full_speed[nr] =
1097 f71882fg_read16(data,
1098 F71882FG_REG_FAN_FULL_SPEED(nr));
1099 data->pwm[nr] =
1100 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1101 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001102
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001103 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1104 if (data->type == f8000)
1105 data->fan[3] = f71882fg_read16(data,
1106 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001107 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001108 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001109 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001110 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001111 data->in[nr] = f71882fg_read8(data,
1112 F71882FG_REG_IN(nr));
1113
1114 data->last_updated = jiffies;
1115 data->valid = 1;
1116 }
1117
1118 mutex_unlock(&data->update_lock);
1119
1120 return data;
1121}
1122
1123/* Sysfs Interface */
1124static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1125 char *buf)
1126{
1127 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001128 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001129 int speed = fan_from_reg(data->fan[nr]);
1130
1131 if (speed == FAN_MIN_DETECT)
1132 speed = 0;
1133
1134 return sprintf(buf, "%d\n", speed);
1135}
1136
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001137static ssize_t show_fan_full_speed(struct device *dev,
1138 struct device_attribute *devattr, char *buf)
1139{
1140 struct f71882fg_data *data = f71882fg_update_device(dev);
1141 int nr = to_sensor_dev_attr_2(devattr)->index;
1142 int speed = fan_from_reg(data->fan_full_speed[nr]);
1143 return sprintf(buf, "%d\n", speed);
1144}
1145
1146static ssize_t store_fan_full_speed(struct device *dev,
1147 struct device_attribute *devattr,
1148 const char *buf, size_t count)
1149{
1150 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001151 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1152 long val;
1153
1154 err = strict_strtol(buf, 10, &val);
1155 if (err)
1156 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001157
1158 val = SENSORS_LIMIT(val, 23, 1500000);
1159 val = fan_to_reg(val);
1160
1161 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001162 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1163 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001164 mutex_unlock(&data->update_lock);
1165
1166 return count;
1167}
1168
Hans de Goede45fb3662007-07-13 14:34:19 +02001169static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1170 *devattr, char *buf)
1171{
1172 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001173 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001174
1175 if (data->fan_beep & (1 << nr))
1176 return sprintf(buf, "1\n");
1177 else
1178 return sprintf(buf, "0\n");
1179}
1180
1181static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1182 *devattr, const char *buf, size_t count)
1183{
1184 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001185 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1186 unsigned long val;
1187
1188 err = strict_strtoul(buf, 10, &val);
1189 if (err)
1190 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001191
1192 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001193 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001194 if (val)
1195 data->fan_beep |= 1 << nr;
1196 else
1197 data->fan_beep &= ~(1 << nr);
1198
1199 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1200 mutex_unlock(&data->update_lock);
1201
1202 return count;
1203}
1204
1205static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1206 *devattr, char *buf)
1207{
1208 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001209 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001210
1211 if (data->fan_status & (1 << nr))
1212 return sprintf(buf, "1\n");
1213 else
1214 return sprintf(buf, "0\n");
1215}
1216
1217static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1218 char *buf)
1219{
1220 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001221 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001222
1223 return sprintf(buf, "%d\n", data->in[nr] * 8);
1224}
1225
1226static ssize_t show_in_max(struct device *dev, struct device_attribute
1227 *devattr, char *buf)
1228{
1229 struct f71882fg_data *data = f71882fg_update_device(dev);
1230
1231 return sprintf(buf, "%d\n", data->in1_max * 8);
1232}
1233
1234static ssize_t store_in_max(struct device *dev, struct device_attribute
1235 *devattr, const char *buf, size_t count)
1236{
1237 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001238 int err;
1239 long val;
1240
1241 err = strict_strtol(buf, 10, &val);
1242 if (err)
1243 return err;
1244
1245 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001246 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001247
1248 mutex_lock(&data->update_lock);
1249 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1250 data->in1_max = val;
1251 mutex_unlock(&data->update_lock);
1252
1253 return count;
1254}
1255
1256static ssize_t show_in_beep(struct device *dev, struct device_attribute
1257 *devattr, char *buf)
1258{
1259 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001260 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001261
1262 if (data->in_beep & (1 << nr))
1263 return sprintf(buf, "1\n");
1264 else
1265 return sprintf(buf, "0\n");
1266}
1267
1268static ssize_t store_in_beep(struct device *dev, struct device_attribute
1269 *devattr, const char *buf, size_t count)
1270{
1271 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001272 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1273 unsigned long val;
1274
1275 err = strict_strtoul(buf, 10, &val);
1276 if (err)
1277 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001278
1279 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001280 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001281 if (val)
1282 data->in_beep |= 1 << nr;
1283 else
1284 data->in_beep &= ~(1 << nr);
1285
1286 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1287 mutex_unlock(&data->update_lock);
1288
1289 return count;
1290}
1291
1292static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1293 *devattr, char *buf)
1294{
1295 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001296 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001297
1298 if (data->in_status & (1 << nr))
1299 return sprintf(buf, "1\n");
1300 else
1301 return sprintf(buf, "0\n");
1302}
1303
1304static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1305 char *buf)
1306{
1307 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001308 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001309 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001310
Hans de Goede09475d32009-06-15 18:39:52 +02001311 if (data->type == f71858fg) {
1312 /* TEMP_TABLE_SEL 1 or 3 ? */
1313 if (data->temp_config & 1) {
1314 sign = data->temp[nr] & 0x0001;
1315 temp = (data->temp[nr] >> 5) & 0x7ff;
1316 } else {
1317 sign = data->temp[nr] & 0x8000;
1318 temp = (data->temp[nr] >> 5) & 0x3ff;
1319 }
1320 temp *= 125;
1321 if (sign)
1322 temp -= 128000;
1323 } else
1324 temp = data->temp[nr] * 1000;
1325
1326 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001327}
1328
1329static ssize_t show_temp_max(struct device *dev, struct device_attribute
1330 *devattr, char *buf)
1331{
1332 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001333 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001334
1335 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1336}
1337
1338static ssize_t store_temp_max(struct device *dev, struct device_attribute
1339 *devattr, const char *buf, size_t count)
1340{
1341 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001342 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1343 long val;
1344
1345 err = strict_strtol(buf, 10, &val);
1346 if (err)
1347 return err;
1348
1349 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001350 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001351
1352 mutex_lock(&data->update_lock);
1353 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1354 data->temp_high[nr] = val;
1355 mutex_unlock(&data->update_lock);
1356
1357 return count;
1358}
1359
1360static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1361 *devattr, char *buf)
1362{
1363 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001364 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001365 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001366
Hans de Goedece0bfa52009-01-07 16:37:28 +01001367 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001368 if (nr & 1)
1369 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1370 else
1371 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1372 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001373 mutex_unlock(&data->update_lock);
1374
1375 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001376}
1377
1378static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1379 *devattr, const char *buf, size_t count)
1380{
1381 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001382 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001383 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001384 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001385 long val;
1386
1387 err = strict_strtol(buf, 10, &val);
1388 if (err)
1389 return err;
1390
1391 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001392
1393 mutex_lock(&data->update_lock);
1394
1395 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001396 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1397 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1398 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001399 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001400
1401 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001402 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1403 if (nr & 1)
1404 reg = (reg & 0x0f) | (val << 4);
1405 else
1406 reg = (reg & 0xf0) | val;
1407 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1408 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001409
Hans de Goede45fb3662007-07-13 14:34:19 +02001410 mutex_unlock(&data->update_lock);
1411 return ret;
1412}
1413
1414static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1415 *devattr, char *buf)
1416{
1417 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001418 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001419
1420 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1421}
1422
1423static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1424 *devattr, const char *buf, size_t count)
1425{
1426 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001427 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1428 long val;
1429
1430 err = strict_strtol(buf, 10, &val);
1431 if (err)
1432 return err;
1433
1434 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001435 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001436
1437 mutex_lock(&data->update_lock);
1438 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1439 data->temp_ovt[nr] = val;
1440 mutex_unlock(&data->update_lock);
1441
1442 return count;
1443}
1444
1445static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1446 *devattr, char *buf)
1447{
1448 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001449 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001450 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001451
Hans de Goedece0bfa52009-01-07 16:37:28 +01001452 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001453 if (nr & 1)
1454 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1455 else
1456 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1457 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001458 mutex_unlock(&data->update_lock);
1459
1460 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001461}
1462
1463static ssize_t show_temp_type(struct device *dev, struct device_attribute
1464 *devattr, char *buf)
1465{
1466 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001467 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001468
1469 return sprintf(buf, "%d\n", data->temp_type[nr]);
1470}
1471
1472static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1473 *devattr, char *buf)
1474{
1475 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001476 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001477
Hans de Goede7567a042009-01-07 16:37:28 +01001478 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001479 return sprintf(buf, "1\n");
1480 else
1481 return sprintf(buf, "0\n");
1482}
1483
1484static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1485 *devattr, const char *buf, size_t count)
1486{
1487 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001488 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1489 unsigned long val;
1490
1491 err = strict_strtoul(buf, 10, &val);
1492 if (err)
1493 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001494
1495 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001496 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001497 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001498 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001499 else
Hans de Goede7567a042009-01-07 16:37:28 +01001500 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001501
1502 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1503 mutex_unlock(&data->update_lock);
1504
1505 return count;
1506}
1507
1508static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1509 *devattr, char *buf)
1510{
1511 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001512 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001513
Hans de Goede7567a042009-01-07 16:37:28 +01001514 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001515 return sprintf(buf, "1\n");
1516 else
1517 return sprintf(buf, "0\n");
1518}
1519
1520static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1521 *devattr, char *buf)
1522{
1523 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001524 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001525
Hans de Goede7567a042009-01-07 16:37:28 +01001526 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001527 return sprintf(buf, "1\n");
1528 else
1529 return sprintf(buf, "0\n");
1530}
1531
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001532static ssize_t show_pwm(struct device *dev,
1533 struct device_attribute *devattr, char *buf)
1534{
1535 struct f71882fg_data *data = f71882fg_update_device(dev);
1536 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001537 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001538 if (data->pwm_enable & (1 << (2 * nr)))
1539 /* PWM mode */
1540 val = data->pwm[nr];
1541 else {
1542 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001543 val = 255 * fan_from_reg(data->fan_target[nr])
1544 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001545 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001546 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001547 return sprintf(buf, "%d\n", val);
1548}
1549
1550static ssize_t store_pwm(struct device *dev,
1551 struct device_attribute *devattr, const char *buf,
1552 size_t count)
1553{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001554 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001555 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1556 long val;
1557
1558 err = strict_strtol(buf, 10, &val);
1559 if (err)
1560 return err;
1561
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001562 val = SENSORS_LIMIT(val, 0, 255);
1563
1564 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001565 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001566 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1567 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1568 count = -EROFS;
1569 goto leave;
1570 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001571 if (data->pwm_enable & (1 << (2 * nr))) {
1572 /* PWM mode */
1573 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1574 data->pwm[nr] = val;
1575 } else {
1576 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001577 int target, full_speed;
1578 full_speed = f71882fg_read16(data,
1579 F71882FG_REG_FAN_FULL_SPEED(nr));
1580 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1581 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1582 data->fan_target[nr] = target;
1583 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001584 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001585leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001586 mutex_unlock(&data->update_lock);
1587
1588 return count;
1589}
1590
1591static ssize_t show_pwm_enable(struct device *dev,
1592 struct device_attribute *devattr, char *buf)
1593{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001594 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001595 struct f71882fg_data *data = f71882fg_update_device(dev);
1596 int nr = to_sensor_dev_attr_2(devattr)->index;
1597
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001598 switch ((data->pwm_enable >> 2 * nr) & 3) {
1599 case 0:
1600 case 1:
1601 result = 2; /* Normal auto mode */
1602 break;
1603 case 2:
1604 result = 1; /* Manual mode */
1605 break;
1606 case 3:
1607 if (data->type == f8000)
1608 result = 3; /* Thermostat mode */
1609 else
1610 result = 1; /* Manual mode */
1611 break;
1612 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001613
1614 return sprintf(buf, "%d\n", result);
1615}
1616
1617static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1618 *devattr, const char *buf, size_t count)
1619{
1620 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001621 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1622 long val;
1623
1624 err = strict_strtol(buf, 10, &val);
1625 if (err)
1626 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001627
Hans de Goede3fc78382009-06-15 18:39:50 +02001628 /* Special case for F8000 pwm channel 3 which only does auto mode */
1629 if (data->type == f8000 && nr == 2 && val != 2)
1630 return -EINVAL;
1631
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001632 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001633 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001634 /* Special case for F8000 auto PWM mode / Thermostat mode */
1635 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1636 switch (val) {
1637 case 2:
1638 data->pwm_enable &= ~(2 << (2 * nr));
1639 break; /* Normal auto mode */
1640 case 3:
1641 data->pwm_enable |= 2 << (2 * nr);
1642 break; /* Thermostat mode */
1643 default:
1644 count = -EINVAL;
1645 goto leave;
1646 }
1647 } else {
1648 switch (val) {
1649 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001650 /* The f71858fg does not support manual RPM mode */
1651 if (data->type == f71858fg &&
1652 ((data->pwm_enable >> (2 * nr)) & 1)) {
1653 count = -EINVAL;
1654 goto leave;
1655 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001656 data->pwm_enable |= 2 << (2 * nr);
1657 break; /* Manual */
1658 case 2:
1659 data->pwm_enable &= ~(2 << (2 * nr));
1660 break; /* Normal auto mode */
1661 default:
1662 count = -EINVAL;
1663 goto leave;
1664 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001665 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001666 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001667leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001668 mutex_unlock(&data->update_lock);
1669
1670 return count;
1671}
1672
1673static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1674 struct device_attribute *devattr,
1675 char *buf)
1676{
1677 int result;
1678 struct f71882fg_data *data = f71882fg_update_device(dev);
1679 int pwm = to_sensor_dev_attr_2(devattr)->index;
1680 int point = to_sensor_dev_attr_2(devattr)->nr;
1681
Hans de Goedece0bfa52009-01-07 16:37:28 +01001682 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001683 if (data->pwm_enable & (1 << (2 * pwm))) {
1684 /* PWM mode */
1685 result = data->pwm_auto_point_pwm[pwm][point];
1686 } else {
1687 /* RPM mode */
1688 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1689 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001690 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001691
1692 return sprintf(buf, "%d\n", result);
1693}
1694
1695static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1696 struct device_attribute *devattr,
1697 const char *buf, size_t count)
1698{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001699 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001700 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001701 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001702 long val;
1703
1704 err = strict_strtol(buf, 10, &val);
1705 if (err)
1706 return err;
1707
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001708 val = SENSORS_LIMIT(val, 0, 255);
1709
1710 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001711 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001712 if (data->pwm_enable & (1 << (2 * pwm))) {
1713 /* PWM mode */
1714 } else {
1715 /* RPM mode */
1716 if (val < 29) /* Prevent negative numbers */
1717 val = 255;
1718 else
1719 val = (255 - val) * 32 / val;
1720 }
1721 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1722 data->pwm_auto_point_pwm[pwm][point] = val;
1723 mutex_unlock(&data->update_lock);
1724
1725 return count;
1726}
1727
1728static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1729 struct device_attribute *devattr,
1730 char *buf)
1731{
1732 int result = 0;
1733 struct f71882fg_data *data = f71882fg_update_device(dev);
1734 int nr = to_sensor_dev_attr_2(devattr)->index;
1735 int point = to_sensor_dev_attr_2(devattr)->nr;
1736
1737 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001738 if (nr & 1)
1739 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1740 else
1741 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001742 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1743 mutex_unlock(&data->update_lock);
1744
1745 return sprintf(buf, "%d\n", result);
1746}
1747
1748static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1749 struct device_attribute *devattr,
1750 const char *buf, size_t count)
1751{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001752 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001753 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001754 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001755 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001756 long val;
1757
1758 err = strict_strtol(buf, 10, &val);
1759 if (err)
1760 return err;
1761
1762 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001763
1764 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001765 data->pwm_auto_point_temp[nr][point] =
1766 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001767 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1768 data->pwm_auto_point_temp[nr][point]);
1769 val = data->pwm_auto_point_temp[nr][point] - val;
1770
Hans de Goedebc274902009-01-07 16:37:29 +01001771 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1772 if (nr & 1)
1773 reg = (reg & 0x0f) | (val << 4);
1774 else
1775 reg = (reg & 0xf0) | val;
1776
1777 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1778 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001779 mutex_unlock(&data->update_lock);
1780
1781 return count;
1782}
1783
1784static ssize_t show_pwm_interpolate(struct device *dev,
1785 struct device_attribute *devattr, char *buf)
1786{
1787 int result;
1788 struct f71882fg_data *data = f71882fg_update_device(dev);
1789 int nr = to_sensor_dev_attr_2(devattr)->index;
1790
1791 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1792
1793 return sprintf(buf, "%d\n", result);
1794}
1795
1796static ssize_t store_pwm_interpolate(struct device *dev,
1797 struct device_attribute *devattr,
1798 const char *buf, size_t count)
1799{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001800 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001801 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1802 unsigned long val;
1803
1804 err = strict_strtoul(buf, 10, &val);
1805 if (err)
1806 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001807
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001808 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001809 data->pwm_auto_point_mapping[nr] =
1810 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001811 if (val)
1812 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1813 else
1814 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1815 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1816 data->pwm_auto_point_mapping[nr] = val;
1817 mutex_unlock(&data->update_lock);
1818
1819 return count;
1820}
1821
1822static ssize_t show_pwm_auto_point_channel(struct device *dev,
1823 struct device_attribute *devattr,
1824 char *buf)
1825{
1826 int result;
1827 struct f71882fg_data *data = f71882fg_update_device(dev);
1828 int nr = to_sensor_dev_attr_2(devattr)->index;
1829
Hans de Goede09475d32009-06-15 18:39:52 +02001830 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1831 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001832
1833 return sprintf(buf, "%d\n", result);
1834}
1835
1836static ssize_t store_pwm_auto_point_channel(struct device *dev,
1837 struct device_attribute *devattr,
1838 const char *buf, size_t count)
1839{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001840 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001841 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1842 long val;
1843
1844 err = strict_strtol(buf, 10, &val);
1845 if (err)
1846 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001847
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001848 switch (val) {
1849 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001850 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001851 break;
1852 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001853 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001854 break;
1855 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001856 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001857 break;
1858 default:
1859 return -EINVAL;
1860 }
Hans de Goede09475d32009-06-15 18:39:52 +02001861 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001862 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001863 data->pwm_auto_point_mapping[nr] =
1864 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001865 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1866 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1867 data->pwm_auto_point_mapping[nr] = val;
1868 mutex_unlock(&data->update_lock);
1869
1870 return count;
1871}
1872
1873static ssize_t show_pwm_auto_point_temp(struct device *dev,
1874 struct device_attribute *devattr,
1875 char *buf)
1876{
1877 int result;
1878 struct f71882fg_data *data = f71882fg_update_device(dev);
1879 int pwm = to_sensor_dev_attr_2(devattr)->index;
1880 int point = to_sensor_dev_attr_2(devattr)->nr;
1881
1882 result = data->pwm_auto_point_temp[pwm][point];
1883 return sprintf(buf, "%d\n", 1000 * result);
1884}
1885
1886static ssize_t store_pwm_auto_point_temp(struct device *dev,
1887 struct device_attribute *devattr,
1888 const char *buf, size_t count)
1889{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001890 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001891 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001892 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001893 long val;
1894
1895 err = strict_strtol(buf, 10, &val);
1896 if (err)
1897 return err;
1898
1899 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001900
Giel van Schijndel7721fea2010-08-09 17:21:13 -07001901 if (data->type == f71889fg
1902 || data->type == f71808fg)
Hans de Goede76698962009-12-09 20:36:01 +01001903 val = SENSORS_LIMIT(val, -128, 127);
1904 else
1905 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001906
1907 mutex_lock(&data->update_lock);
1908 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1909 data->pwm_auto_point_temp[pwm][point] = val;
1910 mutex_unlock(&data->update_lock);
1911
1912 return count;
1913}
1914
Hans de Goede45fb3662007-07-13 14:34:19 +02001915static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1916 char *buf)
1917{
Hans de Goede498be962009-01-07 16:37:28 +01001918 struct f71882fg_data *data = dev_get_drvdata(dev);
1919 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001920}
1921
Hans de Goedec13548c2009-01-07 16:37:27 +01001922static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1923 struct sensor_device_attribute_2 *attr, int count)
1924{
1925 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001926
Hans de Goedec13548c2009-01-07 16:37:27 +01001927 for (i = 0; i < count; i++) {
1928 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1929 if (err)
1930 return err;
1931 }
1932 return 0;
1933}
1934
Hans de Goedefc16c562009-12-09 20:36:01 +01001935static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1936 struct sensor_device_attribute_2 *attr, int count)
1937{
1938 int i;
1939
1940 for (i = 0; i < count; i++)
1941 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1942}
1943
Hans de Goedec13548c2009-01-07 16:37:27 +01001944static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001945{
1946 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001947 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001948 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001949 u8 start_reg;
1950
Hans de Goedec13548c2009-01-07 16:37:27 +01001951 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1952 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001953 return -ENOMEM;
1954
1955 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001956 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001957 data->temp_start =
1958 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001959 mutex_init(&data->update_lock);
1960 platform_set_drvdata(pdev, data);
1961
Hans de Goede3cc74752009-01-07 16:37:28 +01001962 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001963 if (start_reg & 0x04) {
1964 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1965 err = -ENODEV;
1966 goto exit_free;
1967 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001968 if (!(start_reg & 0x03)) {
1969 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1970 err = -ENODEV;
1971 goto exit_free;
1972 }
1973
Hans de Goede45fb3662007-07-13 14:34:19 +02001974 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001975 err = device_create_file(&pdev->dev, &dev_attr_name);
1976 if (err)
1977 goto exit_unregister_sysfs;
1978
Hans de Goedec13548c2009-01-07 16:37:27 +01001979 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001980 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001981 case f71858fg:
1982 data->temp_config =
1983 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1984 if (data->temp_config & 0x10)
1985 /* The f71858fg temperature alarms behave as
1986 the f8000 alarms in this mode */
1987 err = f71882fg_create_sysfs_files(pdev,
1988 f8000_in_temp_attr,
1989 ARRAY_SIZE(f8000_in_temp_attr));
1990 else
1991 err = f71882fg_create_sysfs_files(pdev,
1992 f71858fg_in_temp_attr,
1993 ARRAY_SIZE(f71858fg_in_temp_attr));
1994 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001995 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001996 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001997 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001998 fxxxx_in1_alarm_attr,
1999 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002000 if (err)
2001 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002002 /* fall through! */
2003 case f71862fg:
2004 err = f71882fg_create_sysfs_files(pdev,
Giel van Schijndel7721fea2010-08-09 17:21:13 -07002005 f71862_temp_attr,
2006 ARRAY_SIZE(f71862_temp_attr));
2007 if (err)
2008 goto exit_unregister_sysfs;
2009 err = f71882fg_create_sysfs_files(pdev,
2010 fxxxx_in_attr,
2011 ARRAY_SIZE(fxxxx_in_attr));
2012 if (err)
2013 goto exit_unregister_sysfs;
2014 err = f71882fg_create_sysfs_files(pdev,
2015 fxxxx_temp_attr,
2016 ARRAY_SIZE(fxxxx_temp_attr));
2017 break;
2018 case f71808fg:
2019 err = f71882fg_create_sysfs_files(pdev,
2020 f71808_in_attr,
2021 ARRAY_SIZE(f71808_in_attr));
2022 if (err)
2023 goto exit_unregister_sysfs;
2024 err = f71882fg_create_sysfs_files(pdev,
2025 fxxxx_temp_attr,
2026 ARRAY_SIZE(fxxxx_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002027 break;
2028 case f8000:
2029 err = f71882fg_create_sysfs_files(pdev,
2030 f8000_in_temp_attr,
2031 ARRAY_SIZE(f8000_in_temp_attr));
2032 break;
Hans de Goede498be962009-01-07 16:37:28 +01002033 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002034 if (err)
2035 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02002036 }
2037
Hans de Goede45fb3662007-07-13 14:34:19 +02002038 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02002039 data->pwm_enable =
2040 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2041
2042 /* Sanity check the pwm settings */
2043 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002044 case f71858fg:
2045 err = 0;
2046 for (i = 0; i < nr_fans; i++)
2047 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2048 err = 1;
2049 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002050 case f71862fg:
2051 err = (data->pwm_enable & 0x15) != 0x15;
2052 break;
Giel van Schijndel7721fea2010-08-09 17:21:13 -07002053 case f71808fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002054 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002055 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002056 err = 0;
2057 break;
2058 case f8000:
2059 err = data->pwm_enable & 0x20;
2060 break;
2061 }
2062 if (err) {
2063 dev_err(&pdev->dev,
2064 "Invalid (reserved) pwm settings: 0x%02x\n",
2065 (unsigned int)data->pwm_enable);
2066 err = -ENODEV;
2067 goto exit_unregister_sysfs;
2068 }
2069
Hans de Goedeb69b0392009-12-09 20:36:00 +01002070 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2071 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002072 if (err)
2073 goto exit_unregister_sysfs;
2074
Hans de Goede76698962009-12-09 20:36:01 +01002075 if (data->type == f71862fg || data->type == f71882fg ||
2076 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002077 err = f71882fg_create_sysfs_files(pdev,
2078 fxxxx_fan_beep_attr, nr_fans);
2079 if (err)
2080 goto exit_unregister_sysfs;
2081 }
2082
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002083 switch (data->type) {
2084 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002085 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002086 f71862fg_auto_pwm_attr,
2087 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002088 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002089 case f8000:
2090 err = f71882fg_create_sysfs_files(pdev,
2091 f8000_fan_attr,
2092 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002093 if (err)
2094 goto exit_unregister_sysfs;
2095 err = f71882fg_create_sysfs_files(pdev,
2096 f8000_auto_pwm_attr,
2097 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002098 break;
Giel van Schijndel7721fea2010-08-09 17:21:13 -07002099 case f71808fg:
Hans de Goede76698962009-12-09 20:36:01 +01002100 case f71889fg:
2101 for (i = 0; i < nr_fans; i++) {
2102 data->pwm_auto_point_mapping[i] =
2103 f71882fg_read8(data,
2104 F71882FG_REG_POINT_MAPPING(i));
2105 if (data->pwm_auto_point_mapping[i] & 0x80)
2106 break;
2107 }
2108 if (i != nr_fans) {
2109 dev_warn(&pdev->dev,
2110 "Auto pwm controlled by raw digital "
2111 "data, disabling pwm auto_point "
2112 "sysfs attributes\n");
2113 break;
2114 }
2115 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002116 default: /* f71858fg / f71882fg */
2117 err = f71882fg_create_sysfs_files(pdev,
2118 &fxxxx_auto_pwm_attr[0][0],
2119 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002120 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002121 if (err)
2122 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002123
2124 for (i = 0; i < nr_fans; i++)
2125 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2126 (data->pwm_enable & (1 << 2 * i)) ?
2127 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002128 }
2129
Tony Jones1beeffe2007-08-20 13:46:20 -07002130 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2131 if (IS_ERR(data->hwmon_dev)) {
2132 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002133 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002134 goto exit_unregister_sysfs;
2135 }
2136
2137 return 0;
2138
2139exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002140 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002141 return err; /* f71882fg_remove() also frees our data */
2142exit_free:
2143 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002144 return err;
2145}
2146
Hans de Goedec13548c2009-01-07 16:37:27 +01002147static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002148{
Hans de Goede45fb3662007-07-13 14:34:19 +02002149 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002150 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2151 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002152
2153 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002154 if (data->hwmon_dev)
2155 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002156
Hans de Goedec13548c2009-01-07 16:37:27 +01002157 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002158
Hans de Goedefc16c562009-12-09 20:36:01 +01002159 if (start_reg & 0x01) {
2160 switch (data->type) {
2161 case f71858fg:
2162 if (data->temp_config & 0x10)
2163 f71882fg_remove_sysfs_files(pdev,
2164 f8000_in_temp_attr,
2165 ARRAY_SIZE(f8000_in_temp_attr));
2166 else
2167 f71882fg_remove_sysfs_files(pdev,
2168 f71858fg_in_temp_attr,
2169 ARRAY_SIZE(f71858fg_in_temp_attr));
2170 break;
2171 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002172 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002173 f71882fg_remove_sysfs_files(pdev,
2174 fxxxx_in1_alarm_attr,
2175 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2176 /* fall through! */
2177 case f71862fg:
2178 f71882fg_remove_sysfs_files(pdev,
Giel van Schijndel7721fea2010-08-09 17:21:13 -07002179 f71862_temp_attr,
2180 ARRAY_SIZE(f71862_temp_attr));
2181 f71882fg_remove_sysfs_files(pdev,
2182 fxxxx_in_attr,
2183 ARRAY_SIZE(fxxxx_in_attr));
2184 f71882fg_remove_sysfs_files(pdev,
2185 fxxxx_temp_attr,
2186 ARRAY_SIZE(fxxxx_temp_attr));
2187 break;
2188 case f71808fg:
2189 f71882fg_remove_sysfs_files(pdev,
2190 f71808_in_attr,
2191 ARRAY_SIZE(f71808_in_attr));
2192 f71882fg_remove_sysfs_files(pdev,
2193 fxxxx_temp_attr,
2194 ARRAY_SIZE(fxxxx_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002195 break;
2196 case f8000:
2197 f71882fg_remove_sysfs_files(pdev,
2198 f8000_in_temp_attr,
2199 ARRAY_SIZE(f8000_in_temp_attr));
2200 break;
2201 }
2202 }
Hans de Goede498be962009-01-07 16:37:28 +01002203
Hans de Goedefc16c562009-12-09 20:36:01 +01002204 if (start_reg & 0x02) {
2205 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2206 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002207
Hans de Goede76698962009-12-09 20:36:01 +01002208 if (data->type == f71862fg || data->type == f71882fg ||
2209 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002210 f71882fg_remove_sysfs_files(pdev,
2211 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002212
Hans de Goedefc16c562009-12-09 20:36:01 +01002213 switch (data->type) {
2214 case f71862fg:
2215 f71882fg_remove_sysfs_files(pdev,
2216 f71862fg_auto_pwm_attr,
2217 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2218 break;
2219 case f8000:
2220 f71882fg_remove_sysfs_files(pdev,
2221 f8000_fan_attr,
2222 ARRAY_SIZE(f8000_fan_attr));
2223 f71882fg_remove_sysfs_files(pdev,
2224 f8000_auto_pwm_attr,
2225 ARRAY_SIZE(f8000_auto_pwm_attr));
2226 break;
2227 default: /* f71858fg / f71882fg / f71889fg */
2228 f71882fg_remove_sysfs_files(pdev,
2229 &fxxxx_auto_pwm_attr[0][0],
2230 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2231 }
2232 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002233
Hans de Goede45fb3662007-07-13 14:34:19 +02002234 kfree(data);
2235
2236 return 0;
2237}
2238
Hans de Goede498be962009-01-07 16:37:28 +01002239static int __init f71882fg_find(int sioaddr, unsigned short *address,
2240 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002241{
2242 int err = -ENODEV;
2243 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002244
Giel van Schijndel729d2732010-05-27 19:58:43 +02002245 /* Don't step on other drivers' I/O space by accident */
2246 if (!request_region(sioaddr, 2, DRVNAME)) {
2247 printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
2248 (int)sioaddr);
2249 return -EBUSY;
2250 }
2251
Hans de Goede45fb3662007-07-13 14:34:19 +02002252 superio_enter(sioaddr);
2253
2254 devid = superio_inw(sioaddr, SIO_REG_MANID);
2255 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002256 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002257 goto exit;
2258 }
2259
Jean Delvare67b671b2007-12-06 23:13:42 +01002260 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002261 switch (devid) {
Giel van Schijndel7721fea2010-08-09 17:21:13 -07002262 case SIO_F71808_ID:
2263 sio_data->type = f71808fg;
2264 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002265 case SIO_F71858_ID:
2266 sio_data->type = f71858fg;
2267 break;
Hans de Goede498be962009-01-07 16:37:28 +01002268 case SIO_F71862_ID:
2269 sio_data->type = f71862fg;
2270 break;
2271 case SIO_F71882_ID:
2272 sio_data->type = f71882fg;
2273 break;
Hans de Goede76698962009-12-09 20:36:01 +01002274 case SIO_F71889_ID:
2275 sio_data->type = f71889fg;
2276 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002277 case SIO_F8000_ID:
2278 sio_data->type = f8000;
2279 break;
Hans de Goede498be962009-01-07 16:37:28 +01002280 default:
Hans de Goede76698962009-12-09 20:36:01 +01002281 printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
2282 (unsigned int)devid);
Hans de Goede45fb3662007-07-13 14:34:19 +02002283 goto exit;
2284 }
2285
Hans de Goede09475d32009-06-15 18:39:52 +02002286 if (sio_data->type == f71858fg)
2287 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2288 else
2289 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2290
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002291 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002292 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2293 goto exit;
2294 }
2295
2296 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002297 if (*address == 0) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002298 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2299 goto exit;
2300 }
2301 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2302
Hans de Goede45fb3662007-07-13 14:34:19 +02002303 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002304 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2305 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002306 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2307exit:
2308 superio_exit(sioaddr);
Giel van Schijndel729d2732010-05-27 19:58:43 +02002309 release_region(sioaddr, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02002310 return err;
2311}
2312
Hans de Goede498be962009-01-07 16:37:28 +01002313static int __init f71882fg_device_add(unsigned short address,
2314 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002315{
2316 struct resource res = {
2317 .start = address,
2318 .end = address + REGION_LENGTH - 1,
2319 .flags = IORESOURCE_IO,
2320 };
2321 int err;
2322
2323 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002324 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002325 return -ENOMEM;
2326
2327 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002328 err = acpi_check_resource_conflict(&res);
2329 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002330 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002331
Hans de Goede45fb3662007-07-13 14:34:19 +02002332 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002333 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002334 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2335 goto exit_device_put;
2336 }
2337
Hans de Goede498be962009-01-07 16:37:28 +01002338 err = platform_device_add_data(f71882fg_pdev, sio_data,
2339 sizeof(struct f71882fg_sio_data));
2340 if (err) {
2341 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2342 goto exit_device_put;
2343 }
2344
Hans de Goede45fb3662007-07-13 14:34:19 +02002345 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002346 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002347 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2348 goto exit_device_put;
2349 }
2350
2351 return 0;
2352
2353exit_device_put:
2354 platform_device_put(f71882fg_pdev);
2355
2356 return err;
2357}
2358
2359static int __init f71882fg_init(void)
2360{
2361 int err = -ENODEV;
2362 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002363 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002364
Hans de Goede498be962009-01-07 16:37:28 +01002365 memset(&sio_data, 0, sizeof(sio_data));
2366
2367 if (f71882fg_find(0x2e, &address, &sio_data) &&
2368 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002369 goto exit;
2370
Hans de Goedec13548c2009-01-07 16:37:27 +01002371 err = platform_driver_register(&f71882fg_driver);
2372 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002373 goto exit;
2374
Hans de Goede498be962009-01-07 16:37:28 +01002375 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002376 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002377 goto exit_driver;
2378
2379 return 0;
2380
2381exit_driver:
2382 platform_driver_unregister(&f71882fg_driver);
2383exit:
2384 return err;
2385}
2386
2387static void __exit f71882fg_exit(void)
2388{
2389 platform_device_unregister(f71882fg_pdev);
2390 platform_driver_unregister(&f71882fg_driver);
2391}
2392
2393MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002394MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002395MODULE_LICENSE("GPL");
2396
2397module_init(f71882fg_init);
2398module_exit(f71882fg_exit);