blob: 210ed6619df48178cd68f2022ce0d5bfc4ffd51d [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
1813static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001814{
1815 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001816 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001817 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001818 u8 start_reg;
1819
Hans de Goedec13548c2009-01-07 16:37:27 +01001820 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1821 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001822 return -ENOMEM;
1823
1824 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001825 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001826 data->temp_start =
1827 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001828 mutex_init(&data->update_lock);
1829 platform_set_drvdata(pdev, data);
1830
Hans de Goede3cc74752009-01-07 16:37:28 +01001831 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001832 if (start_reg & 0x04) {
1833 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1834 err = -ENODEV;
1835 goto exit_free;
1836 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001837 if (!(start_reg & 0x03)) {
1838 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1839 err = -ENODEV;
1840 goto exit_free;
1841 }
1842
Hans de Goede45fb3662007-07-13 14:34:19 +02001843 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001844 err = device_create_file(&pdev->dev, &dev_attr_name);
1845 if (err)
1846 goto exit_unregister_sysfs;
1847
Hans de Goedec13548c2009-01-07 16:37:27 +01001848 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001849 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001850 case f71858fg:
1851 data->temp_config =
1852 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1853 if (data->temp_config & 0x10)
1854 /* The f71858fg temperature alarms behave as
1855 the f8000 alarms in this mode */
1856 err = f71882fg_create_sysfs_files(pdev,
1857 f8000_in_temp_attr,
1858 ARRAY_SIZE(f8000_in_temp_attr));
1859 else
1860 err = f71882fg_create_sysfs_files(pdev,
1861 f71858fg_in_temp_attr,
1862 ARRAY_SIZE(f71858fg_in_temp_attr));
1863 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001864 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001865 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001866 fxxxx_in1_alarm_attr,
1867 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001868 if (err)
1869 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001870 /* fall through! */
1871 case f71862fg:
1872 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001873 fxxxx_in_temp_attr,
1874 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001875 break;
1876 case f8000:
1877 err = f71882fg_create_sysfs_files(pdev,
1878 f8000_in_temp_attr,
1879 ARRAY_SIZE(f8000_in_temp_attr));
1880 break;
Hans de Goede498be962009-01-07 16:37:28 +01001881 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001882 if (err)
1883 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001884 }
1885
Hans de Goede45fb3662007-07-13 14:34:19 +02001886 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001887 data->pwm_enable =
1888 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1889
1890 /* Sanity check the pwm settings */
1891 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001892 case f71858fg:
1893 err = 0;
1894 for (i = 0; i < nr_fans; i++)
1895 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1896 err = 1;
1897 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001898 case f71862fg:
1899 err = (data->pwm_enable & 0x15) != 0x15;
1900 break;
1901 case f71882fg:
1902 err = 0;
1903 break;
1904 case f8000:
1905 err = data->pwm_enable & 0x20;
1906 break;
1907 }
1908 if (err) {
1909 dev_err(&pdev->dev,
1910 "Invalid (reserved) pwm settings: 0x%02x\n",
1911 (unsigned int)data->pwm_enable);
1912 err = -ENODEV;
1913 goto exit_unregister_sysfs;
1914 }
1915
Hans de Goedeb69b0392009-12-09 20:36:00 +01001916 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
1917 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01001918 if (err)
1919 goto exit_unregister_sysfs;
1920
Hans de Goedeb69b0392009-12-09 20:36:00 +01001921 if (data->type == f71862fg || data->type == f71882fg) {
1922 err = f71882fg_create_sysfs_files(pdev,
1923 fxxxx_fan_beep_attr, nr_fans);
1924 if (err)
1925 goto exit_unregister_sysfs;
1926 }
1927
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001928 switch (data->type) {
1929 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001930 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001931 f71862fg_auto_pwm_attr,
1932 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001933 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001934 case f8000:
1935 err = f71882fg_create_sysfs_files(pdev,
1936 f8000_fan_attr,
1937 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01001938 if (err)
1939 goto exit_unregister_sysfs;
1940 err = f71882fg_create_sysfs_files(pdev,
1941 f8000_auto_pwm_attr,
1942 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001943 break;
Hans de Goedeb69b0392009-12-09 20:36:00 +01001944 default: /* f71858fg / f71882fg */
1945 err = f71882fg_create_sysfs_files(pdev,
1946 &fxxxx_auto_pwm_attr[0][0],
1947 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01001948 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001949 if (err)
1950 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001951
1952 for (i = 0; i < nr_fans; i++)
1953 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1954 (data->pwm_enable & (1 << 2 * i)) ?
1955 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001956 }
1957
Tony Jones1beeffe2007-08-20 13:46:20 -07001958 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1959 if (IS_ERR(data->hwmon_dev)) {
1960 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001961 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001962 goto exit_unregister_sysfs;
1963 }
1964
1965 return 0;
1966
1967exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001968 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001969 return err; /* f71882fg_remove() also frees our data */
1970exit_free:
1971 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001972 return err;
1973}
1974
Hans de Goedec13548c2009-01-07 16:37:27 +01001975static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001976{
Hans de Goedeb69b0392009-12-09 20:36:00 +01001977 int i, j;
Hans de Goede45fb3662007-07-13 14:34:19 +02001978 struct f71882fg_data *data = platform_get_drvdata(pdev);
1979
1980 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001981 if (data->hwmon_dev)
1982 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001983
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001984 /* Note we are not looping over all attr arrays we have as the ones
1985 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001986 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001987
Hans de Goede66344aa2009-12-09 20:35:59 +01001988 for (i = 0; i < ARRAY_SIZE(fxxxx_in_temp_attr); i++)
Hans de Goede498be962009-01-07 16:37:28 +01001989 device_remove_file(&pdev->dev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001990 &fxxxx_in_temp_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001991
Hans de Goede66344aa2009-12-09 20:35:59 +01001992 for (i = 0; i < ARRAY_SIZE(fxxxx_in1_alarm_attr); i++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001993 device_remove_file(&pdev->dev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001994 &fxxxx_in1_alarm_attr[i].dev_attr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001995
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001996 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
Hans de Goedeb69b0392009-12-09 20:36:00 +01001997 for (j = 0; j < ARRAY_SIZE(fxxxx_fan_attr[0]); j++)
1998 device_remove_file(&pdev->dev,
1999 &fxxxx_fan_attr[i][j].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01002000
Hans de Goede66344aa2009-12-09 20:35:59 +01002001 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_beep_attr); i++)
2002 device_remove_file(&pdev->dev,
2003 &fxxxx_fan_beep_attr[i].dev_attr);
Hans de Goede45fb3662007-07-13 14:34:19 +02002004
Hans de Goedeb69b0392009-12-09 20:36:00 +01002005 for (i = 0; i < ARRAY_SIZE(fxxxx_auto_pwm_attr); i++)
2006 for (j = 0; j < ARRAY_SIZE(fxxxx_auto_pwm_attr[0]); j++)
2007 device_remove_file(&pdev->dev,
2008 &fxxxx_auto_pwm_attr[i][j].dev_attr);
Hans de Goede66344aa2009-12-09 20:35:59 +01002009
2010 for (i = 0; i < ARRAY_SIZE(f8000_auto_pwm_attr); i++)
2011 device_remove_file(&pdev->dev,
2012 &f8000_auto_pwm_attr[i].dev_attr);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002013
Hans de Goede45fb3662007-07-13 14:34:19 +02002014 kfree(data);
2015
2016 return 0;
2017}
2018
Hans de Goede498be962009-01-07 16:37:28 +01002019static int __init f71882fg_find(int sioaddr, unsigned short *address,
2020 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002021{
2022 int err = -ENODEV;
2023 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002024
2025 superio_enter(sioaddr);
2026
2027 devid = superio_inw(sioaddr, SIO_REG_MANID);
2028 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002029 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002030 goto exit;
2031 }
2032
Jean Delvare67b671b2007-12-06 23:13:42 +01002033 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002034 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002035 case SIO_F71858_ID:
2036 sio_data->type = f71858fg;
2037 break;
Hans de Goede498be962009-01-07 16:37:28 +01002038 case SIO_F71862_ID:
2039 sio_data->type = f71862fg;
2040 break;
2041 case SIO_F71882_ID:
2042 sio_data->type = f71882fg;
2043 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002044 case SIO_F8000_ID:
2045 sio_data->type = f8000;
2046 break;
Hans de Goede498be962009-01-07 16:37:28 +01002047 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02002048 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
2049 goto exit;
2050 }
2051
Hans de Goede09475d32009-06-15 18:39:52 +02002052 if (sio_data->type == f71858fg)
2053 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2054 else
2055 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2056
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002057 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002058 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2059 goto exit;
2060 }
2061
2062 *address = superio_inw(sioaddr, SIO_REG_ADDR);
2063 if (*address == 0)
2064 {
2065 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2066 goto exit;
2067 }
2068 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2069
Hans de Goede45fb3662007-07-13 14:34:19 +02002070 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002071 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2072 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002073 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2074exit:
2075 superio_exit(sioaddr);
2076 return err;
2077}
2078
Hans de Goede498be962009-01-07 16:37:28 +01002079static int __init f71882fg_device_add(unsigned short address,
2080 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002081{
2082 struct resource res = {
2083 .start = address,
2084 .end = address + REGION_LENGTH - 1,
2085 .flags = IORESOURCE_IO,
2086 };
2087 int err;
2088
2089 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002090 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002091 return -ENOMEM;
2092
2093 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002094 err = acpi_check_resource_conflict(&res);
2095 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002096 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002097
Hans de Goede45fb3662007-07-13 14:34:19 +02002098 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002099 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002100 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2101 goto exit_device_put;
2102 }
2103
Hans de Goede498be962009-01-07 16:37:28 +01002104 err = platform_device_add_data(f71882fg_pdev, sio_data,
2105 sizeof(struct f71882fg_sio_data));
2106 if (err) {
2107 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2108 goto exit_device_put;
2109 }
2110
Hans de Goede45fb3662007-07-13 14:34:19 +02002111 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002112 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002113 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2114 goto exit_device_put;
2115 }
2116
2117 return 0;
2118
2119exit_device_put:
2120 platform_device_put(f71882fg_pdev);
2121
2122 return err;
2123}
2124
2125static int __init f71882fg_init(void)
2126{
2127 int err = -ENODEV;
2128 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002129 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002130
Hans de Goede498be962009-01-07 16:37:28 +01002131 memset(&sio_data, 0, sizeof(sio_data));
2132
2133 if (f71882fg_find(0x2e, &address, &sio_data) &&
2134 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002135 goto exit;
2136
Hans de Goedec13548c2009-01-07 16:37:27 +01002137 err = platform_driver_register(&f71882fg_driver);
2138 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002139 goto exit;
2140
Hans de Goede498be962009-01-07 16:37:28 +01002141 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002142 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002143 goto exit_driver;
2144
2145 return 0;
2146
2147exit_driver:
2148 platform_driver_unregister(&f71882fg_driver);
2149exit:
2150 return err;
2151}
2152
2153static void __exit f71882fg_exit(void)
2154{
2155 platform_device_unregister(f71882fg_pdev);
2156 platform_driver_unregister(&f71882fg_driver);
2157}
2158
2159MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002160MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002161MODULE_LICENSE("GPL");
2162
2163module_init(f71882fg_init);
2164module_exit(f71882fg_exit);