blob: 40dd6cf3e80d040e3f91e7472cf1710660e288cd [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 */
Hans de Goede09475d32009-06-15 18:39:52 +020048#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010049#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020050#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010051#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052
53#define REGION_LENGTH 8
54#define ADDR_REG_OFFSET 5
55#define DATA_REG_OFFSET 6
56
57#define F71882FG_REG_PECI 0x0A
58
Hans de Goede498be962009-01-07 16:37:28 +010059#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
60#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020061#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010062#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020063
64#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010065#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
66#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020067#define F71882FG_REG_FAN_STATUS 0x92
68#define F71882FG_REG_FAN_BEEP 0x93
69
Hans de Goede7567a042009-01-07 16:37:28 +010070#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
71#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
72#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020073#define F71882FG_REG_TEMP_STATUS 0x62
74#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020075#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010076#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020077#define F71882FG_REG_TEMP_TYPE 0x6B
78#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
79
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010080#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
81#define F71882FG_REG_PWM_TYPE 0x94
82#define F71882FG_REG_PWM_ENABLE 0x96
83
Hans de Goedebc274902009-01-07 16:37:29 +010084#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010085
86#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
87#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
88#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
89
Hans de Goede45fb3662007-07-13 14:34:19 +020090#define F71882FG_REG_START 0x01
91
92#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
93
Jean Delvare67b671b2007-12-06 23:13:42 +010094static unsigned short force_id;
95module_param(force_id, ushort, 0);
96MODULE_PARM_DESC(force_id, "Override the detected device ID");
97
Hans de Goede09475d32009-06-15 18:39:52 +020098enum chips { f71858fg, f71862fg, f71882fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +010099
100static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200101 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100102 "f71862fg",
103 "f71882fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100104 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100105};
106
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100107static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200108
109/* Super-I/O Function prototypes */
110static inline int superio_inb(int base, int reg);
111static inline int superio_inw(int base, int reg);
112static inline void superio_enter(int base);
113static inline void superio_select(int base, int ld);
114static inline void superio_exit(int base);
115
Hans de Goede498be962009-01-07 16:37:28 +0100116struct f71882fg_sio_data {
117 enum chips type;
118};
119
Hans de Goede45fb3662007-07-13 14:34:19 +0200120struct f71882fg_data {
121 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100122 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700123 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200124
125 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200126 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200127 char valid; /* !=0 if following fields are valid */
128 unsigned long last_updated; /* In jiffies */
129 unsigned long last_limits; /* In jiffies */
130
131 /* Register Values */
132 u8 in[9];
133 u8 in1_max;
134 u8 in_status;
135 u8 in_beep;
136 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100137 u16 fan_target[4];
138 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200139 u8 fan_status;
140 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100141 /* Note: all models have only 3 temperature channels, but on some
142 they are addressed as 0-2 and on others as 1-3, so for coding
143 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200144 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100145 u8 temp_ovt[4];
146 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100147 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100148 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200149 u8 temp_status;
150 u8 temp_beep;
151 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200152 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100153 u8 pwm[4];
154 u8 pwm_enable;
155 u8 pwm_auto_point_hyst[2];
156 u8 pwm_auto_point_mapping[4];
157 u8 pwm_auto_point_pwm[4][5];
158 u8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200159};
160
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100161/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200162static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
163 char *buf);
164static ssize_t show_in_max(struct device *dev, struct device_attribute
165 *devattr, char *buf);
166static ssize_t store_in_max(struct device *dev, struct device_attribute
167 *devattr, const char *buf, size_t count);
168static ssize_t show_in_beep(struct device *dev, struct device_attribute
169 *devattr, char *buf);
170static ssize_t store_in_beep(struct device *dev, struct device_attribute
171 *devattr, const char *buf, size_t count);
172static ssize_t show_in_alarm(struct device *dev, struct device_attribute
173 *devattr, char *buf);
174/* Sysfs Fan */
175static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
176 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100177static ssize_t show_fan_full_speed(struct device *dev,
178 struct device_attribute *devattr, char *buf);
179static ssize_t store_fan_full_speed(struct device *dev,
180 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200181static ssize_t show_fan_beep(struct device *dev, struct device_attribute
182 *devattr, char *buf);
183static ssize_t store_fan_beep(struct device *dev, struct device_attribute
184 *devattr, const char *buf, size_t count);
185static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
186 *devattr, char *buf);
187/* Sysfs Temp */
188static ssize_t show_temp(struct device *dev, struct device_attribute
189 *devattr, char *buf);
190static ssize_t show_temp_max(struct device *dev, struct device_attribute
191 *devattr, char *buf);
192static ssize_t store_temp_max(struct device *dev, struct device_attribute
193 *devattr, const char *buf, size_t count);
194static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
195 *devattr, char *buf);
196static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
197 *devattr, const char *buf, size_t count);
198static ssize_t show_temp_crit(struct device *dev, struct device_attribute
199 *devattr, char *buf);
200static ssize_t store_temp_crit(struct device *dev, struct device_attribute
201 *devattr, const char *buf, size_t count);
202static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
203 *devattr, char *buf);
204static ssize_t show_temp_type(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_beep(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t store_temp_beep(struct device *dev, struct device_attribute
209 *devattr, const char *buf, size_t count);
210static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212static ssize_t show_temp_fault(struct device *dev, struct device_attribute
213 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100214/* PWM and Auto point control */
215static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
216 char *buf);
217static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
218 const char *buf, size_t count);
219static ssize_t show_pwm_enable(struct device *dev,
220 struct device_attribute *devattr, char *buf);
221static ssize_t store_pwm_enable(struct device *dev,
222 struct device_attribute *devattr, const char *buf, size_t count);
223static ssize_t show_pwm_interpolate(struct device *dev,
224 struct device_attribute *devattr, char *buf);
225static ssize_t store_pwm_interpolate(struct device *dev,
226 struct device_attribute *devattr, const char *buf, size_t count);
227static ssize_t show_pwm_auto_point_channel(struct device *dev,
228 struct device_attribute *devattr, char *buf);
229static ssize_t store_pwm_auto_point_channel(struct device *dev,
230 struct device_attribute *devattr, const char *buf, size_t count);
231static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
232 struct device_attribute *devattr, char *buf);
233static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
234 struct device_attribute *devattr, const char *buf, size_t count);
235static ssize_t show_pwm_auto_point_pwm(struct device *dev,
236 struct device_attribute *devattr, char *buf);
237static ssize_t store_pwm_auto_point_pwm(struct device *dev,
238 struct device_attribute *devattr, const char *buf, size_t count);
239static ssize_t show_pwm_auto_point_temp(struct device *dev,
240 struct device_attribute *devattr, char *buf);
241static ssize_t store_pwm_auto_point_temp(struct device *dev,
242 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200243/* Sysfs misc */
244static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
245 char *buf);
246
247static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100248static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200249
250static struct platform_driver f71882fg_driver = {
251 .driver = {
252 .owner = THIS_MODULE,
253 .name = DRVNAME,
254 },
255 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200256 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200257};
258
Hans de Goedec13548c2009-01-07 16:37:27 +0100259static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200260
Hans de Goede66344aa2009-12-09 20:35:59 +0100261/* Temp and in attr for the f71858fg, the f71858fg is special as it
262 has its temperature indexes start at 0 (the others start at 1) and
263 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200264static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
265 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
266 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
267 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
268 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
269 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
270 store_temp_max, 0, 0),
271 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
272 store_temp_max_hyst, 0, 0),
273 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
274 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
275 store_temp_crit, 0, 0),
276 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
277 0, 0),
278 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
279 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
280 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
281 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
282 store_temp_max, 0, 1),
283 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
284 store_temp_max_hyst, 0, 1),
285 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
286 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
287 store_temp_crit, 0, 1),
288 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
289 0, 1),
290 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
291 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
292 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
293 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
294 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
295 store_temp_max, 0, 2),
296 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
297 store_temp_max_hyst, 0, 2),
298 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
299 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
300 store_temp_crit, 0, 2),
301 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
302 0, 2),
303 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
304 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
305};
306
Hans de Goede66344aa2009-12-09 20:35:59 +0100307/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
308static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100309 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
310 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100311 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
312 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
313 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
314 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
315 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
316 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
317 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100318 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100319 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100320 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100321 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100322 store_temp_max_hyst, 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100323 /* Should really be temp1_max_alarm, but older versions did not handle
324 the max and crit alarms separately and lm_sensors v2 depends on the
325 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
326 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
327 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
328 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100329 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100330 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100331 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100332 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100333 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
334 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
335 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100336 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100337 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
338 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
339 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100340 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100341 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100342 store_temp_max_hyst, 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100343 /* Should be temp2_max_alarm, see temp1_alarm note */
344 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
345 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
346 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100348 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100349 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100350 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100351 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
352 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
353 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100354 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100355 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
356 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
357 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
358 store_temp_max, 0, 3),
359 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
360 store_temp_max_hyst, 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100361 /* Should be temp3_max_alarm, see temp1_alarm note */
362 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
363 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
364 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100365 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
366 store_temp_crit, 0, 3),
367 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
368 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100369 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
370 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
371 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100372 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100373 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200374};
375
Hans de Goede66344aa2009-12-09 20:35:59 +0100376/* For models with in1 alarm capability */
377static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100378 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
379 0, 1),
380 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
381 0, 1),
382 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
383};
384
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100385/* Temp and in attr for the f8000
386 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
387 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100388 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100389 */
390static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
391 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
392 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
393 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
394 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
395 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
396 store_temp_crit, 0, 0),
397 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
398 store_temp_max, 0, 0),
399 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200400 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100401 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
402 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
403 store_temp_crit, 0, 1),
404 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
405 store_temp_max, 0, 1),
406 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
407 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200408 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100409 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
410 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
411 store_temp_crit, 0, 2),
412 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
413 store_temp_max, 0, 2),
414 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200415 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100416};
417
418/* Fan / PWM attr common to all models */
419static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100420 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100421 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
422 show_fan_full_speed,
423 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100424 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
425 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
427 show_fan_full_speed,
428 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100429 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
430 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100431 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
432 show_fan_full_speed,
433 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100434 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100435
436 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
437 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
438 store_pwm_enable, 0, 0),
439 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
440 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100441
442 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
443 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
444 store_pwm_enable, 0, 1),
445 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
446 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100447
Hans de Goede3fc78382009-06-15 18:39:50 +0200448 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
449 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
450 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100451 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
452 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100453};
454
Hans de Goede66344aa2009-12-09 20:35:59 +0100455/* Attr for models which can beep on Fan alarm */
456static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100457 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
458 store_fan_beep, 0, 0),
459 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
460 store_fan_beep, 0, 1),
461 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
462 store_fan_beep, 0, 2),
Hans de Goede66344aa2009-12-09 20:35:59 +0100463};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100464
Hans de Goede66344aa2009-12-09 20:35:59 +0100465/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
466 f71858fg / f71882fg / f71889fg */
467static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
468 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
469 show_pwm_auto_point_channel,
470 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100471 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
472 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
473 1, 0),
474 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
475 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
476 4, 0),
477 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
478 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
479 0, 0),
480 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
481 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
482 3, 0),
483 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
484 show_pwm_auto_point_temp_hyst,
485 store_pwm_auto_point_temp_hyst,
486 0, 0),
487 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
488 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
489
Hans de Goede66344aa2009-12-09 20:35:59 +0100490 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
491 show_pwm_auto_point_channel,
492 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100493 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
494 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
495 1, 1),
496 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
497 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
498 4, 1),
499 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
500 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
501 0, 1),
502 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
503 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
504 3, 1),
505 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
506 show_pwm_auto_point_temp_hyst,
507 store_pwm_auto_point_temp_hyst,
508 0, 1),
509 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
510 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100511
Hans de Goede66344aa2009-12-09 20:35:59 +0100512 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
513 show_pwm_auto_point_channel,
514 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100515 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
517 1, 2),
518 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
520 4, 2),
521 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
522 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
523 0, 2),
524 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
525 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
526 3, 2),
527 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
528 show_pwm_auto_point_temp_hyst,
529 store_pwm_auto_point_temp_hyst,
530 0, 2),
531 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
532 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100533};
534
Hans de Goede66344aa2009-12-09 20:35:59 +0100535/* PWM attr common to the f71858fg, f71882fg and f71889fg */
536static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[] = {
537 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
538 show_pwm_auto_point_channel,
539 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100540 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
541 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
542 0, 0),
543 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
544 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
545 1, 0),
546 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
547 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
548 2, 0),
549 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
550 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
551 3, 0),
552 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
553 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
554 4, 0),
555 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
556 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
557 0, 0),
558 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
559 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
560 1, 0),
561 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
562 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
563 2, 0),
564 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
565 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
566 3, 0),
567 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
568 show_pwm_auto_point_temp_hyst,
569 store_pwm_auto_point_temp_hyst,
570 0, 0),
571 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
572 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
573 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
574 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
575 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
576 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
577
Hans de Goede66344aa2009-12-09 20:35:59 +0100578 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_channel,
580 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100581 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
583 0, 1),
584 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
585 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
586 1, 1),
587 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
588 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
589 2, 1),
590 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
592 3, 1),
593 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
595 4, 1),
596 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
598 0, 1),
599 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
601 1, 1),
602 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
604 2, 1),
605 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
606 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
607 3, 1),
608 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
609 show_pwm_auto_point_temp_hyst,
610 store_pwm_auto_point_temp_hyst,
611 0, 1),
612 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
613 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
614 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
615 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
616 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
617 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
618
Hans de Goede66344aa2009-12-09 20:35:59 +0100619 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_channel,
621 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100622 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
624 0, 2),
625 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
627 1, 2),
628 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 2, 2),
631 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
633 3, 2),
634 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 4, 2),
637 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
639 0, 2),
640 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 1, 2),
643 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
645 2, 2),
646 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
648 3, 2),
649 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_temp_hyst,
651 store_pwm_auto_point_temp_hyst,
652 0, 2),
653 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
654 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
655 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
656 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
657 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
658 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede09475d32009-06-15 18:39:52 +0200659};
660
661/* Fan / PWM attr found on the f71882fg but not on the f71858fg */
Hans de Goede66344aa2009-12-09 20:35:59 +0100662static struct sensor_device_attribute_2 f71882fg_auto_pwm_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200663 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
664 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
665 show_fan_full_speed,
666 store_fan_full_speed, 0, 3),
667 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
668 store_fan_beep, 0, 3),
669 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100670
671 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
672 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
673 store_pwm_enable, 0, 3),
674 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
675 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
676 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_channel,
678 store_pwm_auto_point_channel, 0, 3),
679 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
681 0, 3),
682 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
684 1, 3),
685 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
686 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
687 2, 3),
688 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
689 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
690 3, 3),
691 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
692 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
693 4, 3),
694 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
695 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
696 0, 3),
697 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
698 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
699 1, 3),
700 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
701 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
702 2, 3),
703 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
705 3, 3),
706 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_temp_hyst,
708 store_pwm_auto_point_temp_hyst,
709 0, 3),
710 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
712 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
714 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
715 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200716};
717
Hans de Goede66344aa2009-12-09 20:35:59 +0100718/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100719static struct sensor_device_attribute_2 f8000_fan_attr[] = {
720 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100721};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100722
Hans de Goede66344aa2009-12-09 20:35:59 +0100723/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
724 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
725 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
726static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
727 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
728 show_pwm_auto_point_channel,
729 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100730 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
731 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
732 0, 2),
733 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
734 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
735 1, 2),
736 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
737 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
738 2, 2),
739 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
740 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
741 3, 2),
742 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
743 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
744 4, 2),
745 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
746 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
747 0, 2),
748 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
749 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
750 1, 2),
751 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
752 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
753 2, 2),
754 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
755 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
756 3, 2),
757 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_temp_hyst,
759 store_pwm_auto_point_temp_hyst,
760 0, 2),
761 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
763 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
765 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
766 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
767
Hans de Goede66344aa2009-12-09 20:35:59 +0100768 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_channel,
770 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100771 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
773 0, 0),
774 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
776 1, 0),
777 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
778 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
779 2, 0),
780 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
781 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
782 3, 0),
783 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
784 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
785 4, 0),
786 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
787 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
788 0, 0),
789 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
790 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
791 1, 0),
792 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
793 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
794 2, 0),
795 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
796 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
797 3, 0),
798 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
799 show_pwm_auto_point_temp_hyst,
800 store_pwm_auto_point_temp_hyst,
801 0, 0),
802 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
804 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
806 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
807 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
808
Hans de Goede66344aa2009-12-09 20:35:59 +0100809 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_channel,
811 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100812 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
814 0, 1),
815 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
817 1, 1),
818 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
819 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
820 2, 1),
821 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
822 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
823 3, 1),
824 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
825 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
826 4, 1),
827 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
828 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
829 0, 1),
830 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
831 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
832 1, 1),
833 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
834 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
835 2, 1),
836 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
837 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
838 3, 1),
839 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
840 show_pwm_auto_point_temp_hyst,
841 store_pwm_auto_point_temp_hyst,
842 0, 1),
843 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
845 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
847 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
848 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
849};
Hans de Goede45fb3662007-07-13 14:34:19 +0200850
851/* Super I/O functions */
852static inline int superio_inb(int base, int reg)
853{
854 outb(reg, base);
855 return inb(base + 1);
856}
857
858static int superio_inw(int base, int reg)
859{
860 int val;
861 outb(reg++, base);
862 val = inb(base + 1) << 8;
863 outb(reg, base);
864 val |= inb(base + 1);
865 return val;
866}
867
868static inline void superio_enter(int base)
869{
870 /* according to the datasheet the key must be send twice! */
871 outb( SIO_UNLOCK_KEY, base);
872 outb( SIO_UNLOCK_KEY, base);
873}
874
875static inline void superio_select( int base, int ld)
876{
877 outb(SIO_REG_LDSEL, base);
878 outb(ld, base + 1);
879}
880
881static inline void superio_exit(int base)
882{
883 outb(SIO_LOCK_KEY, base);
884}
885
Hans de Goede2f650632009-01-07 16:37:31 +0100886static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200887{
888 return reg ? (1500000 / reg) : 0;
889}
890
Hans de Goede2f650632009-01-07 16:37:31 +0100891static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100892{
893 return fan ? (1500000 / fan) : 0;
894}
895
Hans de Goede45fb3662007-07-13 14:34:19 +0200896static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
897{
898 u8 val;
899
900 outb(reg, data->addr + ADDR_REG_OFFSET);
901 val = inb(data->addr + DATA_REG_OFFSET);
902
903 return val;
904}
905
906static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
907{
908 u16 val;
909
910 outb(reg++, data->addr + ADDR_REG_OFFSET);
911 val = inb(data->addr + DATA_REG_OFFSET) << 8;
912 outb(reg, data->addr + ADDR_REG_OFFSET);
913 val |= inb(data->addr + DATA_REG_OFFSET);
914
915 return val;
916}
917
918static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
919{
920 outb(reg, data->addr + ADDR_REG_OFFSET);
921 outb(val, data->addr + DATA_REG_OFFSET);
922}
923
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100924static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
925{
926 outb(reg++, data->addr + ADDR_REG_OFFSET);
927 outb(val >> 8, data->addr + DATA_REG_OFFSET);
928 outb(reg, data->addr + ADDR_REG_OFFSET);
929 outb(val & 255, data->addr + DATA_REG_OFFSET);
930}
931
Hans de Goede09475d32009-06-15 18:39:52 +0200932static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
933{
934 if (data->type == f71858fg)
935 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
936 else
937 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
938}
939
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100940static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200941{
942 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100943 int nr, reg = 0, reg2;
944 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200945 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200946
947 mutex_lock(&data->update_lock);
948
949 /* Update once every 60 seconds */
950 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
951 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100952 if (data->type == f71882fg) {
953 data->in1_max =
954 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
955 data->in_beep =
956 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
957 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200958
959 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200960 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200961 data->temp_ovt[nr] = f71882fg_read8(data,
962 F71882FG_REG_TEMP_OVT(nr));
963 data->temp_high[nr] = f71882fg_read8(data,
964 F71882FG_REG_TEMP_HIGH(nr));
965 }
966
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100967 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100968 data->temp_hyst[0] = f71882fg_read8(data,
969 F71882FG_REG_TEMP_HYST(0));
970 data->temp_hyst[1] = f71882fg_read8(data,
971 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200972 }
973
974 if (data->type == f71862fg || data->type == f71882fg) {
975 data->fan_beep = f71882fg_read8(data,
976 F71882FG_REG_FAN_BEEP);
977 data->temp_beep = f71882fg_read8(data,
978 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100979 /* Have to hardcode type, because temp1 is special */
980 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
981 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
982 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
983 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200984 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
985 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100986 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200987 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100988 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goede09475d32009-06-15 18:39:52 +0200989 else if (data->type == f71862fg || data->type == f71882fg)
Hans de Goede7567a042009-01-07 16:37:28 +0100990 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100991 else
Hans de Goede09475d32009-06-15 18:39:52 +0200992 data->temp_type[1] = 2; /* Only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200993
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100994 data->pwm_enable = f71882fg_read8(data,
995 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100996 data->pwm_auto_point_hyst[0] =
997 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
998 data->pwm_auto_point_hyst[1] =
999 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1000
Hans de Goede498be962009-01-07 16:37:28 +01001001 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001002 data->pwm_auto_point_mapping[nr] =
1003 f71882fg_read8(data,
1004 F71882FG_REG_POINT_MAPPING(nr));
1005
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001006 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001007 int point;
1008 for (point = 0; point < 5; point++) {
1009 data->pwm_auto_point_pwm[nr][point] =
1010 f71882fg_read8(data,
1011 F71882FG_REG_POINT_PWM
1012 (nr, point));
1013 }
1014 for (point = 0; point < 4; point++) {
1015 data->pwm_auto_point_temp[nr][point] =
1016 f71882fg_read8(data,
1017 F71882FG_REG_POINT_TEMP
1018 (nr, point));
1019 }
1020 } else {
1021 data->pwm_auto_point_pwm[nr][1] =
1022 f71882fg_read8(data,
1023 F71882FG_REG_POINT_PWM
1024 (nr, 1));
1025 data->pwm_auto_point_pwm[nr][4] =
1026 f71882fg_read8(data,
1027 F71882FG_REG_POINT_PWM
1028 (nr, 4));
1029 data->pwm_auto_point_temp[nr][0] =
1030 f71882fg_read8(data,
1031 F71882FG_REG_POINT_TEMP
1032 (nr, 0));
1033 data->pwm_auto_point_temp[nr][3] =
1034 f71882fg_read8(data,
1035 F71882FG_REG_POINT_TEMP
1036 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001037 }
1038 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001039 data->last_limits = jiffies;
1040 }
1041
1042 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001043 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001044 data->temp_status = f71882fg_read8(data,
1045 F71882FG_REG_TEMP_STATUS);
1046 data->temp_diode_open = f71882fg_read8(data,
1047 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001048 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1049 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001050
1051 data->fan_status = f71882fg_read8(data,
1052 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001053 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001054 data->fan[nr] = f71882fg_read16(data,
1055 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001056 data->fan_target[nr] =
1057 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1058 data->fan_full_speed[nr] =
1059 f71882fg_read16(data,
1060 F71882FG_REG_FAN_FULL_SPEED(nr));
1061 data->pwm[nr] =
1062 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1063 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001064
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001065 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1066 if (data->type == f8000)
1067 data->fan[3] = f71882fg_read16(data,
1068 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +01001069 if (data->type == f71882fg)
1070 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001071 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001072 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001073 data->in[nr] = f71882fg_read8(data,
1074 F71882FG_REG_IN(nr));
1075
1076 data->last_updated = jiffies;
1077 data->valid = 1;
1078 }
1079
1080 mutex_unlock(&data->update_lock);
1081
1082 return data;
1083}
1084
1085/* Sysfs Interface */
1086static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1087 char *buf)
1088{
1089 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001090 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001091 int speed = fan_from_reg(data->fan[nr]);
1092
1093 if (speed == FAN_MIN_DETECT)
1094 speed = 0;
1095
1096 return sprintf(buf, "%d\n", speed);
1097}
1098
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001099static ssize_t show_fan_full_speed(struct device *dev,
1100 struct device_attribute *devattr, char *buf)
1101{
1102 struct f71882fg_data *data = f71882fg_update_device(dev);
1103 int nr = to_sensor_dev_attr_2(devattr)->index;
1104 int speed = fan_from_reg(data->fan_full_speed[nr]);
1105 return sprintf(buf, "%d\n", speed);
1106}
1107
1108static ssize_t store_fan_full_speed(struct device *dev,
1109 struct device_attribute *devattr,
1110 const char *buf, size_t count)
1111{
1112 struct f71882fg_data *data = dev_get_drvdata(dev);
1113 int nr = to_sensor_dev_attr_2(devattr)->index;
1114 long val = simple_strtol(buf, NULL, 10);
1115
1116 val = SENSORS_LIMIT(val, 23, 1500000);
1117 val = fan_to_reg(val);
1118
1119 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001120 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1121 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001122 mutex_unlock(&data->update_lock);
1123
1124 return count;
1125}
1126
Hans de Goede45fb3662007-07-13 14:34:19 +02001127static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1128 *devattr, char *buf)
1129{
1130 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001131 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001132
1133 if (data->fan_beep & (1 << nr))
1134 return sprintf(buf, "1\n");
1135 else
1136 return sprintf(buf, "0\n");
1137}
1138
1139static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1140 *devattr, const char *buf, size_t count)
1141{
1142 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001143 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001144 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001145
1146 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001147 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001148 if (val)
1149 data->fan_beep |= 1 << nr;
1150 else
1151 data->fan_beep &= ~(1 << nr);
1152
1153 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1154 mutex_unlock(&data->update_lock);
1155
1156 return count;
1157}
1158
1159static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1160 *devattr, char *buf)
1161{
1162 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001163 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001164
1165 if (data->fan_status & (1 << nr))
1166 return sprintf(buf, "1\n");
1167 else
1168 return sprintf(buf, "0\n");
1169}
1170
1171static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1172 char *buf)
1173{
1174 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001175 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001176
1177 return sprintf(buf, "%d\n", data->in[nr] * 8);
1178}
1179
1180static ssize_t show_in_max(struct device *dev, struct device_attribute
1181 *devattr, char *buf)
1182{
1183 struct f71882fg_data *data = f71882fg_update_device(dev);
1184
1185 return sprintf(buf, "%d\n", data->in1_max * 8);
1186}
1187
1188static ssize_t store_in_max(struct device *dev, struct device_attribute
1189 *devattr, const char *buf, size_t count)
1190{
1191 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001192 long val = simple_strtol(buf, NULL, 10) / 8;
1193 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001194
1195 mutex_lock(&data->update_lock);
1196 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1197 data->in1_max = val;
1198 mutex_unlock(&data->update_lock);
1199
1200 return count;
1201}
1202
1203static ssize_t show_in_beep(struct device *dev, struct device_attribute
1204 *devattr, char *buf)
1205{
1206 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001207 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001208
1209 if (data->in_beep & (1 << nr))
1210 return sprintf(buf, "1\n");
1211 else
1212 return sprintf(buf, "0\n");
1213}
1214
1215static ssize_t store_in_beep(struct device *dev, struct device_attribute
1216 *devattr, const char *buf, size_t count)
1217{
1218 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001219 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001220 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001221
1222 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001223 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001224 if (val)
1225 data->in_beep |= 1 << nr;
1226 else
1227 data->in_beep &= ~(1 << nr);
1228
1229 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1230 mutex_unlock(&data->update_lock);
1231
1232 return count;
1233}
1234
1235static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1236 *devattr, char *buf)
1237{
1238 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001239 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001240
1241 if (data->in_status & (1 << nr))
1242 return sprintf(buf, "1\n");
1243 else
1244 return sprintf(buf, "0\n");
1245}
1246
1247static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1248 char *buf)
1249{
1250 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001251 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001252 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001253
Hans de Goede09475d32009-06-15 18:39:52 +02001254 if (data->type == f71858fg) {
1255 /* TEMP_TABLE_SEL 1 or 3 ? */
1256 if (data->temp_config & 1) {
1257 sign = data->temp[nr] & 0x0001;
1258 temp = (data->temp[nr] >> 5) & 0x7ff;
1259 } else {
1260 sign = data->temp[nr] & 0x8000;
1261 temp = (data->temp[nr] >> 5) & 0x3ff;
1262 }
1263 temp *= 125;
1264 if (sign)
1265 temp -= 128000;
1266 } else
1267 temp = data->temp[nr] * 1000;
1268
1269 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001270}
1271
1272static ssize_t show_temp_max(struct device *dev, struct device_attribute
1273 *devattr, char *buf)
1274{
1275 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001276 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001277
1278 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1279}
1280
1281static ssize_t store_temp_max(struct device *dev, struct device_attribute
1282 *devattr, const char *buf, size_t count)
1283{
1284 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001285 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001286 long val = simple_strtol(buf, NULL, 10) / 1000;
1287 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001288
1289 mutex_lock(&data->update_lock);
1290 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1291 data->temp_high[nr] = val;
1292 mutex_unlock(&data->update_lock);
1293
1294 return count;
1295}
1296
1297static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1298 *devattr, char *buf)
1299{
1300 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001301 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001302 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001303
Hans de Goedece0bfa52009-01-07 16:37:28 +01001304 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001305 if (nr & 1)
1306 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1307 else
1308 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1309 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001310 mutex_unlock(&data->update_lock);
1311
1312 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001313}
1314
1315static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1316 *devattr, const char *buf, size_t count)
1317{
1318 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001319 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001320 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001321 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001322 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001323
1324 mutex_lock(&data->update_lock);
1325
1326 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001327 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1328 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1329 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001330 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001331
1332 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001333 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1334 if (nr & 1)
1335 reg = (reg & 0x0f) | (val << 4);
1336 else
1337 reg = (reg & 0xf0) | val;
1338 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1339 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001340
Hans de Goede45fb3662007-07-13 14:34:19 +02001341 mutex_unlock(&data->update_lock);
1342 return ret;
1343}
1344
1345static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1346 *devattr, char *buf)
1347{
1348 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001349 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001350
1351 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1352}
1353
1354static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1355 *devattr, const char *buf, size_t count)
1356{
1357 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001358 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001359 long val = simple_strtol(buf, NULL, 10) / 1000;
1360 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001361
1362 mutex_lock(&data->update_lock);
1363 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1364 data->temp_ovt[nr] = val;
1365 mutex_unlock(&data->update_lock);
1366
1367 return count;
1368}
1369
1370static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1371 *devattr, char *buf)
1372{
1373 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001374 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001375 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001376
Hans de Goedece0bfa52009-01-07 16:37:28 +01001377 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001378 if (nr & 1)
1379 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1380 else
1381 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1382 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001383 mutex_unlock(&data->update_lock);
1384
1385 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001386}
1387
1388static ssize_t show_temp_type(struct device *dev, struct device_attribute
1389 *devattr, char *buf)
1390{
1391 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001392 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001393
1394 return sprintf(buf, "%d\n", data->temp_type[nr]);
1395}
1396
1397static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1398 *devattr, char *buf)
1399{
1400 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001401 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001402
Hans de Goede7567a042009-01-07 16:37:28 +01001403 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001404 return sprintf(buf, "1\n");
1405 else
1406 return sprintf(buf, "0\n");
1407}
1408
1409static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1410 *devattr, const char *buf, size_t count)
1411{
1412 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001413 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001414 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001415
1416 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001417 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001418 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001419 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001420 else
Hans de Goede7567a042009-01-07 16:37:28 +01001421 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001422
1423 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1424 mutex_unlock(&data->update_lock);
1425
1426 return count;
1427}
1428
1429static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1430 *devattr, char *buf)
1431{
1432 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001433 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001434
Hans de Goede7567a042009-01-07 16:37:28 +01001435 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001436 return sprintf(buf, "1\n");
1437 else
1438 return sprintf(buf, "0\n");
1439}
1440
1441static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1442 *devattr, char *buf)
1443{
1444 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001445 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001446
Hans de Goede7567a042009-01-07 16:37:28 +01001447 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001448 return sprintf(buf, "1\n");
1449 else
1450 return sprintf(buf, "0\n");
1451}
1452
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001453static ssize_t show_pwm(struct device *dev,
1454 struct device_attribute *devattr, char *buf)
1455{
1456 struct f71882fg_data *data = f71882fg_update_device(dev);
1457 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001458 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001459 if (data->pwm_enable & (1 << (2 * nr)))
1460 /* PWM mode */
1461 val = data->pwm[nr];
1462 else {
1463 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001464 val = 255 * fan_from_reg(data->fan_target[nr])
1465 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001466 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001467 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001468 return sprintf(buf, "%d\n", val);
1469}
1470
1471static ssize_t store_pwm(struct device *dev,
1472 struct device_attribute *devattr, const char *buf,
1473 size_t count)
1474{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001475 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001476 int nr = to_sensor_dev_attr_2(devattr)->index;
1477 long val = simple_strtol(buf, NULL, 10);
1478 val = SENSORS_LIMIT(val, 0, 255);
1479
1480 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001481 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001482 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1483 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1484 count = -EROFS;
1485 goto leave;
1486 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001487 if (data->pwm_enable & (1 << (2 * nr))) {
1488 /* PWM mode */
1489 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1490 data->pwm[nr] = val;
1491 } else {
1492 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001493 int target, full_speed;
1494 full_speed = f71882fg_read16(data,
1495 F71882FG_REG_FAN_FULL_SPEED(nr));
1496 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1497 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1498 data->fan_target[nr] = target;
1499 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001500 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001501leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001502 mutex_unlock(&data->update_lock);
1503
1504 return count;
1505}
1506
1507static ssize_t show_pwm_enable(struct device *dev,
1508 struct device_attribute *devattr, char *buf)
1509{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001510 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001511 struct f71882fg_data *data = f71882fg_update_device(dev);
1512 int nr = to_sensor_dev_attr_2(devattr)->index;
1513
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001514 switch ((data->pwm_enable >> 2 * nr) & 3) {
1515 case 0:
1516 case 1:
1517 result = 2; /* Normal auto mode */
1518 break;
1519 case 2:
1520 result = 1; /* Manual mode */
1521 break;
1522 case 3:
1523 if (data->type == f8000)
1524 result = 3; /* Thermostat mode */
1525 else
1526 result = 1; /* Manual mode */
1527 break;
1528 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001529
1530 return sprintf(buf, "%d\n", result);
1531}
1532
1533static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1534 *devattr, const char *buf, size_t count)
1535{
1536 struct f71882fg_data *data = dev_get_drvdata(dev);
1537 int nr = to_sensor_dev_attr_2(devattr)->index;
1538 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001539
Hans de Goede3fc78382009-06-15 18:39:50 +02001540 /* Special case for F8000 pwm channel 3 which only does auto mode */
1541 if (data->type == f8000 && nr == 2 && val != 2)
1542 return -EINVAL;
1543
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001544 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001545 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001546 /* Special case for F8000 auto PWM mode / Thermostat mode */
1547 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1548 switch (val) {
1549 case 2:
1550 data->pwm_enable &= ~(2 << (2 * nr));
1551 break; /* Normal auto mode */
1552 case 3:
1553 data->pwm_enable |= 2 << (2 * nr);
1554 break; /* Thermostat mode */
1555 default:
1556 count = -EINVAL;
1557 goto leave;
1558 }
1559 } else {
1560 switch (val) {
1561 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001562 /* The f71858fg does not support manual RPM mode */
1563 if (data->type == f71858fg &&
1564 ((data->pwm_enable >> (2 * nr)) & 1)) {
1565 count = -EINVAL;
1566 goto leave;
1567 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001568 data->pwm_enable |= 2 << (2 * nr);
1569 break; /* Manual */
1570 case 2:
1571 data->pwm_enable &= ~(2 << (2 * nr));
1572 break; /* Normal auto mode */
1573 default:
1574 count = -EINVAL;
1575 goto leave;
1576 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001577 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001578 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001579leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001580 mutex_unlock(&data->update_lock);
1581
1582 return count;
1583}
1584
1585static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1586 struct device_attribute *devattr,
1587 char *buf)
1588{
1589 int result;
1590 struct f71882fg_data *data = f71882fg_update_device(dev);
1591 int pwm = to_sensor_dev_attr_2(devattr)->index;
1592 int point = to_sensor_dev_attr_2(devattr)->nr;
1593
Hans de Goedece0bfa52009-01-07 16:37:28 +01001594 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001595 if (data->pwm_enable & (1 << (2 * pwm))) {
1596 /* PWM mode */
1597 result = data->pwm_auto_point_pwm[pwm][point];
1598 } else {
1599 /* RPM mode */
1600 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1601 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001602 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001603
1604 return sprintf(buf, "%d\n", result);
1605}
1606
1607static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1608 struct device_attribute *devattr,
1609 const char *buf, size_t count)
1610{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001611 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001612 int pwm = to_sensor_dev_attr_2(devattr)->index;
1613 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001614 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001615 val = SENSORS_LIMIT(val, 0, 255);
1616
1617 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001618 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001619 if (data->pwm_enable & (1 << (2 * pwm))) {
1620 /* PWM mode */
1621 } else {
1622 /* RPM mode */
1623 if (val < 29) /* Prevent negative numbers */
1624 val = 255;
1625 else
1626 val = (255 - val) * 32 / val;
1627 }
1628 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1629 data->pwm_auto_point_pwm[pwm][point] = val;
1630 mutex_unlock(&data->update_lock);
1631
1632 return count;
1633}
1634
1635static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1636 struct device_attribute *devattr,
1637 char *buf)
1638{
1639 int result = 0;
1640 struct f71882fg_data *data = f71882fg_update_device(dev);
1641 int nr = to_sensor_dev_attr_2(devattr)->index;
1642 int point = to_sensor_dev_attr_2(devattr)->nr;
1643
1644 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001645 if (nr & 1)
1646 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1647 else
1648 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001649 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1650 mutex_unlock(&data->update_lock);
1651
1652 return sprintf(buf, "%d\n", result);
1653}
1654
1655static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1656 struct device_attribute *devattr,
1657 const char *buf, size_t count)
1658{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001659 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001660 int nr = to_sensor_dev_attr_2(devattr)->index;
1661 int point = to_sensor_dev_attr_2(devattr)->nr;
1662 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001663 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001664
1665 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001666 data->pwm_auto_point_temp[nr][point] =
1667 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001668 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1669 data->pwm_auto_point_temp[nr][point]);
1670 val = data->pwm_auto_point_temp[nr][point] - val;
1671
Hans de Goedebc274902009-01-07 16:37:29 +01001672 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1673 if (nr & 1)
1674 reg = (reg & 0x0f) | (val << 4);
1675 else
1676 reg = (reg & 0xf0) | val;
1677
1678 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1679 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001680 mutex_unlock(&data->update_lock);
1681
1682 return count;
1683}
1684
1685static ssize_t show_pwm_interpolate(struct device *dev,
1686 struct device_attribute *devattr, char *buf)
1687{
1688 int result;
1689 struct f71882fg_data *data = f71882fg_update_device(dev);
1690 int nr = to_sensor_dev_attr_2(devattr)->index;
1691
1692 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1693
1694 return sprintf(buf, "%d\n", result);
1695}
1696
1697static ssize_t store_pwm_interpolate(struct device *dev,
1698 struct device_attribute *devattr,
1699 const char *buf, size_t count)
1700{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001701 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001702 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001703 unsigned long val = simple_strtoul(buf, NULL, 10);
1704
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001705 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001706 data->pwm_auto_point_mapping[nr] =
1707 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001708 if (val)
1709 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1710 else
1711 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1712 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1713 data->pwm_auto_point_mapping[nr] = val;
1714 mutex_unlock(&data->update_lock);
1715
1716 return count;
1717}
1718
1719static ssize_t show_pwm_auto_point_channel(struct device *dev,
1720 struct device_attribute *devattr,
1721 char *buf)
1722{
1723 int result;
1724 struct f71882fg_data *data = f71882fg_update_device(dev);
1725 int nr = to_sensor_dev_attr_2(devattr)->index;
1726
Hans de Goede09475d32009-06-15 18:39:52 +02001727 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1728 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001729
1730 return sprintf(buf, "%d\n", result);
1731}
1732
1733static ssize_t store_pwm_auto_point_channel(struct device *dev,
1734 struct device_attribute *devattr,
1735 const char *buf, size_t count)
1736{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001737 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001738 int nr = to_sensor_dev_attr_2(devattr)->index;
1739 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001740
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001741 switch (val) {
1742 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001743 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001744 break;
1745 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001746 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001747 break;
1748 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001749 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001750 break;
1751 default:
1752 return -EINVAL;
1753 }
Hans de Goede09475d32009-06-15 18:39:52 +02001754 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001755 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001756 data->pwm_auto_point_mapping[nr] =
1757 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001758 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1759 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1760 data->pwm_auto_point_mapping[nr] = val;
1761 mutex_unlock(&data->update_lock);
1762
1763 return count;
1764}
1765
1766static ssize_t show_pwm_auto_point_temp(struct device *dev,
1767 struct device_attribute *devattr,
1768 char *buf)
1769{
1770 int result;
1771 struct f71882fg_data *data = f71882fg_update_device(dev);
1772 int pwm = to_sensor_dev_attr_2(devattr)->index;
1773 int point = to_sensor_dev_attr_2(devattr)->nr;
1774
1775 result = data->pwm_auto_point_temp[pwm][point];
1776 return sprintf(buf, "%d\n", 1000 * result);
1777}
1778
1779static ssize_t store_pwm_auto_point_temp(struct device *dev,
1780 struct device_attribute *devattr,
1781 const char *buf, size_t count)
1782{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001783 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001784 int pwm = to_sensor_dev_attr_2(devattr)->index;
1785 int point = to_sensor_dev_attr_2(devattr)->nr;
1786 long val = simple_strtol(buf, NULL, 10) / 1000;
1787 val = SENSORS_LIMIT(val, 0, 255);
1788
1789 mutex_lock(&data->update_lock);
1790 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1791 data->pwm_auto_point_temp[pwm][point] = val;
1792 mutex_unlock(&data->update_lock);
1793
1794 return count;
1795}
1796
Hans de Goede45fb3662007-07-13 14:34:19 +02001797static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1798 char *buf)
1799{
Hans de Goede498be962009-01-07 16:37:28 +01001800 struct f71882fg_data *data = dev_get_drvdata(dev);
1801 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001802}
1803
Hans de Goedec13548c2009-01-07 16:37:27 +01001804static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1805 struct sensor_device_attribute_2 *attr, int count)
1806{
1807 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001808
Hans de Goedec13548c2009-01-07 16:37:27 +01001809 for (i = 0; i < count; i++) {
1810 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1811 if (err)
1812 return err;
1813 }
1814 return 0;
1815}
1816
1817static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001818{
1819 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001820 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001821 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001822 u8 start_reg;
1823
Hans de Goedec13548c2009-01-07 16:37:27 +01001824 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1825 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001826 return -ENOMEM;
1827
1828 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001829 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001830 data->temp_start =
1831 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001832 mutex_init(&data->update_lock);
1833 platform_set_drvdata(pdev, data);
1834
Hans de Goede3cc74752009-01-07 16:37:28 +01001835 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001836 if (start_reg & 0x04) {
1837 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1838 err = -ENODEV;
1839 goto exit_free;
1840 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001841 if (!(start_reg & 0x03)) {
1842 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1843 err = -ENODEV;
1844 goto exit_free;
1845 }
1846
Hans de Goede45fb3662007-07-13 14:34:19 +02001847 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001848 err = device_create_file(&pdev->dev, &dev_attr_name);
1849 if (err)
1850 goto exit_unregister_sysfs;
1851
Hans de Goedec13548c2009-01-07 16:37:27 +01001852 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001853 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001854 case f71858fg:
1855 data->temp_config =
1856 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1857 if (data->temp_config & 0x10)
1858 /* The f71858fg temperature alarms behave as
1859 the f8000 alarms in this mode */
1860 err = f71882fg_create_sysfs_files(pdev,
1861 f8000_in_temp_attr,
1862 ARRAY_SIZE(f8000_in_temp_attr));
1863 else
1864 err = f71882fg_create_sysfs_files(pdev,
1865 f71858fg_in_temp_attr,
1866 ARRAY_SIZE(f71858fg_in_temp_attr));
1867 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001868 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001869 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001870 fxxxx_in1_alarm_attr,
1871 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001872 if (err)
1873 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001874 /* fall through! */
1875 case f71862fg:
1876 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001877 fxxxx_in_temp_attr,
1878 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001879 break;
1880 case f8000:
1881 err = f71882fg_create_sysfs_files(pdev,
1882 f8000_in_temp_attr,
1883 ARRAY_SIZE(f8000_in_temp_attr));
1884 break;
Hans de Goede498be962009-01-07 16:37:28 +01001885 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001886 if (err)
1887 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001888 }
1889
Hans de Goede45fb3662007-07-13 14:34:19 +02001890 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001891 data->pwm_enable =
1892 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1893
1894 /* Sanity check the pwm settings */
1895 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001896 case f71858fg:
1897 err = 0;
1898 for (i = 0; i < nr_fans; i++)
1899 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1900 err = 1;
1901 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001902 case f71862fg:
1903 err = (data->pwm_enable & 0x15) != 0x15;
1904 break;
1905 case f71882fg:
1906 err = 0;
1907 break;
1908 case f8000:
1909 err = data->pwm_enable & 0x20;
1910 break;
1911 }
1912 if (err) {
1913 dev_err(&pdev->dev,
1914 "Invalid (reserved) pwm settings: 0x%02x\n",
1915 (unsigned int)data->pwm_enable);
1916 err = -ENODEV;
1917 goto exit_unregister_sysfs;
1918 }
1919
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001920 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1921 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001922 if (err)
1923 goto exit_unregister_sysfs;
1924
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001925 switch (data->type) {
1926 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001927 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001928 fxxxx_fan_beep_attr,
1929 ARRAY_SIZE(fxxxx_fan_beep_attr));
1930 if (err)
1931 goto exit_unregister_sysfs;
1932 err = f71882fg_create_sysfs_files(pdev,
1933 f71862fg_auto_pwm_attr,
1934 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001935 break;
1936 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001937 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001938 fxxxx_fan_beep_attr,
1939 ARRAY_SIZE(fxxxx_fan_beep_attr));
1940 if (err)
1941 goto exit_unregister_sysfs;
1942 err = f71882fg_create_sysfs_files(pdev,
1943 f71882fg_auto_pwm_attr,
1944 ARRAY_SIZE(f71882fg_auto_pwm_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001945 if (err)
1946 goto exit_unregister_sysfs;
1947 /* fall through! */
1948 case f71858fg:
1949 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001950 fxxxx_auto_pwm_attr,
1951 ARRAY_SIZE(fxxxx_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001952 break;
1953 case f8000:
1954 err = f71882fg_create_sysfs_files(pdev,
1955 f8000_fan_attr,
1956 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01001957 if (err)
1958 goto exit_unregister_sysfs;
1959 err = f71882fg_create_sysfs_files(pdev,
1960 f8000_auto_pwm_attr,
1961 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001962 break;
Hans de Goede498be962009-01-07 16:37:28 +01001963 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001964 if (err)
1965 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001966
1967 for (i = 0; i < nr_fans; i++)
1968 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1969 (data->pwm_enable & (1 << 2 * i)) ?
1970 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001971 }
1972
Tony Jones1beeffe2007-08-20 13:46:20 -07001973 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1974 if (IS_ERR(data->hwmon_dev)) {
1975 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001976 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001977 goto exit_unregister_sysfs;
1978 }
1979
1980 return 0;
1981
1982exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001983 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001984 return err; /* f71882fg_remove() also frees our data */
1985exit_free:
1986 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001987 return err;
1988}
1989
Hans de Goedec13548c2009-01-07 16:37:27 +01001990static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001991{
1992 int i;
1993 struct f71882fg_data *data = platform_get_drvdata(pdev);
1994
1995 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001996 if (data->hwmon_dev)
1997 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001998
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001999 /* Note we are not looping over all attr arrays we have as the ones
2000 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01002001 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002002
Hans de Goede66344aa2009-12-09 20:35:59 +01002003 for (i = 0; i < ARRAY_SIZE(fxxxx_in_temp_attr); i++)
Hans de Goede498be962009-01-07 16:37:28 +01002004 device_remove_file(&pdev->dev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002005 &fxxxx_in_temp_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01002006
Hans de Goede66344aa2009-12-09 20:35:59 +01002007 for (i = 0; i < ARRAY_SIZE(fxxxx_in1_alarm_attr); i++)
Hans de Goede45fb3662007-07-13 14:34:19 +02002008 device_remove_file(&pdev->dev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002009 &fxxxx_in1_alarm_attr[i].dev_attr);
Hans de Goede45fb3662007-07-13 14:34:19 +02002010
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002011 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
2012 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01002013
Hans de Goede66344aa2009-12-09 20:35:59 +01002014 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_beep_attr); i++)
2015 device_remove_file(&pdev->dev,
2016 &fxxxx_fan_beep_attr[i].dev_attr);
Hans de Goede45fb3662007-07-13 14:34:19 +02002017
Hans de Goede66344aa2009-12-09 20:35:59 +01002018 for (i = 0; i < ARRAY_SIZE(f71882fg_auto_pwm_attr); i++)
2019 device_remove_file(&pdev->dev,
2020 &f71882fg_auto_pwm_attr[i].dev_attr);
2021
2022 for (i = 0; i < ARRAY_SIZE(f8000_auto_pwm_attr); i++)
2023 device_remove_file(&pdev->dev,
2024 &f8000_auto_pwm_attr[i].dev_attr);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002025
Hans de Goede45fb3662007-07-13 14:34:19 +02002026 kfree(data);
2027
2028 return 0;
2029}
2030
Hans de Goede498be962009-01-07 16:37:28 +01002031static int __init f71882fg_find(int sioaddr, unsigned short *address,
2032 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002033{
2034 int err = -ENODEV;
2035 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002036
2037 superio_enter(sioaddr);
2038
2039 devid = superio_inw(sioaddr, SIO_REG_MANID);
2040 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002041 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002042 goto exit;
2043 }
2044
Jean Delvare67b671b2007-12-06 23:13:42 +01002045 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002046 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002047 case SIO_F71858_ID:
2048 sio_data->type = f71858fg;
2049 break;
Hans de Goede498be962009-01-07 16:37:28 +01002050 case SIO_F71862_ID:
2051 sio_data->type = f71862fg;
2052 break;
2053 case SIO_F71882_ID:
2054 sio_data->type = f71882fg;
2055 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002056 case SIO_F8000_ID:
2057 sio_data->type = f8000;
2058 break;
Hans de Goede498be962009-01-07 16:37:28 +01002059 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02002060 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
2061 goto exit;
2062 }
2063
Hans de Goede09475d32009-06-15 18:39:52 +02002064 if (sio_data->type == f71858fg)
2065 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2066 else
2067 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2068
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002069 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002070 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2071 goto exit;
2072 }
2073
2074 *address = superio_inw(sioaddr, SIO_REG_ADDR);
2075 if (*address == 0)
2076 {
2077 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2078 goto exit;
2079 }
2080 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2081
Hans de Goede45fb3662007-07-13 14:34:19 +02002082 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002083 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2084 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002085 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2086exit:
2087 superio_exit(sioaddr);
2088 return err;
2089}
2090
Hans de Goede498be962009-01-07 16:37:28 +01002091static int __init f71882fg_device_add(unsigned short address,
2092 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002093{
2094 struct resource res = {
2095 .start = address,
2096 .end = address + REGION_LENGTH - 1,
2097 .flags = IORESOURCE_IO,
2098 };
2099 int err;
2100
2101 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002102 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002103 return -ENOMEM;
2104
2105 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002106 err = acpi_check_resource_conflict(&res);
2107 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002108 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002109
Hans de Goede45fb3662007-07-13 14:34:19 +02002110 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002111 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002112 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2113 goto exit_device_put;
2114 }
2115
Hans de Goede498be962009-01-07 16:37:28 +01002116 err = platform_device_add_data(f71882fg_pdev, sio_data,
2117 sizeof(struct f71882fg_sio_data));
2118 if (err) {
2119 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2120 goto exit_device_put;
2121 }
2122
Hans de Goede45fb3662007-07-13 14:34:19 +02002123 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002124 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002125 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2126 goto exit_device_put;
2127 }
2128
2129 return 0;
2130
2131exit_device_put:
2132 platform_device_put(f71882fg_pdev);
2133
2134 return err;
2135}
2136
2137static int __init f71882fg_init(void)
2138{
2139 int err = -ENODEV;
2140 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002141 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002142
Hans de Goede498be962009-01-07 16:37:28 +01002143 memset(&sio_data, 0, sizeof(sio_data));
2144
2145 if (f71882fg_find(0x2e, &address, &sio_data) &&
2146 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002147 goto exit;
2148
Hans de Goedec13548c2009-01-07 16:37:27 +01002149 err = platform_driver_register(&f71882fg_driver);
2150 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002151 goto exit;
2152
Hans de Goede498be962009-01-07 16:37:28 +01002153 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002154 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002155 goto exit_driver;
2156
2157 return 0;
2158
2159exit_driver:
2160 platform_driver_unregister(&f71882fg_driver);
2161exit:
2162 return err;
2163}
2164
2165static void __exit f71882fg_exit(void)
2166{
2167 platform_device_unregister(f71882fg_pdev);
2168 platform_driver_unregister(&f71882fg_driver);
2169}
2170
2171MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002172MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002173MODULE_LICENSE("GPL");
2174
2175module_init(f71882fg_init);
2176module_exit(f71882fg_exit);