blob: 3a695f06905e2abcf1b9ad2ce89f7e50a6499c39 [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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100419static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
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),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100425 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
426 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
427 store_pwm_enable, 0, 0),
428 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
429 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100430}, {
431 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
432 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
433 show_fan_full_speed,
434 store_fan_full_speed, 0, 1),
435 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100436 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
437 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
438 store_pwm_enable, 0, 1),
439 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
440 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100441}, {
442 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
443 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
444 show_fan_full_speed,
445 store_fan_full_speed, 0, 2),
446 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200447 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
448 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
449 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100450 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
451 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100452}, {
453 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
454 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
455 show_fan_full_speed,
456 store_fan_full_speed, 0, 3),
457 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
458 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
459 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
460 store_pwm_enable, 0, 3),
461 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
462 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
463} };
Hans de Goede498be962009-01-07 16:37:28 +0100464
Hans de Goede66344aa2009-12-09 20:35:59 +0100465/* Attr for models which can beep on Fan alarm */
466static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100467 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
468 store_fan_beep, 0, 0),
469 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
470 store_fan_beep, 0, 1),
471 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
472 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100473 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100475};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100476
Hans de Goede66344aa2009-12-09 20:35:59 +0100477/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
478 f71858fg / f71882fg / f71889fg */
479static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
480 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
481 show_pwm_auto_point_channel,
482 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100483 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
484 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
485 1, 0),
486 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
487 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
488 4, 0),
489 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
490 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
491 0, 0),
492 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
493 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
494 3, 0),
495 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
496 show_pwm_auto_point_temp_hyst,
497 store_pwm_auto_point_temp_hyst,
498 0, 0),
499 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
500 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
501
Hans de Goede66344aa2009-12-09 20:35:59 +0100502 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
503 show_pwm_auto_point_channel,
504 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100505 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
506 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
507 1, 1),
508 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
509 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
510 4, 1),
511 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
512 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
513 0, 1),
514 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
515 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
516 3, 1),
517 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
518 show_pwm_auto_point_temp_hyst,
519 store_pwm_auto_point_temp_hyst,
520 0, 1),
521 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
522 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100523
Hans de Goede66344aa2009-12-09 20:35:59 +0100524 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
525 show_pwm_auto_point_channel,
526 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100527 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
528 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
529 1, 2),
530 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
531 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
532 4, 2),
533 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
534 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
535 0, 2),
536 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
537 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
538 3, 2),
539 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
540 show_pwm_auto_point_temp_hyst,
541 store_pwm_auto_point_temp_hyst,
542 0, 2),
543 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
544 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100545};
546
Hans de Goede66344aa2009-12-09 20:35:59 +0100547/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100548static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100549 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
550 show_pwm_auto_point_channel,
551 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100552 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
553 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
554 0, 0),
555 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
556 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
557 1, 0),
558 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
559 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
560 2, 0),
561 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
562 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
563 3, 0),
564 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
565 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
566 4, 0),
567 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
568 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
569 0, 0),
570 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
571 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
572 1, 0),
573 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
575 2, 0),
576 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
578 3, 0),
579 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_temp_hyst,
581 store_pwm_auto_point_temp_hyst,
582 0, 0),
583 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
584 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
585 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
586 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
587 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
588 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100589}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100590 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_channel,
592 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100593 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
595 0, 1),
596 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
598 1, 1),
599 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
601 2, 1),
602 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
604 3, 1),
605 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
606 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
607 4, 1),
608 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
609 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
610 0, 1),
611 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
613 1, 1),
614 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
616 2, 1),
617 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
619 3, 1),
620 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_temp_hyst,
622 store_pwm_auto_point_temp_hyst,
623 0, 1),
624 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
625 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
626 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
627 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
628 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100630}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100631 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_channel,
633 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100634 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 0, 2),
637 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 1, 2),
640 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
642 2, 2),
643 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
645 3, 2),
646 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
648 4, 2),
649 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
651 0, 2),
652 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
653 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
654 1, 2),
655 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
657 2, 2),
658 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
659 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
660 3, 2),
661 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
662 show_pwm_auto_point_temp_hyst,
663 store_pwm_auto_point_temp_hyst,
664 0, 2),
665 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
666 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
667 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
668 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
669 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100671}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100672 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_channel,
674 store_pwm_auto_point_channel, 0, 3),
675 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
677 0, 3),
678 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 1, 3),
681 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 2, 3),
684 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 3, 3),
687 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
689 4, 3),
690 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
692 0, 3),
693 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
695 1, 3),
696 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
698 2, 3),
699 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
701 3, 3),
702 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_temp_hyst,
704 store_pwm_auto_point_temp_hyst,
705 0, 3),
706 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
707 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
708 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
709 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
710 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100712} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200713
Hans de Goede66344aa2009-12-09 20:35:59 +0100714/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100715static struct sensor_device_attribute_2 f8000_fan_attr[] = {
716 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100717};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100718
Hans de Goede66344aa2009-12-09 20:35:59 +0100719/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
720 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
721 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
722static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
723 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
724 show_pwm_auto_point_channel,
725 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100726 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
727 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
728 0, 2),
729 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
730 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
731 1, 2),
732 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
733 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
734 2, 2),
735 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
736 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
737 3, 2),
738 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
739 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
740 4, 2),
741 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
742 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
743 0, 2),
744 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
746 1, 2),
747 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
749 2, 2),
750 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
752 3, 2),
753 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_temp_hyst,
755 store_pwm_auto_point_temp_hyst,
756 0, 2),
757 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
758 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
759 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
760 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
761 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
763
Hans de Goede66344aa2009-12-09 20:35:59 +0100764 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_channel,
766 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100767 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
769 0, 0),
770 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
772 1, 0),
773 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
775 2, 0),
776 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
778 3, 0),
779 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
780 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
781 4, 0),
782 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
783 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
784 0, 0),
785 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
787 1, 0),
788 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
790 2, 0),
791 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
793 3, 0),
794 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_temp_hyst,
796 store_pwm_auto_point_temp_hyst,
797 0, 0),
798 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
799 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
800 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
801 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
802 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
804
Hans de Goede66344aa2009-12-09 20:35:59 +0100805 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_channel,
807 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100808 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
810 0, 1),
811 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
813 1, 1),
814 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 2, 1),
817 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
819 3, 1),
820 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
822 4, 1),
823 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
825 0, 1),
826 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
828 1, 1),
829 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
831 2, 1),
832 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
834 3, 1),
835 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_temp_hyst,
837 store_pwm_auto_point_temp_hyst,
838 0, 1),
839 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
840 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
841 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
842 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
843 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
845};
Hans de Goede45fb3662007-07-13 14:34:19 +0200846
847/* Super I/O functions */
848static inline int superio_inb(int base, int reg)
849{
850 outb(reg, base);
851 return inb(base + 1);
852}
853
854static int superio_inw(int base, int reg)
855{
856 int val;
857 outb(reg++, base);
858 val = inb(base + 1) << 8;
859 outb(reg, base);
860 val |= inb(base + 1);
861 return val;
862}
863
864static inline void superio_enter(int base)
865{
866 /* according to the datasheet the key must be send twice! */
867 outb( SIO_UNLOCK_KEY, base);
868 outb( SIO_UNLOCK_KEY, base);
869}
870
871static inline void superio_select( int base, int ld)
872{
873 outb(SIO_REG_LDSEL, base);
874 outb(ld, base + 1);
875}
876
877static inline void superio_exit(int base)
878{
879 outb(SIO_LOCK_KEY, base);
880}
881
Hans de Goede2f650632009-01-07 16:37:31 +0100882static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200883{
884 return reg ? (1500000 / reg) : 0;
885}
886
Hans de Goede2f650632009-01-07 16:37:31 +0100887static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100888{
889 return fan ? (1500000 / fan) : 0;
890}
891
Hans de Goede45fb3662007-07-13 14:34:19 +0200892static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
893{
894 u8 val;
895
896 outb(reg, data->addr + ADDR_REG_OFFSET);
897 val = inb(data->addr + DATA_REG_OFFSET);
898
899 return val;
900}
901
902static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
903{
904 u16 val;
905
906 outb(reg++, data->addr + ADDR_REG_OFFSET);
907 val = inb(data->addr + DATA_REG_OFFSET) << 8;
908 outb(reg, data->addr + ADDR_REG_OFFSET);
909 val |= inb(data->addr + DATA_REG_OFFSET);
910
911 return val;
912}
913
914static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
915{
916 outb(reg, data->addr + ADDR_REG_OFFSET);
917 outb(val, data->addr + DATA_REG_OFFSET);
918}
919
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100920static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
921{
922 outb(reg++, data->addr + ADDR_REG_OFFSET);
923 outb(val >> 8, data->addr + DATA_REG_OFFSET);
924 outb(reg, data->addr + ADDR_REG_OFFSET);
925 outb(val & 255, data->addr + DATA_REG_OFFSET);
926}
927
Hans de Goede09475d32009-06-15 18:39:52 +0200928static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
929{
930 if (data->type == f71858fg)
931 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
932 else
933 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
934}
935
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100936static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200937{
938 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100939 int nr, reg = 0, reg2;
940 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200941 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200942
943 mutex_lock(&data->update_lock);
944
945 /* Update once every 60 seconds */
946 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
947 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100948 if (data->type == f71882fg) {
949 data->in1_max =
950 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
951 data->in_beep =
952 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
953 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200954
955 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200956 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200957 data->temp_ovt[nr] = f71882fg_read8(data,
958 F71882FG_REG_TEMP_OVT(nr));
959 data->temp_high[nr] = f71882fg_read8(data,
960 F71882FG_REG_TEMP_HIGH(nr));
961 }
962
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100963 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100964 data->temp_hyst[0] = f71882fg_read8(data,
965 F71882FG_REG_TEMP_HYST(0));
966 data->temp_hyst[1] = f71882fg_read8(data,
967 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200968 }
969
970 if (data->type == f71862fg || data->type == f71882fg) {
971 data->fan_beep = f71882fg_read8(data,
972 F71882FG_REG_FAN_BEEP);
973 data->temp_beep = f71882fg_read8(data,
974 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100975 /* Have to hardcode type, because temp1 is special */
976 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
977 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
978 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
979 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200980 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
981 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100982 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200983 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100984 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goede09475d32009-06-15 18:39:52 +0200985 else if (data->type == f71862fg || data->type == f71882fg)
Hans de Goede7567a042009-01-07 16:37:28 +0100986 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100987 else
Hans de Goede09475d32009-06-15 18:39:52 +0200988 data->temp_type[1] = 2; /* Only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200989
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100990 data->pwm_enable = f71882fg_read8(data,
991 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100992 data->pwm_auto_point_hyst[0] =
993 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
994 data->pwm_auto_point_hyst[1] =
995 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
996
Hans de Goede498be962009-01-07 16:37:28 +0100997 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100998 data->pwm_auto_point_mapping[nr] =
999 f71882fg_read8(data,
1000 F71882FG_REG_POINT_MAPPING(nr));
1001
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001002 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001003 int point;
1004 for (point = 0; point < 5; point++) {
1005 data->pwm_auto_point_pwm[nr][point] =
1006 f71882fg_read8(data,
1007 F71882FG_REG_POINT_PWM
1008 (nr, point));
1009 }
1010 for (point = 0; point < 4; point++) {
1011 data->pwm_auto_point_temp[nr][point] =
1012 f71882fg_read8(data,
1013 F71882FG_REG_POINT_TEMP
1014 (nr, point));
1015 }
1016 } else {
1017 data->pwm_auto_point_pwm[nr][1] =
1018 f71882fg_read8(data,
1019 F71882FG_REG_POINT_PWM
1020 (nr, 1));
1021 data->pwm_auto_point_pwm[nr][4] =
1022 f71882fg_read8(data,
1023 F71882FG_REG_POINT_PWM
1024 (nr, 4));
1025 data->pwm_auto_point_temp[nr][0] =
1026 f71882fg_read8(data,
1027 F71882FG_REG_POINT_TEMP
1028 (nr, 0));
1029 data->pwm_auto_point_temp[nr][3] =
1030 f71882fg_read8(data,
1031 F71882FG_REG_POINT_TEMP
1032 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001033 }
1034 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001035 data->last_limits = jiffies;
1036 }
1037
1038 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001039 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001040 data->temp_status = f71882fg_read8(data,
1041 F71882FG_REG_TEMP_STATUS);
1042 data->temp_diode_open = f71882fg_read8(data,
1043 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001044 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1045 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001046
1047 data->fan_status = f71882fg_read8(data,
1048 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001049 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001050 data->fan[nr] = f71882fg_read16(data,
1051 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001052 data->fan_target[nr] =
1053 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1054 data->fan_full_speed[nr] =
1055 f71882fg_read16(data,
1056 F71882FG_REG_FAN_FULL_SPEED(nr));
1057 data->pwm[nr] =
1058 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1059 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001060
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001061 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1062 if (data->type == f8000)
1063 data->fan[3] = f71882fg_read16(data,
1064 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +01001065 if (data->type == f71882fg)
1066 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001067 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001068 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001069 data->in[nr] = f71882fg_read8(data,
1070 F71882FG_REG_IN(nr));
1071
1072 data->last_updated = jiffies;
1073 data->valid = 1;
1074 }
1075
1076 mutex_unlock(&data->update_lock);
1077
1078 return data;
1079}
1080
1081/* Sysfs Interface */
1082static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1083 char *buf)
1084{
1085 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001086 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001087 int speed = fan_from_reg(data->fan[nr]);
1088
1089 if (speed == FAN_MIN_DETECT)
1090 speed = 0;
1091
1092 return sprintf(buf, "%d\n", speed);
1093}
1094
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001095static ssize_t show_fan_full_speed(struct device *dev,
1096 struct device_attribute *devattr, char *buf)
1097{
1098 struct f71882fg_data *data = f71882fg_update_device(dev);
1099 int nr = to_sensor_dev_attr_2(devattr)->index;
1100 int speed = fan_from_reg(data->fan_full_speed[nr]);
1101 return sprintf(buf, "%d\n", speed);
1102}
1103
1104static ssize_t store_fan_full_speed(struct device *dev,
1105 struct device_attribute *devattr,
1106 const char *buf, size_t count)
1107{
1108 struct f71882fg_data *data = dev_get_drvdata(dev);
1109 int nr = to_sensor_dev_attr_2(devattr)->index;
1110 long val = simple_strtol(buf, NULL, 10);
1111
1112 val = SENSORS_LIMIT(val, 23, 1500000);
1113 val = fan_to_reg(val);
1114
1115 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001116 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1117 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001118 mutex_unlock(&data->update_lock);
1119
1120 return count;
1121}
1122
Hans de Goede45fb3662007-07-13 14:34:19 +02001123static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1124 *devattr, char *buf)
1125{
1126 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001127 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001128
1129 if (data->fan_beep & (1 << nr))
1130 return sprintf(buf, "1\n");
1131 else
1132 return sprintf(buf, "0\n");
1133}
1134
1135static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1136 *devattr, const char *buf, size_t count)
1137{
1138 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001139 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001140 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001141
1142 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001143 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001144 if (val)
1145 data->fan_beep |= 1 << nr;
1146 else
1147 data->fan_beep &= ~(1 << nr);
1148
1149 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1150 mutex_unlock(&data->update_lock);
1151
1152 return count;
1153}
1154
1155static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1156 *devattr, char *buf)
1157{
1158 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001159 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001160
1161 if (data->fan_status & (1 << nr))
1162 return sprintf(buf, "1\n");
1163 else
1164 return sprintf(buf, "0\n");
1165}
1166
1167static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1168 char *buf)
1169{
1170 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001171 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001172
1173 return sprintf(buf, "%d\n", data->in[nr] * 8);
1174}
1175
1176static ssize_t show_in_max(struct device *dev, struct device_attribute
1177 *devattr, char *buf)
1178{
1179 struct f71882fg_data *data = f71882fg_update_device(dev);
1180
1181 return sprintf(buf, "%d\n", data->in1_max * 8);
1182}
1183
1184static ssize_t store_in_max(struct device *dev, struct device_attribute
1185 *devattr, const char *buf, size_t count)
1186{
1187 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001188 long val = simple_strtol(buf, NULL, 10) / 8;
1189 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001190
1191 mutex_lock(&data->update_lock);
1192 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1193 data->in1_max = val;
1194 mutex_unlock(&data->update_lock);
1195
1196 return count;
1197}
1198
1199static ssize_t show_in_beep(struct device *dev, struct device_attribute
1200 *devattr, char *buf)
1201{
1202 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001203 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001204
1205 if (data->in_beep & (1 << nr))
1206 return sprintf(buf, "1\n");
1207 else
1208 return sprintf(buf, "0\n");
1209}
1210
1211static ssize_t store_in_beep(struct device *dev, struct device_attribute
1212 *devattr, const char *buf, size_t count)
1213{
1214 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001215 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001216 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001217
1218 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001219 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001220 if (val)
1221 data->in_beep |= 1 << nr;
1222 else
1223 data->in_beep &= ~(1 << nr);
1224
1225 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1226 mutex_unlock(&data->update_lock);
1227
1228 return count;
1229}
1230
1231static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1232 *devattr, char *buf)
1233{
1234 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001235 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001236
1237 if (data->in_status & (1 << nr))
1238 return sprintf(buf, "1\n");
1239 else
1240 return sprintf(buf, "0\n");
1241}
1242
1243static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1244 char *buf)
1245{
1246 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001247 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001248 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001249
Hans de Goede09475d32009-06-15 18:39:52 +02001250 if (data->type == f71858fg) {
1251 /* TEMP_TABLE_SEL 1 or 3 ? */
1252 if (data->temp_config & 1) {
1253 sign = data->temp[nr] & 0x0001;
1254 temp = (data->temp[nr] >> 5) & 0x7ff;
1255 } else {
1256 sign = data->temp[nr] & 0x8000;
1257 temp = (data->temp[nr] >> 5) & 0x3ff;
1258 }
1259 temp *= 125;
1260 if (sign)
1261 temp -= 128000;
1262 } else
1263 temp = data->temp[nr] * 1000;
1264
1265 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001266}
1267
1268static ssize_t show_temp_max(struct device *dev, struct device_attribute
1269 *devattr, char *buf)
1270{
1271 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001272 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001273
1274 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1275}
1276
1277static ssize_t store_temp_max(struct device *dev, struct device_attribute
1278 *devattr, const char *buf, size_t count)
1279{
1280 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001281 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001282 long val = simple_strtol(buf, NULL, 10) / 1000;
1283 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001284
1285 mutex_lock(&data->update_lock);
1286 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1287 data->temp_high[nr] = val;
1288 mutex_unlock(&data->update_lock);
1289
1290 return count;
1291}
1292
1293static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1294 *devattr, char *buf)
1295{
1296 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001297 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001298 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001299
Hans de Goedece0bfa52009-01-07 16:37:28 +01001300 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001301 if (nr & 1)
1302 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1303 else
1304 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1305 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001306 mutex_unlock(&data->update_lock);
1307
1308 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001309}
1310
1311static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1312 *devattr, const char *buf, size_t count)
1313{
1314 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001315 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001316 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001317 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001318 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001319
1320 mutex_lock(&data->update_lock);
1321
1322 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001323 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1324 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1325 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001326 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001327
1328 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001329 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1330 if (nr & 1)
1331 reg = (reg & 0x0f) | (val << 4);
1332 else
1333 reg = (reg & 0xf0) | val;
1334 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1335 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001336
Hans de Goede45fb3662007-07-13 14:34:19 +02001337 mutex_unlock(&data->update_lock);
1338 return ret;
1339}
1340
1341static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1342 *devattr, char *buf)
1343{
1344 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001345 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001346
1347 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1348}
1349
1350static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1351 *devattr, const char *buf, size_t count)
1352{
1353 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001354 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001355 long val = simple_strtol(buf, NULL, 10) / 1000;
1356 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001357
1358 mutex_lock(&data->update_lock);
1359 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1360 data->temp_ovt[nr] = val;
1361 mutex_unlock(&data->update_lock);
1362
1363 return count;
1364}
1365
1366static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1367 *devattr, char *buf)
1368{
1369 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001370 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001371 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001372
Hans de Goedece0bfa52009-01-07 16:37:28 +01001373 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001374 if (nr & 1)
1375 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1376 else
1377 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1378 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001379 mutex_unlock(&data->update_lock);
1380
1381 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001382}
1383
1384static ssize_t show_temp_type(struct device *dev, struct device_attribute
1385 *devattr, char *buf)
1386{
1387 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001388 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001389
1390 return sprintf(buf, "%d\n", data->temp_type[nr]);
1391}
1392
1393static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1394 *devattr, char *buf)
1395{
1396 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001397 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001398
Hans de Goede7567a042009-01-07 16:37:28 +01001399 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001400 return sprintf(buf, "1\n");
1401 else
1402 return sprintf(buf, "0\n");
1403}
1404
1405static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1406 *devattr, const char *buf, size_t count)
1407{
1408 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001409 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001410 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001411
1412 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001413 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001414 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001415 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001416 else
Hans de Goede7567a042009-01-07 16:37:28 +01001417 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001418
1419 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1420 mutex_unlock(&data->update_lock);
1421
1422 return count;
1423}
1424
1425static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1426 *devattr, char *buf)
1427{
1428 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001429 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001430
Hans de Goede7567a042009-01-07 16:37:28 +01001431 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001432 return sprintf(buf, "1\n");
1433 else
1434 return sprintf(buf, "0\n");
1435}
1436
1437static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1438 *devattr, char *buf)
1439{
1440 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001441 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001442
Hans de Goede7567a042009-01-07 16:37:28 +01001443 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001444 return sprintf(buf, "1\n");
1445 else
1446 return sprintf(buf, "0\n");
1447}
1448
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001449static ssize_t show_pwm(struct device *dev,
1450 struct device_attribute *devattr, char *buf)
1451{
1452 struct f71882fg_data *data = f71882fg_update_device(dev);
1453 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001454 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001455 if (data->pwm_enable & (1 << (2 * nr)))
1456 /* PWM mode */
1457 val = data->pwm[nr];
1458 else {
1459 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001460 val = 255 * fan_from_reg(data->fan_target[nr])
1461 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001462 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001463 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001464 return sprintf(buf, "%d\n", val);
1465}
1466
1467static ssize_t store_pwm(struct device *dev,
1468 struct device_attribute *devattr, const char *buf,
1469 size_t count)
1470{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001471 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001472 int nr = to_sensor_dev_attr_2(devattr)->index;
1473 long val = simple_strtol(buf, NULL, 10);
1474 val = SENSORS_LIMIT(val, 0, 255);
1475
1476 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001477 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001478 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1479 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1480 count = -EROFS;
1481 goto leave;
1482 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001483 if (data->pwm_enable & (1 << (2 * nr))) {
1484 /* PWM mode */
1485 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1486 data->pwm[nr] = val;
1487 } else {
1488 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001489 int target, full_speed;
1490 full_speed = f71882fg_read16(data,
1491 F71882FG_REG_FAN_FULL_SPEED(nr));
1492 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1493 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1494 data->fan_target[nr] = target;
1495 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001496 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001497leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001498 mutex_unlock(&data->update_lock);
1499
1500 return count;
1501}
1502
1503static ssize_t show_pwm_enable(struct device *dev,
1504 struct device_attribute *devattr, char *buf)
1505{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001506 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001507 struct f71882fg_data *data = f71882fg_update_device(dev);
1508 int nr = to_sensor_dev_attr_2(devattr)->index;
1509
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001510 switch ((data->pwm_enable >> 2 * nr) & 3) {
1511 case 0:
1512 case 1:
1513 result = 2; /* Normal auto mode */
1514 break;
1515 case 2:
1516 result = 1; /* Manual mode */
1517 break;
1518 case 3:
1519 if (data->type == f8000)
1520 result = 3; /* Thermostat mode */
1521 else
1522 result = 1; /* Manual mode */
1523 break;
1524 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001525
1526 return sprintf(buf, "%d\n", result);
1527}
1528
1529static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1530 *devattr, const char *buf, size_t count)
1531{
1532 struct f71882fg_data *data = dev_get_drvdata(dev);
1533 int nr = to_sensor_dev_attr_2(devattr)->index;
1534 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001535
Hans de Goede3fc78382009-06-15 18:39:50 +02001536 /* Special case for F8000 pwm channel 3 which only does auto mode */
1537 if (data->type == f8000 && nr == 2 && val != 2)
1538 return -EINVAL;
1539
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001540 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001541 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001542 /* Special case for F8000 auto PWM mode / Thermostat mode */
1543 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1544 switch (val) {
1545 case 2:
1546 data->pwm_enable &= ~(2 << (2 * nr));
1547 break; /* Normal auto mode */
1548 case 3:
1549 data->pwm_enable |= 2 << (2 * nr);
1550 break; /* Thermostat mode */
1551 default:
1552 count = -EINVAL;
1553 goto leave;
1554 }
1555 } else {
1556 switch (val) {
1557 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001558 /* The f71858fg does not support manual RPM mode */
1559 if (data->type == f71858fg &&
1560 ((data->pwm_enable >> (2 * nr)) & 1)) {
1561 count = -EINVAL;
1562 goto leave;
1563 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001564 data->pwm_enable |= 2 << (2 * nr);
1565 break; /* Manual */
1566 case 2:
1567 data->pwm_enable &= ~(2 << (2 * nr));
1568 break; /* Normal auto mode */
1569 default:
1570 count = -EINVAL;
1571 goto leave;
1572 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001573 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001574 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001575leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001576 mutex_unlock(&data->update_lock);
1577
1578 return count;
1579}
1580
1581static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1582 struct device_attribute *devattr,
1583 char *buf)
1584{
1585 int result;
1586 struct f71882fg_data *data = f71882fg_update_device(dev);
1587 int pwm = to_sensor_dev_attr_2(devattr)->index;
1588 int point = to_sensor_dev_attr_2(devattr)->nr;
1589
Hans de Goedece0bfa52009-01-07 16:37:28 +01001590 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001591 if (data->pwm_enable & (1 << (2 * pwm))) {
1592 /* PWM mode */
1593 result = data->pwm_auto_point_pwm[pwm][point];
1594 } else {
1595 /* RPM mode */
1596 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1597 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001598 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001599
1600 return sprintf(buf, "%d\n", result);
1601}
1602
1603static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1604 struct device_attribute *devattr,
1605 const char *buf, size_t count)
1606{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001607 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001608 int pwm = to_sensor_dev_attr_2(devattr)->index;
1609 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001610 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001611 val = SENSORS_LIMIT(val, 0, 255);
1612
1613 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001614 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001615 if (data->pwm_enable & (1 << (2 * pwm))) {
1616 /* PWM mode */
1617 } else {
1618 /* RPM mode */
1619 if (val < 29) /* Prevent negative numbers */
1620 val = 255;
1621 else
1622 val = (255 - val) * 32 / val;
1623 }
1624 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1625 data->pwm_auto_point_pwm[pwm][point] = val;
1626 mutex_unlock(&data->update_lock);
1627
1628 return count;
1629}
1630
1631static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1632 struct device_attribute *devattr,
1633 char *buf)
1634{
1635 int result = 0;
1636 struct f71882fg_data *data = f71882fg_update_device(dev);
1637 int nr = to_sensor_dev_attr_2(devattr)->index;
1638 int point = to_sensor_dev_attr_2(devattr)->nr;
1639
1640 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001641 if (nr & 1)
1642 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1643 else
1644 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001645 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1646 mutex_unlock(&data->update_lock);
1647
1648 return sprintf(buf, "%d\n", result);
1649}
1650
1651static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1652 struct device_attribute *devattr,
1653 const char *buf, size_t count)
1654{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001655 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001656 int nr = to_sensor_dev_attr_2(devattr)->index;
1657 int point = to_sensor_dev_attr_2(devattr)->nr;
1658 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001659 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001660
1661 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001662 data->pwm_auto_point_temp[nr][point] =
1663 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001664 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1665 data->pwm_auto_point_temp[nr][point]);
1666 val = data->pwm_auto_point_temp[nr][point] - val;
1667
Hans de Goedebc274902009-01-07 16:37:29 +01001668 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1669 if (nr & 1)
1670 reg = (reg & 0x0f) | (val << 4);
1671 else
1672 reg = (reg & 0xf0) | val;
1673
1674 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1675 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001676 mutex_unlock(&data->update_lock);
1677
1678 return count;
1679}
1680
1681static ssize_t show_pwm_interpolate(struct device *dev,
1682 struct device_attribute *devattr, char *buf)
1683{
1684 int result;
1685 struct f71882fg_data *data = f71882fg_update_device(dev);
1686 int nr = to_sensor_dev_attr_2(devattr)->index;
1687
1688 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1689
1690 return sprintf(buf, "%d\n", result);
1691}
1692
1693static ssize_t store_pwm_interpolate(struct device *dev,
1694 struct device_attribute *devattr,
1695 const char *buf, size_t count)
1696{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001697 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001698 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001699 unsigned long val = simple_strtoul(buf, NULL, 10);
1700
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001701 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001702 data->pwm_auto_point_mapping[nr] =
1703 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001704 if (val)
1705 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1706 else
1707 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1708 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1709 data->pwm_auto_point_mapping[nr] = val;
1710 mutex_unlock(&data->update_lock);
1711
1712 return count;
1713}
1714
1715static ssize_t show_pwm_auto_point_channel(struct device *dev,
1716 struct device_attribute *devattr,
1717 char *buf)
1718{
1719 int result;
1720 struct f71882fg_data *data = f71882fg_update_device(dev);
1721 int nr = to_sensor_dev_attr_2(devattr)->index;
1722
Hans de Goede09475d32009-06-15 18:39:52 +02001723 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1724 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001725
1726 return sprintf(buf, "%d\n", result);
1727}
1728
1729static ssize_t store_pwm_auto_point_channel(struct device *dev,
1730 struct device_attribute *devattr,
1731 const char *buf, size_t count)
1732{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001733 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001734 int nr = to_sensor_dev_attr_2(devattr)->index;
1735 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001736
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001737 switch (val) {
1738 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001739 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001740 break;
1741 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001742 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001743 break;
1744 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001745 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001746 break;
1747 default:
1748 return -EINVAL;
1749 }
Hans de Goede09475d32009-06-15 18:39:52 +02001750 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001751 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001752 data->pwm_auto_point_mapping[nr] =
1753 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001754 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1755 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1756 data->pwm_auto_point_mapping[nr] = val;
1757 mutex_unlock(&data->update_lock);
1758
1759 return count;
1760}
1761
1762static ssize_t show_pwm_auto_point_temp(struct device *dev,
1763 struct device_attribute *devattr,
1764 char *buf)
1765{
1766 int result;
1767 struct f71882fg_data *data = f71882fg_update_device(dev);
1768 int pwm = to_sensor_dev_attr_2(devattr)->index;
1769 int point = to_sensor_dev_attr_2(devattr)->nr;
1770
1771 result = data->pwm_auto_point_temp[pwm][point];
1772 return sprintf(buf, "%d\n", 1000 * result);
1773}
1774
1775static ssize_t store_pwm_auto_point_temp(struct device *dev,
1776 struct device_attribute *devattr,
1777 const char *buf, size_t count)
1778{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001779 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001780 int pwm = to_sensor_dev_attr_2(devattr)->index;
1781 int point = to_sensor_dev_attr_2(devattr)->nr;
1782 long val = simple_strtol(buf, NULL, 10) / 1000;
1783 val = SENSORS_LIMIT(val, 0, 255);
1784
1785 mutex_lock(&data->update_lock);
1786 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1787 data->pwm_auto_point_temp[pwm][point] = val;
1788 mutex_unlock(&data->update_lock);
1789
1790 return count;
1791}
1792
Hans de Goede45fb3662007-07-13 14:34:19 +02001793static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1794 char *buf)
1795{
Hans de Goede498be962009-01-07 16:37:28 +01001796 struct f71882fg_data *data = dev_get_drvdata(dev);
1797 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001798}
1799
Hans de Goedec13548c2009-01-07 16:37:27 +01001800static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1801 struct sensor_device_attribute_2 *attr, int count)
1802{
1803 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001804
Hans de Goedec13548c2009-01-07 16:37:27 +01001805 for (i = 0; i < count; i++) {
1806 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1807 if (err)
1808 return err;
1809 }
1810 return 0;
1811}
1812
Hans de Goedefc16c562009-12-09 20:36:01 +01001813static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1814 struct sensor_device_attribute_2 *attr, int count)
1815{
1816 int i;
1817
1818 for (i = 0; i < count; i++)
1819 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1820}
1821
Hans de Goedec13548c2009-01-07 16:37:27 +01001822static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001823{
1824 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001825 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001826 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001827 u8 start_reg;
1828
Hans de Goedec13548c2009-01-07 16:37:27 +01001829 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1830 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001831 return -ENOMEM;
1832
1833 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001834 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001835 data->temp_start =
1836 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001837 mutex_init(&data->update_lock);
1838 platform_set_drvdata(pdev, data);
1839
Hans de Goede3cc74752009-01-07 16:37:28 +01001840 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001841 if (start_reg & 0x04) {
1842 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1843 err = -ENODEV;
1844 goto exit_free;
1845 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001846 if (!(start_reg & 0x03)) {
1847 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1848 err = -ENODEV;
1849 goto exit_free;
1850 }
1851
Hans de Goede45fb3662007-07-13 14:34:19 +02001852 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001853 err = device_create_file(&pdev->dev, &dev_attr_name);
1854 if (err)
1855 goto exit_unregister_sysfs;
1856
Hans de Goedec13548c2009-01-07 16:37:27 +01001857 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001858 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001859 case f71858fg:
1860 data->temp_config =
1861 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1862 if (data->temp_config & 0x10)
1863 /* The f71858fg temperature alarms behave as
1864 the f8000 alarms in this mode */
1865 err = f71882fg_create_sysfs_files(pdev,
1866 f8000_in_temp_attr,
1867 ARRAY_SIZE(f8000_in_temp_attr));
1868 else
1869 err = f71882fg_create_sysfs_files(pdev,
1870 f71858fg_in_temp_attr,
1871 ARRAY_SIZE(f71858fg_in_temp_attr));
1872 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001873 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001874 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001875 fxxxx_in1_alarm_attr,
1876 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001877 if (err)
1878 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001879 /* fall through! */
1880 case f71862fg:
1881 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001882 fxxxx_in_temp_attr,
1883 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001884 break;
1885 case f8000:
1886 err = f71882fg_create_sysfs_files(pdev,
1887 f8000_in_temp_attr,
1888 ARRAY_SIZE(f8000_in_temp_attr));
1889 break;
Hans de Goede498be962009-01-07 16:37:28 +01001890 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001891 if (err)
1892 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001893 }
1894
Hans de Goede45fb3662007-07-13 14:34:19 +02001895 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001896 data->pwm_enable =
1897 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1898
1899 /* Sanity check the pwm settings */
1900 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001901 case f71858fg:
1902 err = 0;
1903 for (i = 0; i < nr_fans; i++)
1904 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1905 err = 1;
1906 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001907 case f71862fg:
1908 err = (data->pwm_enable & 0x15) != 0x15;
1909 break;
1910 case f71882fg:
1911 err = 0;
1912 break;
1913 case f8000:
1914 err = data->pwm_enable & 0x20;
1915 break;
1916 }
1917 if (err) {
1918 dev_err(&pdev->dev,
1919 "Invalid (reserved) pwm settings: 0x%02x\n",
1920 (unsigned int)data->pwm_enable);
1921 err = -ENODEV;
1922 goto exit_unregister_sysfs;
1923 }
1924
Hans de Goedeb69b0392009-12-09 20:36:00 +01001925 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
1926 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01001927 if (err)
1928 goto exit_unregister_sysfs;
1929
Hans de Goedeb69b0392009-12-09 20:36:00 +01001930 if (data->type == f71862fg || data->type == f71882fg) {
1931 err = f71882fg_create_sysfs_files(pdev,
1932 fxxxx_fan_beep_attr, nr_fans);
1933 if (err)
1934 goto exit_unregister_sysfs;
1935 }
1936
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001937 switch (data->type) {
1938 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001939 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001940 f71862fg_auto_pwm_attr,
1941 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001942 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001943 case f8000:
1944 err = f71882fg_create_sysfs_files(pdev,
1945 f8000_fan_attr,
1946 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01001947 if (err)
1948 goto exit_unregister_sysfs;
1949 err = f71882fg_create_sysfs_files(pdev,
1950 f8000_auto_pwm_attr,
1951 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001952 break;
Hans de Goedeb69b0392009-12-09 20:36:00 +01001953 default: /* f71858fg / f71882fg */
1954 err = f71882fg_create_sysfs_files(pdev,
1955 &fxxxx_auto_pwm_attr[0][0],
1956 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01001957 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001958 if (err)
1959 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001960
1961 for (i = 0; i < nr_fans; i++)
1962 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1963 (data->pwm_enable & (1 << 2 * i)) ?
1964 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001965 }
1966
Tony Jones1beeffe2007-08-20 13:46:20 -07001967 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1968 if (IS_ERR(data->hwmon_dev)) {
1969 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001970 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001971 goto exit_unregister_sysfs;
1972 }
1973
1974 return 0;
1975
1976exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001977 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001978 return err; /* f71882fg_remove() also frees our data */
1979exit_free:
1980 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001981 return err;
1982}
1983
Hans de Goedec13548c2009-01-07 16:37:27 +01001984static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001985{
Hans de Goede45fb3662007-07-13 14:34:19 +02001986 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01001987 int nr_fans = (data->type == f71882fg) ? 4 : 3;
1988 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02001989
1990 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001991 if (data->hwmon_dev)
1992 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001993
Hans de Goedec13548c2009-01-07 16:37:27 +01001994 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001995
Hans de Goedefc16c562009-12-09 20:36:01 +01001996 if (start_reg & 0x01) {
1997 switch (data->type) {
1998 case f71858fg:
1999 if (data->temp_config & 0x10)
2000 f71882fg_remove_sysfs_files(pdev,
2001 f8000_in_temp_attr,
2002 ARRAY_SIZE(f8000_in_temp_attr));
2003 else
2004 f71882fg_remove_sysfs_files(pdev,
2005 f71858fg_in_temp_attr,
2006 ARRAY_SIZE(f71858fg_in_temp_attr));
2007 break;
2008 case f71882fg:
2009 f71882fg_remove_sysfs_files(pdev,
2010 fxxxx_in1_alarm_attr,
2011 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2012 /* fall through! */
2013 case f71862fg:
2014 f71882fg_remove_sysfs_files(pdev,
2015 fxxxx_in_temp_attr,
2016 ARRAY_SIZE(fxxxx_in_temp_attr));
2017 break;
2018 case f8000:
2019 f71882fg_remove_sysfs_files(pdev,
2020 f8000_in_temp_attr,
2021 ARRAY_SIZE(f8000_in_temp_attr));
2022 break;
2023 }
2024 }
Hans de Goede498be962009-01-07 16:37:28 +01002025
Hans de Goedefc16c562009-12-09 20:36:01 +01002026 if (start_reg & 0x02) {
2027 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2028 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002029
Hans de Goedefc16c562009-12-09 20:36:01 +01002030 if (data->type == f71862fg || data->type == f71882fg)
2031 f71882fg_remove_sysfs_files(pdev,
2032 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002033
Hans de Goedefc16c562009-12-09 20:36:01 +01002034 switch (data->type) {
2035 case f71862fg:
2036 f71882fg_remove_sysfs_files(pdev,
2037 f71862fg_auto_pwm_attr,
2038 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2039 break;
2040 case f8000:
2041 f71882fg_remove_sysfs_files(pdev,
2042 f8000_fan_attr,
2043 ARRAY_SIZE(f8000_fan_attr));
2044 f71882fg_remove_sysfs_files(pdev,
2045 f8000_auto_pwm_attr,
2046 ARRAY_SIZE(f8000_auto_pwm_attr));
2047 break;
2048 default: /* f71858fg / f71882fg / f71889fg */
2049 f71882fg_remove_sysfs_files(pdev,
2050 &fxxxx_auto_pwm_attr[0][0],
2051 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2052 }
2053 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002054
Hans de Goede45fb3662007-07-13 14:34:19 +02002055 kfree(data);
2056
2057 return 0;
2058}
2059
Hans de Goede498be962009-01-07 16:37:28 +01002060static int __init f71882fg_find(int sioaddr, unsigned short *address,
2061 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002062{
2063 int err = -ENODEV;
2064 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002065
2066 superio_enter(sioaddr);
2067
2068 devid = superio_inw(sioaddr, SIO_REG_MANID);
2069 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002070 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002071 goto exit;
2072 }
2073
Jean Delvare67b671b2007-12-06 23:13:42 +01002074 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002075 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002076 case SIO_F71858_ID:
2077 sio_data->type = f71858fg;
2078 break;
Hans de Goede498be962009-01-07 16:37:28 +01002079 case SIO_F71862_ID:
2080 sio_data->type = f71862fg;
2081 break;
2082 case SIO_F71882_ID:
2083 sio_data->type = f71882fg;
2084 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002085 case SIO_F8000_ID:
2086 sio_data->type = f8000;
2087 break;
Hans de Goede498be962009-01-07 16:37:28 +01002088 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02002089 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
2090 goto exit;
2091 }
2092
Hans de Goede09475d32009-06-15 18:39:52 +02002093 if (sio_data->type == f71858fg)
2094 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2095 else
2096 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2097
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002098 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002099 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2100 goto exit;
2101 }
2102
2103 *address = superio_inw(sioaddr, SIO_REG_ADDR);
2104 if (*address == 0)
2105 {
2106 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2107 goto exit;
2108 }
2109 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2110
Hans de Goede45fb3662007-07-13 14:34:19 +02002111 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002112 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2113 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002114 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2115exit:
2116 superio_exit(sioaddr);
2117 return err;
2118}
2119
Hans de Goede498be962009-01-07 16:37:28 +01002120static int __init f71882fg_device_add(unsigned short address,
2121 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002122{
2123 struct resource res = {
2124 .start = address,
2125 .end = address + REGION_LENGTH - 1,
2126 .flags = IORESOURCE_IO,
2127 };
2128 int err;
2129
2130 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002131 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002132 return -ENOMEM;
2133
2134 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002135 err = acpi_check_resource_conflict(&res);
2136 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002137 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002138
Hans de Goede45fb3662007-07-13 14:34:19 +02002139 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002140 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002141 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2142 goto exit_device_put;
2143 }
2144
Hans de Goede498be962009-01-07 16:37:28 +01002145 err = platform_device_add_data(f71882fg_pdev, sio_data,
2146 sizeof(struct f71882fg_sio_data));
2147 if (err) {
2148 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2149 goto exit_device_put;
2150 }
2151
Hans de Goede45fb3662007-07-13 14:34:19 +02002152 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002153 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002154 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2155 goto exit_device_put;
2156 }
2157
2158 return 0;
2159
2160exit_device_put:
2161 platform_device_put(f71882fg_pdev);
2162
2163 return err;
2164}
2165
2166static int __init f71882fg_init(void)
2167{
2168 int err = -ENODEV;
2169 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002170 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002171
Hans de Goede498be962009-01-07 16:37:28 +01002172 memset(&sio_data, 0, sizeof(sio_data));
2173
2174 if (f71882fg_find(0x2e, &address, &sio_data) &&
2175 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002176 goto exit;
2177
Hans de Goedec13548c2009-01-07 16:37:27 +01002178 err = platform_driver_register(&f71882fg_driver);
2179 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002180 goto exit;
2181
Hans de Goede498be962009-01-07 16:37:28 +01002182 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002183 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002184 goto exit_driver;
2185
2186 return 0;
2187
2188exit_driver:
2189 platform_driver_unregister(&f71882fg_driver);
2190exit:
2191 return err;
2192}
2193
2194static void __exit f71882fg_exit(void)
2195{
2196 platform_device_unregister(f71882fg_pdev);
2197 platform_driver_unregister(&f71882fg_driver);
2198}
2199
2200MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002201MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002202MODULE_LICENSE("GPL");
2203
2204module_init(f71882fg_init);
2205module_exit(f71882fg_exit);