blob: 75afb3b0e0763c184a1b22cdc163ef32d10d2969 [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 Goede76698962009-12-09 20:36:01 +010051#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010052#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020053
54#define REGION_LENGTH 8
55#define ADDR_REG_OFFSET 5
56#define DATA_REG_OFFSET 6
57
58#define F71882FG_REG_PECI 0x0A
59
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
61#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010063#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010066#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
67#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_FAN_STATUS 0x92
69#define F71882FG_REG_FAN_BEEP 0x93
70
Hans de Goede7567a042009-01-07 16:37:28 +010071#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
72#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
73#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_STATUS 0x62
75#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020076#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010077#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020078#define F71882FG_REG_TEMP_TYPE 0x6B
79#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
80
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
82#define F71882FG_REG_PWM_TYPE 0x94
83#define F71882FG_REG_PWM_ENABLE 0x96
84
Hans de Goedebc274902009-01-07 16:37:29 +010085#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010086
87#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
88#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
89#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
90
Hans de Goede45fb3662007-07-13 14:34:19 +020091#define F71882FG_REG_START 0x01
92
93#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
94
Jean Delvare67b671b2007-12-06 23:13:42 +010095static unsigned short force_id;
96module_param(force_id, ushort, 0);
97MODULE_PARM_DESC(force_id, "Override the detected device ID");
98
Andrew Mortonf2e41e92010-08-19 14:13:31 -070099enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100100
101static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200102 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100103 "f71862fg",
104 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100105 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100106 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100107};
108
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100109static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200110
111/* Super-I/O Function prototypes */
112static inline int superio_inb(int base, int reg);
113static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400114static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200115static inline void superio_select(int base, int ld);
116static inline void superio_exit(int base);
117
Hans de Goede498be962009-01-07 16:37:28 +0100118struct f71882fg_sio_data {
119 enum chips type;
120};
121
Hans de Goede45fb3662007-07-13 14:34:19 +0200122struct f71882fg_data {
123 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100124 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700125 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200126
127 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200128 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200129 char valid; /* !=0 if following fields are valid */
130 unsigned long last_updated; /* In jiffies */
131 unsigned long last_limits; /* In jiffies */
132
133 /* Register Values */
134 u8 in[9];
135 u8 in1_max;
136 u8 in_status;
137 u8 in_beep;
138 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100139 u16 fan_target[4];
140 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200141 u8 fan_status;
142 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100143 /* Note: all models have only 3 temperature channels, but on some
144 they are addressed as 0-2 and on others as 1-3, so for coding
145 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200146 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100147 u8 temp_ovt[4];
148 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100149 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100150 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200151 u8 temp_status;
152 u8 temp_beep;
153 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200154 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100155 u8 pwm[4];
156 u8 pwm_enable;
157 u8 pwm_auto_point_hyst[2];
158 u8 pwm_auto_point_mapping[4];
159 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100160 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200161};
162
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100163/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200164static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
165 char *buf);
166static ssize_t show_in_max(struct device *dev, struct device_attribute
167 *devattr, char *buf);
168static ssize_t store_in_max(struct device *dev, struct device_attribute
169 *devattr, const char *buf, size_t count);
170static ssize_t show_in_beep(struct device *dev, struct device_attribute
171 *devattr, char *buf);
172static ssize_t store_in_beep(struct device *dev, struct device_attribute
173 *devattr, const char *buf, size_t count);
174static ssize_t show_in_alarm(struct device *dev, struct device_attribute
175 *devattr, char *buf);
176/* Sysfs Fan */
177static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
178 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100179static ssize_t show_fan_full_speed(struct device *dev,
180 struct device_attribute *devattr, char *buf);
181static ssize_t store_fan_full_speed(struct device *dev,
182 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200183static ssize_t show_fan_beep(struct device *dev, struct device_attribute
184 *devattr, char *buf);
185static ssize_t store_fan_beep(struct device *dev, struct device_attribute
186 *devattr, const char *buf, size_t count);
187static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189/* Sysfs Temp */
190static ssize_t show_temp(struct device *dev, struct device_attribute
191 *devattr, char *buf);
192static ssize_t show_temp_max(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t store_temp_max(struct device *dev, struct device_attribute
195 *devattr, const char *buf, size_t count);
196static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
199 *devattr, const char *buf, size_t count);
200static ssize_t show_temp_crit(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_temp_crit(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_type(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t show_temp_beep(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t store_temp_beep(struct device *dev, struct device_attribute
211 *devattr, const char *buf, size_t count);
212static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
213 *devattr, char *buf);
214static ssize_t show_temp_fault(struct device *dev, struct device_attribute
215 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100216/* PWM and Auto point control */
217static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
218 char *buf);
219static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
220 const char *buf, size_t count);
221static ssize_t show_pwm_enable(struct device *dev,
222 struct device_attribute *devattr, char *buf);
223static ssize_t store_pwm_enable(struct device *dev,
224 struct device_attribute *devattr, const char *buf, size_t count);
225static ssize_t show_pwm_interpolate(struct device *dev,
226 struct device_attribute *devattr, char *buf);
227static ssize_t store_pwm_interpolate(struct device *dev,
228 struct device_attribute *devattr, const char *buf, size_t count);
229static ssize_t show_pwm_auto_point_channel(struct device *dev,
230 struct device_attribute *devattr, char *buf);
231static ssize_t store_pwm_auto_point_channel(struct device *dev,
232 struct device_attribute *devattr, const char *buf, size_t count);
233static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
234 struct device_attribute *devattr, char *buf);
235static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
236 struct device_attribute *devattr, const char *buf, size_t count);
237static ssize_t show_pwm_auto_point_pwm(struct device *dev,
238 struct device_attribute *devattr, char *buf);
239static ssize_t store_pwm_auto_point_pwm(struct device *dev,
240 struct device_attribute *devattr, const char *buf, size_t count);
241static ssize_t show_pwm_auto_point_temp(struct device *dev,
242 struct device_attribute *devattr, char *buf);
243static ssize_t store_pwm_auto_point_temp(struct device *dev,
244 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200245/* Sysfs misc */
246static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
247 char *buf);
248
249static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100250static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200251
252static struct platform_driver f71882fg_driver = {
253 .driver = {
254 .owner = THIS_MODULE,
255 .name = DRVNAME,
256 },
257 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200258 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200259};
260
Hans de Goedec13548c2009-01-07 16:37:27 +0100261static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200262
Hans de Goede66344aa2009-12-09 20:35:59 +0100263/* Temp and in attr for the f71858fg, the f71858fg is special as it
264 has its temperature indexes start at 0 (the others start at 1) and
265 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200266static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
267 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
268 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
269 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
270 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
271 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
272 store_temp_max, 0, 0),
273 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
274 store_temp_max_hyst, 0, 0),
275 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
276 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
277 store_temp_crit, 0, 0),
278 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
279 0, 0),
280 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
281 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
282 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
283 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
284 store_temp_max, 0, 1),
285 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
286 store_temp_max_hyst, 0, 1),
287 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
288 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
289 store_temp_crit, 0, 1),
290 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
291 0, 1),
292 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
293 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
294 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
295 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
296 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
297 store_temp_max, 0, 2),
298 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
299 store_temp_max_hyst, 0, 2),
300 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
301 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
302 store_temp_crit, 0, 2),
303 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
304 0, 2),
305 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
306 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
307};
308
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700309/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
310static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100311 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
312 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100313 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
314 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
315 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
316 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
317 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
318 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
319 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100320 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100321 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100322 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100323 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100324 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100325 /* Should really be temp1_max_alarm, but older versions did not handle
326 the max and crit alarms separately and lm_sensors v2 depends on the
327 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
328 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
329 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
330 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100331 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100332 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100333 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100334 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100335 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
336 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
337 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100338 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100339 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
340 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
341 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100342 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100343 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100344 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100345 /* Should be temp2_max_alarm, see temp1_alarm note */
346 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
347 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
348 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100349 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100350 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100353 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
354 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
355 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100357 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
358 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
359 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
360 store_temp_max, 0, 3),
361 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
362 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100363 /* Should be temp3_max_alarm, see temp1_alarm note */
364 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
365 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
366 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
368 store_temp_crit, 0, 3),
369 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
370 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100371 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
372 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
373 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100374 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200376};
377
Hans de Goede66344aa2009-12-09 20:35:59 +0100378/* For models with in1 alarm capability */
379static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100380 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
381 0, 1),
382 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
383 0, 1),
384 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
385};
386
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100387/* Temp and in attr for the f8000
388 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
389 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100390 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100391 */
392static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
393 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
394 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
395 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
396 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
397 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
398 store_temp_crit, 0, 0),
399 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
400 store_temp_max, 0, 0),
401 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200402 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100403 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
404 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
405 store_temp_crit, 0, 1),
406 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
407 store_temp_max, 0, 1),
408 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
409 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200410 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100411 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
412 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
413 store_temp_crit, 0, 2),
414 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
415 store_temp_max, 0, 2),
416 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200417 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100418};
419
420/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100421static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100422 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100423 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
424 show_fan_full_speed,
425 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100427 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
428 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
429 store_pwm_enable, 0, 0),
430 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
431 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100432}, {
433 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
434 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
435 show_fan_full_speed,
436 store_fan_full_speed, 0, 1),
437 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100438 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
439 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
440 store_pwm_enable, 0, 1),
441 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
442 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100443}, {
444 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
445 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
446 show_fan_full_speed,
447 store_fan_full_speed, 0, 2),
448 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200449 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
450 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
451 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100452 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
453 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100454}, {
455 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
456 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
457 show_fan_full_speed,
458 store_fan_full_speed, 0, 3),
459 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
460 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
461 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
462 store_pwm_enable, 0, 3),
463 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
464 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
465} };
Hans de Goede498be962009-01-07 16:37:28 +0100466
Hans de Goede66344aa2009-12-09 20:35:59 +0100467/* Attr for models which can beep on Fan alarm */
468static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100469 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
470 store_fan_beep, 0, 0),
471 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
472 store_fan_beep, 0, 1),
473 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100475 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
476 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100477};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100478
Hans de Goede66344aa2009-12-09 20:35:59 +0100479/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
480 f71858fg / f71882fg / f71889fg */
481static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
482 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
483 show_pwm_auto_point_channel,
484 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100485 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
486 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
487 1, 0),
488 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
489 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
490 4, 0),
491 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
492 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
493 0, 0),
494 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
495 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
496 3, 0),
497 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
498 show_pwm_auto_point_temp_hyst,
499 store_pwm_auto_point_temp_hyst,
500 0, 0),
501 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
502 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
503
Hans de Goede66344aa2009-12-09 20:35:59 +0100504 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_channel,
506 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100507 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 1, 1),
510 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
512 4, 1),
513 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 0, 1),
516 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 3, 1),
519 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp_hyst,
521 store_pwm_auto_point_temp_hyst,
522 0, 1),
523 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
524 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100525
Hans de Goede66344aa2009-12-09 20:35:59 +0100526 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_channel,
528 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100529 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 1, 2),
532 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
534 4, 2),
535 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 0, 2),
538 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
540 3, 2),
541 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp_hyst,
543 store_pwm_auto_point_temp_hyst,
544 0, 2),
545 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
546 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100547};
548
Hans de Goede66344aa2009-12-09 20:35:59 +0100549/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100550static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100551 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_channel,
553 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100554 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
556 0, 0),
557 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
559 1, 0),
560 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
562 2, 0),
563 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
565 3, 0),
566 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
567 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
568 4, 0),
569 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
571 0, 0),
572 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
573 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
574 1, 0),
575 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
576 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
577 2, 0),
578 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
580 3, 0),
581 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_temp_hyst,
583 store_pwm_auto_point_temp_hyst,
584 0, 0),
585 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
586 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
587 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
588 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
589 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100591}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100592 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
593 show_pwm_auto_point_channel,
594 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100595 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
596 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
597 0, 1),
598 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
599 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
600 1, 1),
601 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
602 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
603 2, 1),
604 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
605 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
606 3, 1),
607 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
609 4, 1),
610 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
612 0, 1),
613 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
615 1, 1),
616 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
618 2, 1),
619 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
621 3, 1),
622 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_temp_hyst,
624 store_pwm_auto_point_temp_hyst,
625 0, 1),
626 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
627 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
628 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
630 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
631 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100632}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100633 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
634 show_pwm_auto_point_channel,
635 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100636 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
637 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
638 0, 2),
639 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
640 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
641 1, 2),
642 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
643 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
644 2, 2),
645 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
646 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
647 3, 2),
648 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
649 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
650 4, 2),
651 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
652 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
653 0, 2),
654 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
656 1, 2),
657 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
659 2, 2),
660 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
662 3, 2),
663 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_temp_hyst,
665 store_pwm_auto_point_temp_hyst,
666 0, 2),
667 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
668 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
669 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
671 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
672 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100673}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100674 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_channel,
676 store_pwm_auto_point_channel, 0, 3),
677 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
679 0, 3),
680 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
682 1, 3),
683 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
685 2, 3),
686 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
688 3, 3),
689 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
691 4, 3),
692 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
693 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
694 0, 3),
695 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
697 1, 3),
698 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
700 2, 3),
701 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
703 3, 3),
704 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_temp_hyst,
706 store_pwm_auto_point_temp_hyst,
707 0, 3),
708 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
709 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
710 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
712 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100714} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200715
Hans de Goede66344aa2009-12-09 20:35:59 +0100716/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100717static struct sensor_device_attribute_2 f8000_fan_attr[] = {
718 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100719};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100720
Hans de Goede66344aa2009-12-09 20:35:59 +0100721/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
722 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
723 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
724static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
725 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_channel,
727 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100728 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 0, 2),
731 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 1, 2),
734 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
736 2, 2),
737 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
739 3, 2),
740 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
742 4, 2),
743 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
745 0, 2),
746 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
748 1, 2),
749 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
751 2, 2),
752 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
754 3, 2),
755 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_temp_hyst,
757 store_pwm_auto_point_temp_hyst,
758 0, 2),
759 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
760 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
761 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
763 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
765
Hans de Goede66344aa2009-12-09 20:35:59 +0100766 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_channel,
768 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100769 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
771 0, 0),
772 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
774 1, 0),
775 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
777 2, 0),
778 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
780 3, 0),
781 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
783 4, 0),
784 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
785 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
786 0, 0),
787 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
789 1, 0),
790 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
791 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
792 2, 0),
793 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
794 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
795 3, 0),
796 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
797 show_pwm_auto_point_temp_hyst,
798 store_pwm_auto_point_temp_hyst,
799 0, 0),
800 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
801 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
802 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
804 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
806
Hans de Goede66344aa2009-12-09 20:35:59 +0100807 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_channel,
809 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100810 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
812 0, 1),
813 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
815 1, 1),
816 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
818 2, 1),
819 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
821 3, 1),
822 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
823 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
824 4, 1),
825 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
826 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
827 0, 1),
828 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
830 1, 1),
831 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
832 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
833 2, 1),
834 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
835 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
836 3, 1),
837 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
838 show_pwm_auto_point_temp_hyst,
839 store_pwm_auto_point_temp_hyst,
840 0, 1),
841 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
842 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
843 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
845 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
847};
Hans de Goede45fb3662007-07-13 14:34:19 +0200848
849/* Super I/O functions */
850static inline int superio_inb(int base, int reg)
851{
852 outb(reg, base);
853 return inb(base + 1);
854}
855
856static int superio_inw(int base, int reg)
857{
858 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200859 val = superio_inb(base, reg) << 8;
860 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200861 return val;
862}
863
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400864static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200865{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400866 /* Don't step on other drivers' I/O space by accident */
867 if (!request_muxed_region(base, 2, DRVNAME)) {
868 printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
869 base);
870 return -EBUSY;
871 }
872
Hans de Goede45fb3662007-07-13 14:34:19 +0200873 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200874 outb(SIO_UNLOCK_KEY, base);
875 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400876
877 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200878}
879
Giel van Schijndel162bb592010-05-27 19:58:40 +0200880static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200881{
882 outb(SIO_REG_LDSEL, base);
883 outb(ld, base + 1);
884}
885
886static inline void superio_exit(int base)
887{
888 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400889 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200890}
891
Hans de Goede2f650632009-01-07 16:37:31 +0100892static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200893{
894 return reg ? (1500000 / reg) : 0;
895}
896
Hans de Goede2f650632009-01-07 16:37:31 +0100897static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100898{
899 return fan ? (1500000 / fan) : 0;
900}
901
Hans de Goede45fb3662007-07-13 14:34:19 +0200902static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
903{
904 u8 val;
905
906 outb(reg, data->addr + ADDR_REG_OFFSET);
907 val = inb(data->addr + DATA_REG_OFFSET);
908
909 return val;
910}
911
912static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
913{
914 u16 val;
915
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200916 val = f71882fg_read8(data, reg) << 8;
917 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200918
919 return val;
920}
921
922static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
923{
924 outb(reg, data->addr + ADDR_REG_OFFSET);
925 outb(val, data->addr + DATA_REG_OFFSET);
926}
927
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100928static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
929{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200930 f71882fg_write8(data, reg, val >> 8);
931 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100932}
933
Hans de Goede09475d32009-06-15 18:39:52 +0200934static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
935{
936 if (data->type == f71858fg)
937 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
938 else
939 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
940}
941
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100942static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200943{
944 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100945 int nr, reg = 0, reg2;
946 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200947 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200948
949 mutex_lock(&data->update_lock);
950
951 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200952 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200953 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100954 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100955 data->in1_max =
956 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
957 data->in_beep =
958 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
959 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200960
961 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200962 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200963 data->temp_ovt[nr] = f71882fg_read8(data,
964 F71882FG_REG_TEMP_OVT(nr));
965 data->temp_high[nr] = f71882fg_read8(data,
966 F71882FG_REG_TEMP_HIGH(nr));
967 }
968
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100969 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100970 data->temp_hyst[0] = f71882fg_read8(data,
971 F71882FG_REG_TEMP_HYST(0));
972 data->temp_hyst[1] = f71882fg_read8(data,
973 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200974 }
975
Hans de Goede76698962009-12-09 20:36:01 +0100976 if (data->type == f71862fg || data->type == f71882fg ||
977 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200978 data->fan_beep = f71882fg_read8(data,
979 F71882FG_REG_FAN_BEEP);
980 data->temp_beep = f71882fg_read8(data,
981 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100982 /* Have to hardcode type, because temp1 is special */
983 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
984 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
985 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
986 }
Hans de Goede76698962009-12-09 20:36:01 +0100987 /* Determine temp index 1 sensor type */
988 if (data->type == f71889fg) {
989 reg2 = f71882fg_read8(data, F71882FG_REG_START);
990 switch ((reg2 & 0x60) >> 5) {
991 case 0x00: /* BJT / Thermistor */
992 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
993 break;
994 case 0x01: /* AMDSI */
995 data->temp_type[1] = 5;
996 break;
997 case 0x02: /* PECI */
998 case 0x03: /* Ibex Peak ?? Report as PECI for now */
999 data->temp_type[1] = 6;
1000 break;
1001 }
1002 } else {
1003 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
1004 if ((reg2 & 0x03) == 0x01)
1005 data->temp_type[1] = 6; /* PECI */
1006 else if ((reg2 & 0x03) == 0x02)
1007 data->temp_type[1] = 5; /* AMDSI */
1008 else if (data->type == f71862fg ||
1009 data->type == f71882fg)
1010 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1011 else /* f71858fg and f8000 only support BJT */
1012 data->temp_type[1] = 2;
1013 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001014
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001015 data->pwm_enable = f71882fg_read8(data,
1016 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001017 data->pwm_auto_point_hyst[0] =
1018 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1019 data->pwm_auto_point_hyst[1] =
1020 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1021
Hans de Goede498be962009-01-07 16:37:28 +01001022 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001023 data->pwm_auto_point_mapping[nr] =
1024 f71882fg_read8(data,
1025 F71882FG_REG_POINT_MAPPING(nr));
1026
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001027 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001028 int point;
1029 for (point = 0; point < 5; point++) {
1030 data->pwm_auto_point_pwm[nr][point] =
1031 f71882fg_read8(data,
1032 F71882FG_REG_POINT_PWM
1033 (nr, point));
1034 }
1035 for (point = 0; point < 4; point++) {
1036 data->pwm_auto_point_temp[nr][point] =
1037 f71882fg_read8(data,
1038 F71882FG_REG_POINT_TEMP
1039 (nr, point));
1040 }
1041 } else {
1042 data->pwm_auto_point_pwm[nr][1] =
1043 f71882fg_read8(data,
1044 F71882FG_REG_POINT_PWM
1045 (nr, 1));
1046 data->pwm_auto_point_pwm[nr][4] =
1047 f71882fg_read8(data,
1048 F71882FG_REG_POINT_PWM
1049 (nr, 4));
1050 data->pwm_auto_point_temp[nr][0] =
1051 f71882fg_read8(data,
1052 F71882FG_REG_POINT_TEMP
1053 (nr, 0));
1054 data->pwm_auto_point_temp[nr][3] =
1055 f71882fg_read8(data,
1056 F71882FG_REG_POINT_TEMP
1057 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001058 }
1059 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001060 data->last_limits = jiffies;
1061 }
1062
1063 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001064 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001065 data->temp_status = f71882fg_read8(data,
1066 F71882FG_REG_TEMP_STATUS);
1067 data->temp_diode_open = f71882fg_read8(data,
1068 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001069 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1070 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001071
1072 data->fan_status = f71882fg_read8(data,
1073 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001074 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001075 data->fan[nr] = f71882fg_read16(data,
1076 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001077 data->fan_target[nr] =
1078 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1079 data->fan_full_speed[nr] =
1080 f71882fg_read16(data,
1081 F71882FG_REG_FAN_FULL_SPEED(nr));
1082 data->pwm[nr] =
1083 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1084 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001085
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001086 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1087 if (data->type == f8000)
1088 data->fan[3] = f71882fg_read16(data,
1089 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001090 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001091 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001092 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001093 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001094 data->in[nr] = f71882fg_read8(data,
1095 F71882FG_REG_IN(nr));
1096
1097 data->last_updated = jiffies;
1098 data->valid = 1;
1099 }
1100
1101 mutex_unlock(&data->update_lock);
1102
1103 return data;
1104}
1105
1106/* Sysfs Interface */
1107static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1108 char *buf)
1109{
1110 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001111 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001112 int speed = fan_from_reg(data->fan[nr]);
1113
1114 if (speed == FAN_MIN_DETECT)
1115 speed = 0;
1116
1117 return sprintf(buf, "%d\n", speed);
1118}
1119
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001120static ssize_t show_fan_full_speed(struct device *dev,
1121 struct device_attribute *devattr, char *buf)
1122{
1123 struct f71882fg_data *data = f71882fg_update_device(dev);
1124 int nr = to_sensor_dev_attr_2(devattr)->index;
1125 int speed = fan_from_reg(data->fan_full_speed[nr]);
1126 return sprintf(buf, "%d\n", speed);
1127}
1128
1129static ssize_t store_fan_full_speed(struct device *dev,
1130 struct device_attribute *devattr,
1131 const char *buf, size_t count)
1132{
1133 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001134 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1135 long val;
1136
1137 err = strict_strtol(buf, 10, &val);
1138 if (err)
1139 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001140
1141 val = SENSORS_LIMIT(val, 23, 1500000);
1142 val = fan_to_reg(val);
1143
1144 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001145 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1146 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001147 mutex_unlock(&data->update_lock);
1148
1149 return count;
1150}
1151
Hans de Goede45fb3662007-07-13 14:34:19 +02001152static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1153 *devattr, char *buf)
1154{
1155 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001156 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001157
1158 if (data->fan_beep & (1 << nr))
1159 return sprintf(buf, "1\n");
1160 else
1161 return sprintf(buf, "0\n");
1162}
1163
1164static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1165 *devattr, const char *buf, size_t count)
1166{
1167 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001168 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1169 unsigned long val;
1170
1171 err = strict_strtoul(buf, 10, &val);
1172 if (err)
1173 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001174
1175 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001176 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001177 if (val)
1178 data->fan_beep |= 1 << nr;
1179 else
1180 data->fan_beep &= ~(1 << nr);
1181
1182 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1183 mutex_unlock(&data->update_lock);
1184
1185 return count;
1186}
1187
1188static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1189 *devattr, char *buf)
1190{
1191 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001192 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001193
1194 if (data->fan_status & (1 << nr))
1195 return sprintf(buf, "1\n");
1196 else
1197 return sprintf(buf, "0\n");
1198}
1199
1200static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1201 char *buf)
1202{
1203 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001204 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001205
1206 return sprintf(buf, "%d\n", data->in[nr] * 8);
1207}
1208
1209static ssize_t show_in_max(struct device *dev, struct device_attribute
1210 *devattr, char *buf)
1211{
1212 struct f71882fg_data *data = f71882fg_update_device(dev);
1213
1214 return sprintf(buf, "%d\n", data->in1_max * 8);
1215}
1216
1217static ssize_t store_in_max(struct device *dev, struct device_attribute
1218 *devattr, const char *buf, size_t count)
1219{
1220 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001221 int err;
1222 long val;
1223
1224 err = strict_strtol(buf, 10, &val);
1225 if (err)
1226 return err;
1227
1228 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001229 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001230
1231 mutex_lock(&data->update_lock);
1232 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1233 data->in1_max = val;
1234 mutex_unlock(&data->update_lock);
1235
1236 return count;
1237}
1238
1239static ssize_t show_in_beep(struct device *dev, struct device_attribute
1240 *devattr, char *buf)
1241{
1242 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001243 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001244
1245 if (data->in_beep & (1 << nr))
1246 return sprintf(buf, "1\n");
1247 else
1248 return sprintf(buf, "0\n");
1249}
1250
1251static ssize_t store_in_beep(struct device *dev, struct device_attribute
1252 *devattr, const char *buf, size_t count)
1253{
1254 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001255 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1256 unsigned long val;
1257
1258 err = strict_strtoul(buf, 10, &val);
1259 if (err)
1260 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001261
1262 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001263 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001264 if (val)
1265 data->in_beep |= 1 << nr;
1266 else
1267 data->in_beep &= ~(1 << nr);
1268
1269 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1270 mutex_unlock(&data->update_lock);
1271
1272 return count;
1273}
1274
1275static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1276 *devattr, char *buf)
1277{
1278 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001279 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001280
1281 if (data->in_status & (1 << nr))
1282 return sprintf(buf, "1\n");
1283 else
1284 return sprintf(buf, "0\n");
1285}
1286
1287static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1288 char *buf)
1289{
1290 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001291 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001292 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001293
Hans de Goede09475d32009-06-15 18:39:52 +02001294 if (data->type == f71858fg) {
1295 /* TEMP_TABLE_SEL 1 or 3 ? */
1296 if (data->temp_config & 1) {
1297 sign = data->temp[nr] & 0x0001;
1298 temp = (data->temp[nr] >> 5) & 0x7ff;
1299 } else {
1300 sign = data->temp[nr] & 0x8000;
1301 temp = (data->temp[nr] >> 5) & 0x3ff;
1302 }
1303 temp *= 125;
1304 if (sign)
1305 temp -= 128000;
1306 } else
1307 temp = data->temp[nr] * 1000;
1308
1309 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001310}
1311
1312static ssize_t show_temp_max(struct device *dev, struct device_attribute
1313 *devattr, char *buf)
1314{
1315 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001316 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001317
1318 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1319}
1320
1321static ssize_t store_temp_max(struct device *dev, struct device_attribute
1322 *devattr, const char *buf, size_t count)
1323{
1324 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001325 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1326 long val;
1327
1328 err = strict_strtol(buf, 10, &val);
1329 if (err)
1330 return err;
1331
1332 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001333 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001334
1335 mutex_lock(&data->update_lock);
1336 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1337 data->temp_high[nr] = val;
1338 mutex_unlock(&data->update_lock);
1339
1340 return count;
1341}
1342
1343static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1344 *devattr, char *buf)
1345{
1346 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001347 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001348 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001349
Hans de Goedece0bfa52009-01-07 16:37:28 +01001350 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001351 if (nr & 1)
1352 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1353 else
1354 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1355 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001356 mutex_unlock(&data->update_lock);
1357
1358 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001359}
1360
1361static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1362 *devattr, const char *buf, size_t count)
1363{
1364 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001365 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001366 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001367 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001368 long val;
1369
1370 err = strict_strtol(buf, 10, &val);
1371 if (err)
1372 return err;
1373
1374 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001375
1376 mutex_lock(&data->update_lock);
1377
1378 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001379 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1380 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1381 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001382 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001383
1384 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001385 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1386 if (nr & 1)
1387 reg = (reg & 0x0f) | (val << 4);
1388 else
1389 reg = (reg & 0xf0) | val;
1390 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1391 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001392
Hans de Goede45fb3662007-07-13 14:34:19 +02001393 mutex_unlock(&data->update_lock);
1394 return ret;
1395}
1396
1397static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1398 *devattr, char *buf)
1399{
1400 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001401 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001402
1403 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1404}
1405
1406static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1407 *devattr, const char *buf, size_t count)
1408{
1409 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001410 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1411 long val;
1412
1413 err = strict_strtol(buf, 10, &val);
1414 if (err)
1415 return err;
1416
1417 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001418 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001419
1420 mutex_lock(&data->update_lock);
1421 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1422 data->temp_ovt[nr] = val;
1423 mutex_unlock(&data->update_lock);
1424
1425 return count;
1426}
1427
1428static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1429 *devattr, char *buf)
1430{
1431 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001432 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001433 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001434
Hans de Goedece0bfa52009-01-07 16:37:28 +01001435 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001436 if (nr & 1)
1437 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1438 else
1439 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1440 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001441 mutex_unlock(&data->update_lock);
1442
1443 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001444}
1445
1446static ssize_t show_temp_type(struct device *dev, struct device_attribute
1447 *devattr, char *buf)
1448{
1449 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001450 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001451
1452 return sprintf(buf, "%d\n", data->temp_type[nr]);
1453}
1454
1455static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1456 *devattr, char *buf)
1457{
1458 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001459 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001460
Hans de Goede7567a042009-01-07 16:37:28 +01001461 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001462 return sprintf(buf, "1\n");
1463 else
1464 return sprintf(buf, "0\n");
1465}
1466
1467static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1468 *devattr, const char *buf, size_t count)
1469{
1470 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001471 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1472 unsigned long val;
1473
1474 err = strict_strtoul(buf, 10, &val);
1475 if (err)
1476 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001477
1478 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001479 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001480 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001481 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001482 else
Hans de Goede7567a042009-01-07 16:37:28 +01001483 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001484
1485 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1486 mutex_unlock(&data->update_lock);
1487
1488 return count;
1489}
1490
1491static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1492 *devattr, char *buf)
1493{
1494 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001495 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001496
Hans de Goede7567a042009-01-07 16:37:28 +01001497 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001498 return sprintf(buf, "1\n");
1499 else
1500 return sprintf(buf, "0\n");
1501}
1502
1503static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1504 *devattr, char *buf)
1505{
1506 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001507 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001508
Hans de Goede7567a042009-01-07 16:37:28 +01001509 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001510 return sprintf(buf, "1\n");
1511 else
1512 return sprintf(buf, "0\n");
1513}
1514
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001515static ssize_t show_pwm(struct device *dev,
1516 struct device_attribute *devattr, char *buf)
1517{
1518 struct f71882fg_data *data = f71882fg_update_device(dev);
1519 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001520 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001521 if (data->pwm_enable & (1 << (2 * nr)))
1522 /* PWM mode */
1523 val = data->pwm[nr];
1524 else {
1525 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001526 val = 255 * fan_from_reg(data->fan_target[nr])
1527 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001528 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001529 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001530 return sprintf(buf, "%d\n", val);
1531}
1532
1533static ssize_t store_pwm(struct device *dev,
1534 struct device_attribute *devattr, const char *buf,
1535 size_t count)
1536{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001537 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001538 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1539 long val;
1540
1541 err = strict_strtol(buf, 10, &val);
1542 if (err)
1543 return err;
1544
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001545 val = SENSORS_LIMIT(val, 0, 255);
1546
1547 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001548 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001549 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1550 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1551 count = -EROFS;
1552 goto leave;
1553 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001554 if (data->pwm_enable & (1 << (2 * nr))) {
1555 /* PWM mode */
1556 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1557 data->pwm[nr] = val;
1558 } else {
1559 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001560 int target, full_speed;
1561 full_speed = f71882fg_read16(data,
1562 F71882FG_REG_FAN_FULL_SPEED(nr));
1563 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1564 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1565 data->fan_target[nr] = target;
1566 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001567 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001568leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001569 mutex_unlock(&data->update_lock);
1570
1571 return count;
1572}
1573
1574static ssize_t show_pwm_enable(struct device *dev,
1575 struct device_attribute *devattr, char *buf)
1576{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001577 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001578 struct f71882fg_data *data = f71882fg_update_device(dev);
1579 int nr = to_sensor_dev_attr_2(devattr)->index;
1580
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001581 switch ((data->pwm_enable >> 2 * nr) & 3) {
1582 case 0:
1583 case 1:
1584 result = 2; /* Normal auto mode */
1585 break;
1586 case 2:
1587 result = 1; /* Manual mode */
1588 break;
1589 case 3:
1590 if (data->type == f8000)
1591 result = 3; /* Thermostat mode */
1592 else
1593 result = 1; /* Manual mode */
1594 break;
1595 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001596
1597 return sprintf(buf, "%d\n", result);
1598}
1599
1600static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1601 *devattr, const char *buf, size_t count)
1602{
1603 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001604 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1605 long val;
1606
1607 err = strict_strtol(buf, 10, &val);
1608 if (err)
1609 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001610
Hans de Goede3fc78382009-06-15 18:39:50 +02001611 /* Special case for F8000 pwm channel 3 which only does auto mode */
1612 if (data->type == f8000 && nr == 2 && val != 2)
1613 return -EINVAL;
1614
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001615 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001616 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001617 /* Special case for F8000 auto PWM mode / Thermostat mode */
1618 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1619 switch (val) {
1620 case 2:
1621 data->pwm_enable &= ~(2 << (2 * nr));
1622 break; /* Normal auto mode */
1623 case 3:
1624 data->pwm_enable |= 2 << (2 * nr);
1625 break; /* Thermostat mode */
1626 default:
1627 count = -EINVAL;
1628 goto leave;
1629 }
1630 } else {
1631 switch (val) {
1632 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001633 /* The f71858fg does not support manual RPM mode */
1634 if (data->type == f71858fg &&
1635 ((data->pwm_enable >> (2 * nr)) & 1)) {
1636 count = -EINVAL;
1637 goto leave;
1638 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001639 data->pwm_enable |= 2 << (2 * nr);
1640 break; /* Manual */
1641 case 2:
1642 data->pwm_enable &= ~(2 << (2 * nr));
1643 break; /* Normal auto mode */
1644 default:
1645 count = -EINVAL;
1646 goto leave;
1647 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001648 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001649 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001650leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001651 mutex_unlock(&data->update_lock);
1652
1653 return count;
1654}
1655
1656static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1657 struct device_attribute *devattr,
1658 char *buf)
1659{
1660 int result;
1661 struct f71882fg_data *data = f71882fg_update_device(dev);
1662 int pwm = to_sensor_dev_attr_2(devattr)->index;
1663 int point = to_sensor_dev_attr_2(devattr)->nr;
1664
Hans de Goedece0bfa52009-01-07 16:37:28 +01001665 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001666 if (data->pwm_enable & (1 << (2 * pwm))) {
1667 /* PWM mode */
1668 result = data->pwm_auto_point_pwm[pwm][point];
1669 } else {
1670 /* RPM mode */
1671 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1672 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001673 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001674
1675 return sprintf(buf, "%d\n", result);
1676}
1677
1678static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1679 struct device_attribute *devattr,
1680 const char *buf, size_t count)
1681{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001682 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001683 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001684 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001685 long val;
1686
1687 err = strict_strtol(buf, 10, &val);
1688 if (err)
1689 return err;
1690
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001691 val = SENSORS_LIMIT(val, 0, 255);
1692
1693 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001694 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001695 if (data->pwm_enable & (1 << (2 * pwm))) {
1696 /* PWM mode */
1697 } else {
1698 /* RPM mode */
1699 if (val < 29) /* Prevent negative numbers */
1700 val = 255;
1701 else
1702 val = (255 - val) * 32 / val;
1703 }
1704 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1705 data->pwm_auto_point_pwm[pwm][point] = val;
1706 mutex_unlock(&data->update_lock);
1707
1708 return count;
1709}
1710
1711static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1712 struct device_attribute *devattr,
1713 char *buf)
1714{
1715 int result = 0;
1716 struct f71882fg_data *data = f71882fg_update_device(dev);
1717 int nr = to_sensor_dev_attr_2(devattr)->index;
1718 int point = to_sensor_dev_attr_2(devattr)->nr;
1719
1720 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001721 if (nr & 1)
1722 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1723 else
1724 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001725 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1726 mutex_unlock(&data->update_lock);
1727
1728 return sprintf(buf, "%d\n", result);
1729}
1730
1731static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1732 struct device_attribute *devattr,
1733 const char *buf, size_t count)
1734{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001735 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001736 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001737 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001738 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001739 long val;
1740
1741 err = strict_strtol(buf, 10, &val);
1742 if (err)
1743 return err;
1744
1745 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001746
1747 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001748 data->pwm_auto_point_temp[nr][point] =
1749 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001750 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1751 data->pwm_auto_point_temp[nr][point]);
1752 val = data->pwm_auto_point_temp[nr][point] - val;
1753
Hans de Goedebc274902009-01-07 16:37:29 +01001754 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1755 if (nr & 1)
1756 reg = (reg & 0x0f) | (val << 4);
1757 else
1758 reg = (reg & 0xf0) | val;
1759
1760 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1761 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001762 mutex_unlock(&data->update_lock);
1763
1764 return count;
1765}
1766
1767static ssize_t show_pwm_interpolate(struct device *dev,
1768 struct device_attribute *devattr, char *buf)
1769{
1770 int result;
1771 struct f71882fg_data *data = f71882fg_update_device(dev);
1772 int nr = to_sensor_dev_attr_2(devattr)->index;
1773
1774 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1775
1776 return sprintf(buf, "%d\n", result);
1777}
1778
1779static ssize_t store_pwm_interpolate(struct device *dev,
1780 struct device_attribute *devattr,
1781 const char *buf, size_t count)
1782{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001783 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001784 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1785 unsigned long val;
1786
1787 err = strict_strtoul(buf, 10, &val);
1788 if (err)
1789 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001790
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001791 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001792 data->pwm_auto_point_mapping[nr] =
1793 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001794 if (val)
1795 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1796 else
1797 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1798 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1799 data->pwm_auto_point_mapping[nr] = val;
1800 mutex_unlock(&data->update_lock);
1801
1802 return count;
1803}
1804
1805static ssize_t show_pwm_auto_point_channel(struct device *dev,
1806 struct device_attribute *devattr,
1807 char *buf)
1808{
1809 int result;
1810 struct f71882fg_data *data = f71882fg_update_device(dev);
1811 int nr = to_sensor_dev_attr_2(devattr)->index;
1812
Hans de Goede09475d32009-06-15 18:39:52 +02001813 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1814 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001815
1816 return sprintf(buf, "%d\n", result);
1817}
1818
1819static ssize_t store_pwm_auto_point_channel(struct device *dev,
1820 struct device_attribute *devattr,
1821 const char *buf, size_t count)
1822{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001823 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001824 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1825 long val;
1826
1827 err = strict_strtol(buf, 10, &val);
1828 if (err)
1829 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001830
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001831 switch (val) {
1832 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001833 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001834 break;
1835 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001836 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001837 break;
1838 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001839 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001840 break;
1841 default:
1842 return -EINVAL;
1843 }
Hans de Goede09475d32009-06-15 18:39:52 +02001844 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001845 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001846 data->pwm_auto_point_mapping[nr] =
1847 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001848 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1849 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1850 data->pwm_auto_point_mapping[nr] = val;
1851 mutex_unlock(&data->update_lock);
1852
1853 return count;
1854}
1855
1856static ssize_t show_pwm_auto_point_temp(struct device *dev,
1857 struct device_attribute *devattr,
1858 char *buf)
1859{
1860 int result;
1861 struct f71882fg_data *data = f71882fg_update_device(dev);
1862 int pwm = to_sensor_dev_attr_2(devattr)->index;
1863 int point = to_sensor_dev_attr_2(devattr)->nr;
1864
1865 result = data->pwm_auto_point_temp[pwm][point];
1866 return sprintf(buf, "%d\n", 1000 * result);
1867}
1868
1869static ssize_t store_pwm_auto_point_temp(struct device *dev,
1870 struct device_attribute *devattr,
1871 const char *buf, size_t count)
1872{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001873 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001874 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001875 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001876 long val;
1877
1878 err = strict_strtol(buf, 10, &val);
1879 if (err)
1880 return err;
1881
1882 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001883
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001884 if (data->type == f71889fg)
Hans de Goede76698962009-12-09 20:36:01 +01001885 val = SENSORS_LIMIT(val, -128, 127);
1886 else
1887 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001888
1889 mutex_lock(&data->update_lock);
1890 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1891 data->pwm_auto_point_temp[pwm][point] = val;
1892 mutex_unlock(&data->update_lock);
1893
1894 return count;
1895}
1896
Hans de Goede45fb3662007-07-13 14:34:19 +02001897static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1898 char *buf)
1899{
Hans de Goede498be962009-01-07 16:37:28 +01001900 struct f71882fg_data *data = dev_get_drvdata(dev);
1901 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001902}
1903
Hans de Goedec13548c2009-01-07 16:37:27 +01001904static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1905 struct sensor_device_attribute_2 *attr, int count)
1906{
1907 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001908
Hans de Goedec13548c2009-01-07 16:37:27 +01001909 for (i = 0; i < count; i++) {
1910 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1911 if (err)
1912 return err;
1913 }
1914 return 0;
1915}
1916
Hans de Goedefc16c562009-12-09 20:36:01 +01001917static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1918 struct sensor_device_attribute_2 *attr, int count)
1919{
1920 int i;
1921
1922 for (i = 0; i < count; i++)
1923 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1924}
1925
Hans de Goedec13548c2009-01-07 16:37:27 +01001926static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001927{
1928 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001929 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001930 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001931 u8 start_reg;
1932
Hans de Goedec13548c2009-01-07 16:37:27 +01001933 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1934 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001935 return -ENOMEM;
1936
1937 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001938 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001939 data->temp_start =
1940 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001941 mutex_init(&data->update_lock);
1942 platform_set_drvdata(pdev, data);
1943
Hans de Goede3cc74752009-01-07 16:37:28 +01001944 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001945 if (start_reg & 0x04) {
1946 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1947 err = -ENODEV;
1948 goto exit_free;
1949 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001950 if (!(start_reg & 0x03)) {
1951 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1952 err = -ENODEV;
1953 goto exit_free;
1954 }
1955
Hans de Goede45fb3662007-07-13 14:34:19 +02001956 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001957 err = device_create_file(&pdev->dev, &dev_attr_name);
1958 if (err)
1959 goto exit_unregister_sysfs;
1960
Hans de Goedec13548c2009-01-07 16:37:27 +01001961 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001962 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001963 case f71858fg:
1964 data->temp_config =
1965 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1966 if (data->temp_config & 0x10)
1967 /* The f71858fg temperature alarms behave as
1968 the f8000 alarms in this mode */
1969 err = f71882fg_create_sysfs_files(pdev,
1970 f8000_in_temp_attr,
1971 ARRAY_SIZE(f8000_in_temp_attr));
1972 else
1973 err = f71882fg_create_sysfs_files(pdev,
1974 f71858fg_in_temp_attr,
1975 ARRAY_SIZE(f71858fg_in_temp_attr));
1976 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001977 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001978 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001979 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001980 fxxxx_in1_alarm_attr,
1981 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001982 if (err)
1983 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001984 /* fall through! */
1985 case f71862fg:
1986 err = f71882fg_create_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001987 fxxxx_in_temp_attr,
1988 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001989 break;
1990 case f8000:
1991 err = f71882fg_create_sysfs_files(pdev,
1992 f8000_in_temp_attr,
1993 ARRAY_SIZE(f8000_in_temp_attr));
1994 break;
Hans de Goede498be962009-01-07 16:37:28 +01001995 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001996 if (err)
1997 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001998 }
1999
Hans de Goede45fb3662007-07-13 14:34:19 +02002000 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02002001 data->pwm_enable =
2002 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2003
2004 /* Sanity check the pwm settings */
2005 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002006 case f71858fg:
2007 err = 0;
2008 for (i = 0; i < nr_fans; i++)
2009 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2010 err = 1;
2011 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002012 case f71862fg:
2013 err = (data->pwm_enable & 0x15) != 0x15;
2014 break;
2015 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002016 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002017 err = 0;
2018 break;
2019 case f8000:
2020 err = data->pwm_enable & 0x20;
2021 break;
2022 }
2023 if (err) {
2024 dev_err(&pdev->dev,
2025 "Invalid (reserved) pwm settings: 0x%02x\n",
2026 (unsigned int)data->pwm_enable);
2027 err = -ENODEV;
2028 goto exit_unregister_sysfs;
2029 }
2030
Hans de Goedeb69b0392009-12-09 20:36:00 +01002031 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2032 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002033 if (err)
2034 goto exit_unregister_sysfs;
2035
Hans de Goede76698962009-12-09 20:36:01 +01002036 if (data->type == f71862fg || data->type == f71882fg ||
2037 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002038 err = f71882fg_create_sysfs_files(pdev,
2039 fxxxx_fan_beep_attr, nr_fans);
2040 if (err)
2041 goto exit_unregister_sysfs;
2042 }
2043
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002044 switch (data->type) {
2045 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002046 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002047 f71862fg_auto_pwm_attr,
2048 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002049 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002050 case f8000:
2051 err = f71882fg_create_sysfs_files(pdev,
2052 f8000_fan_attr,
2053 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002054 if (err)
2055 goto exit_unregister_sysfs;
2056 err = f71882fg_create_sysfs_files(pdev,
2057 f8000_auto_pwm_attr,
2058 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002059 break;
Hans de Goede76698962009-12-09 20:36:01 +01002060 case f71889fg:
2061 for (i = 0; i < nr_fans; i++) {
2062 data->pwm_auto_point_mapping[i] =
2063 f71882fg_read8(data,
2064 F71882FG_REG_POINT_MAPPING(i));
2065 if (data->pwm_auto_point_mapping[i] & 0x80)
2066 break;
2067 }
2068 if (i != nr_fans) {
2069 dev_warn(&pdev->dev,
2070 "Auto pwm controlled by raw digital "
2071 "data, disabling pwm auto_point "
2072 "sysfs attributes\n");
2073 break;
2074 }
2075 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002076 default: /* f71858fg / f71882fg */
2077 err = f71882fg_create_sysfs_files(pdev,
2078 &fxxxx_auto_pwm_attr[0][0],
2079 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002080 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002081 if (err)
2082 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002083
2084 for (i = 0; i < nr_fans; i++)
2085 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2086 (data->pwm_enable & (1 << 2 * i)) ?
2087 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002088 }
2089
Tony Jones1beeffe2007-08-20 13:46:20 -07002090 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2091 if (IS_ERR(data->hwmon_dev)) {
2092 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002093 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002094 goto exit_unregister_sysfs;
2095 }
2096
2097 return 0;
2098
2099exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002100 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002101 return err; /* f71882fg_remove() also frees our data */
2102exit_free:
2103 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002104 return err;
2105}
2106
Hans de Goedec13548c2009-01-07 16:37:27 +01002107static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002108{
Hans de Goede45fb3662007-07-13 14:34:19 +02002109 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002110 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2111 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002112
2113 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002114 if (data->hwmon_dev)
2115 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002116
Hans de Goedec13548c2009-01-07 16:37:27 +01002117 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002118
Hans de Goedefc16c562009-12-09 20:36:01 +01002119 if (start_reg & 0x01) {
2120 switch (data->type) {
2121 case f71858fg:
2122 if (data->temp_config & 0x10)
2123 f71882fg_remove_sysfs_files(pdev,
2124 f8000_in_temp_attr,
2125 ARRAY_SIZE(f8000_in_temp_attr));
2126 else
2127 f71882fg_remove_sysfs_files(pdev,
2128 f71858fg_in_temp_attr,
2129 ARRAY_SIZE(f71858fg_in_temp_attr));
2130 break;
2131 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002132 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002133 f71882fg_remove_sysfs_files(pdev,
2134 fxxxx_in1_alarm_attr,
2135 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2136 /* fall through! */
2137 case f71862fg:
2138 f71882fg_remove_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07002139 fxxxx_in_temp_attr,
2140 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002141 break;
2142 case f8000:
2143 f71882fg_remove_sysfs_files(pdev,
2144 f8000_in_temp_attr,
2145 ARRAY_SIZE(f8000_in_temp_attr));
2146 break;
2147 }
2148 }
Hans de Goede498be962009-01-07 16:37:28 +01002149
Hans de Goedefc16c562009-12-09 20:36:01 +01002150 if (start_reg & 0x02) {
2151 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2152 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002153
Hans de Goede76698962009-12-09 20:36:01 +01002154 if (data->type == f71862fg || data->type == f71882fg ||
2155 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002156 f71882fg_remove_sysfs_files(pdev,
2157 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002158
Hans de Goedefc16c562009-12-09 20:36:01 +01002159 switch (data->type) {
2160 case f71862fg:
2161 f71882fg_remove_sysfs_files(pdev,
2162 f71862fg_auto_pwm_attr,
2163 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2164 break;
2165 case f8000:
2166 f71882fg_remove_sysfs_files(pdev,
2167 f8000_fan_attr,
2168 ARRAY_SIZE(f8000_fan_attr));
2169 f71882fg_remove_sysfs_files(pdev,
2170 f8000_auto_pwm_attr,
2171 ARRAY_SIZE(f8000_auto_pwm_attr));
2172 break;
2173 default: /* f71858fg / f71882fg / f71889fg */
2174 f71882fg_remove_sysfs_files(pdev,
2175 &fxxxx_auto_pwm_attr[0][0],
2176 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2177 }
2178 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002179
Hans de Goede45fb3662007-07-13 14:34:19 +02002180 kfree(data);
2181
2182 return 0;
2183}
2184
Hans de Goede498be962009-01-07 16:37:28 +01002185static int __init f71882fg_find(int sioaddr, unsigned short *address,
2186 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002187{
Hans de Goede45fb3662007-07-13 14:34:19 +02002188 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002189 int err = superio_enter(sioaddr);
2190 if (err)
2191 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002192
2193 devid = superio_inw(sioaddr, SIO_REG_MANID);
2194 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002195 pr_debug(DRVNAME ": Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002196 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002197 goto exit;
2198 }
2199
Jean Delvare67b671b2007-12-06 23:13:42 +01002200 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002201 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002202 case SIO_F71858_ID:
2203 sio_data->type = f71858fg;
2204 break;
Hans de Goede498be962009-01-07 16:37:28 +01002205 case SIO_F71862_ID:
2206 sio_data->type = f71862fg;
2207 break;
2208 case SIO_F71882_ID:
2209 sio_data->type = f71882fg;
2210 break;
Hans de Goede76698962009-12-09 20:36:01 +01002211 case SIO_F71889_ID:
2212 sio_data->type = f71889fg;
2213 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002214 case SIO_F8000_ID:
2215 sio_data->type = f8000;
2216 break;
Hans de Goede498be962009-01-07 16:37:28 +01002217 default:
Hans de Goede76698962009-12-09 20:36:01 +01002218 printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
2219 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002220 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002221 goto exit;
2222 }
2223
Hans de Goede09475d32009-06-15 18:39:52 +02002224 if (sio_data->type == f71858fg)
2225 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2226 else
2227 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2228
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002229 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002230 printk(KERN_WARNING DRVNAME ": Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002231 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002232 goto exit;
2233 }
2234
2235 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002236 if (*address == 0) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002237 printk(KERN_WARNING DRVNAME ": Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002238 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002239 goto exit;
2240 }
2241 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2242
Hans de Goede45fb3662007-07-13 14:34:19 +02002243 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002244 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2245 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002246 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2247exit:
2248 superio_exit(sioaddr);
2249 return err;
2250}
2251
Hans de Goede498be962009-01-07 16:37:28 +01002252static int __init f71882fg_device_add(unsigned short address,
2253 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002254{
2255 struct resource res = {
2256 .start = address,
2257 .end = address + REGION_LENGTH - 1,
2258 .flags = IORESOURCE_IO,
2259 };
2260 int err;
2261
2262 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002263 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002264 return -ENOMEM;
2265
2266 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002267 err = acpi_check_resource_conflict(&res);
2268 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002269 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002270
Hans de Goede45fb3662007-07-13 14:34:19 +02002271 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002272 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002273 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2274 goto exit_device_put;
2275 }
2276
Hans de Goede498be962009-01-07 16:37:28 +01002277 err = platform_device_add_data(f71882fg_pdev, sio_data,
2278 sizeof(struct f71882fg_sio_data));
2279 if (err) {
2280 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2281 goto exit_device_put;
2282 }
2283
Hans de Goede45fb3662007-07-13 14:34:19 +02002284 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002285 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002286 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2287 goto exit_device_put;
2288 }
2289
2290 return 0;
2291
2292exit_device_put:
2293 platform_device_put(f71882fg_pdev);
2294
2295 return err;
2296}
2297
2298static int __init f71882fg_init(void)
2299{
2300 int err = -ENODEV;
2301 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002302 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002303
Hans de Goede498be962009-01-07 16:37:28 +01002304 memset(&sio_data, 0, sizeof(sio_data));
2305
2306 if (f71882fg_find(0x2e, &address, &sio_data) &&
2307 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002308 goto exit;
2309
Hans de Goedec13548c2009-01-07 16:37:27 +01002310 err = platform_driver_register(&f71882fg_driver);
2311 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002312 goto exit;
2313
Hans de Goede498be962009-01-07 16:37:28 +01002314 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002315 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002316 goto exit_driver;
2317
2318 return 0;
2319
2320exit_driver:
2321 platform_driver_unregister(&f71882fg_driver);
2322exit:
2323 return err;
2324}
2325
2326static void __exit f71882fg_exit(void)
2327{
2328 platform_device_unregister(f71882fg_pdev);
2329 platform_driver_unregister(&f71882fg_driver);
2330}
2331
2332MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002333MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002334MODULE_LICENSE("GPL");
2335
2336module_init(f71882fg_init);
2337module_exit(f71882fg_exit);