blob: 537841ef44b99d179318f7510dbf28dddedb0ed8 [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
Hans de Goede76698962009-12-09 20:36:01 +010099enum 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);
114static inline void superio_enter(int base);
115static 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
Hans de Goede66344aa2009-12-09 20:35:59 +0100309/* 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
864static inline void superio_enter(int base)
865{
866 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200867 outb(SIO_UNLOCK_KEY, base);
868 outb(SIO_UNLOCK_KEY, base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200869}
870
Giel van Schijndel162bb592010-05-27 19:58:40 +0200871static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200872{
873 outb(SIO_REG_LDSEL, base);
874 outb(ld, base + 1);
875}
876
877static inline void superio_exit(int base)
878{
879 outb(SIO_LOCK_KEY, base);
880}
881
Hans de Goede2f650632009-01-07 16:37:31 +0100882static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200883{
884 return reg ? (1500000 / reg) : 0;
885}
886
Hans de Goede2f650632009-01-07 16:37:31 +0100887static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100888{
889 return fan ? (1500000 / fan) : 0;
890}
891
Hans de Goede45fb3662007-07-13 14:34:19 +0200892static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
893{
894 u8 val;
895
896 outb(reg, data->addr + ADDR_REG_OFFSET);
897 val = inb(data->addr + DATA_REG_OFFSET);
898
899 return val;
900}
901
902static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
903{
904 u16 val;
905
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200906 val = f71882fg_read8(data, reg) << 8;
907 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200908
909 return val;
910}
911
912static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
913{
914 outb(reg, data->addr + ADDR_REG_OFFSET);
915 outb(val, data->addr + DATA_REG_OFFSET);
916}
917
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100918static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
919{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200920 f71882fg_write8(data, reg, val >> 8);
921 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100922}
923
Hans de Goede09475d32009-06-15 18:39:52 +0200924static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
925{
926 if (data->type == f71858fg)
927 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
928 else
929 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
930}
931
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100932static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200933{
934 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100935 int nr, reg = 0, reg2;
936 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200937 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200938
939 mutex_lock(&data->update_lock);
940
941 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200942 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200943 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100944 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100945 data->in1_max =
946 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
947 data->in_beep =
948 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
949 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200950
951 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200952 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200953 data->temp_ovt[nr] = f71882fg_read8(data,
954 F71882FG_REG_TEMP_OVT(nr));
955 data->temp_high[nr] = f71882fg_read8(data,
956 F71882FG_REG_TEMP_HIGH(nr));
957 }
958
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100959 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100960 data->temp_hyst[0] = f71882fg_read8(data,
961 F71882FG_REG_TEMP_HYST(0));
962 data->temp_hyst[1] = f71882fg_read8(data,
963 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200964 }
965
Hans de Goede76698962009-12-09 20:36:01 +0100966 if (data->type == f71862fg || data->type == f71882fg ||
967 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200968 data->fan_beep = f71882fg_read8(data,
969 F71882FG_REG_FAN_BEEP);
970 data->temp_beep = f71882fg_read8(data,
971 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100972 /* Have to hardcode type, because temp1 is special */
973 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
974 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
975 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
976 }
Hans de Goede76698962009-12-09 20:36:01 +0100977 /* Determine temp index 1 sensor type */
978 if (data->type == f71889fg) {
979 reg2 = f71882fg_read8(data, F71882FG_REG_START);
980 switch ((reg2 & 0x60) >> 5) {
981 case 0x00: /* BJT / Thermistor */
982 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
983 break;
984 case 0x01: /* AMDSI */
985 data->temp_type[1] = 5;
986 break;
987 case 0x02: /* PECI */
988 case 0x03: /* Ibex Peak ?? Report as PECI for now */
989 data->temp_type[1] = 6;
990 break;
991 }
992 } else {
993 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
994 if ((reg2 & 0x03) == 0x01)
995 data->temp_type[1] = 6; /* PECI */
996 else if ((reg2 & 0x03) == 0x02)
997 data->temp_type[1] = 5; /* AMDSI */
998 else if (data->type == f71862fg ||
999 data->type == f71882fg)
1000 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1001 else /* f71858fg and f8000 only support BJT */
1002 data->temp_type[1] = 2;
1003 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001004
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001005 data->pwm_enable = f71882fg_read8(data,
1006 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001007 data->pwm_auto_point_hyst[0] =
1008 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1009 data->pwm_auto_point_hyst[1] =
1010 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1011
Hans de Goede498be962009-01-07 16:37:28 +01001012 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001013 data->pwm_auto_point_mapping[nr] =
1014 f71882fg_read8(data,
1015 F71882FG_REG_POINT_MAPPING(nr));
1016
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001017 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001018 int point;
1019 for (point = 0; point < 5; point++) {
1020 data->pwm_auto_point_pwm[nr][point] =
1021 f71882fg_read8(data,
1022 F71882FG_REG_POINT_PWM
1023 (nr, point));
1024 }
1025 for (point = 0; point < 4; point++) {
1026 data->pwm_auto_point_temp[nr][point] =
1027 f71882fg_read8(data,
1028 F71882FG_REG_POINT_TEMP
1029 (nr, point));
1030 }
1031 } else {
1032 data->pwm_auto_point_pwm[nr][1] =
1033 f71882fg_read8(data,
1034 F71882FG_REG_POINT_PWM
1035 (nr, 1));
1036 data->pwm_auto_point_pwm[nr][4] =
1037 f71882fg_read8(data,
1038 F71882FG_REG_POINT_PWM
1039 (nr, 4));
1040 data->pwm_auto_point_temp[nr][0] =
1041 f71882fg_read8(data,
1042 F71882FG_REG_POINT_TEMP
1043 (nr, 0));
1044 data->pwm_auto_point_temp[nr][3] =
1045 f71882fg_read8(data,
1046 F71882FG_REG_POINT_TEMP
1047 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001048 }
1049 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001050 data->last_limits = jiffies;
1051 }
1052
1053 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001054 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001055 data->temp_status = f71882fg_read8(data,
1056 F71882FG_REG_TEMP_STATUS);
1057 data->temp_diode_open = f71882fg_read8(data,
1058 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001059 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1060 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001061
1062 data->fan_status = f71882fg_read8(data,
1063 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001064 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001065 data->fan[nr] = f71882fg_read16(data,
1066 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001067 data->fan_target[nr] =
1068 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1069 data->fan_full_speed[nr] =
1070 f71882fg_read16(data,
1071 F71882FG_REG_FAN_FULL_SPEED(nr));
1072 data->pwm[nr] =
1073 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1074 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001075
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001076 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1077 if (data->type == f8000)
1078 data->fan[3] = f71882fg_read16(data,
1079 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001080 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001081 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001082 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001083 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001084 data->in[nr] = f71882fg_read8(data,
1085 F71882FG_REG_IN(nr));
1086
1087 data->last_updated = jiffies;
1088 data->valid = 1;
1089 }
1090
1091 mutex_unlock(&data->update_lock);
1092
1093 return data;
1094}
1095
1096/* Sysfs Interface */
1097static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1098 char *buf)
1099{
1100 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001101 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001102 int speed = fan_from_reg(data->fan[nr]);
1103
1104 if (speed == FAN_MIN_DETECT)
1105 speed = 0;
1106
1107 return sprintf(buf, "%d\n", speed);
1108}
1109
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001110static ssize_t show_fan_full_speed(struct device *dev,
1111 struct device_attribute *devattr, char *buf)
1112{
1113 struct f71882fg_data *data = f71882fg_update_device(dev);
1114 int nr = to_sensor_dev_attr_2(devattr)->index;
1115 int speed = fan_from_reg(data->fan_full_speed[nr]);
1116 return sprintf(buf, "%d\n", speed);
1117}
1118
1119static ssize_t store_fan_full_speed(struct device *dev,
1120 struct device_attribute *devattr,
1121 const char *buf, size_t count)
1122{
1123 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001124 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1125 long val;
1126
1127 err = strict_strtol(buf, 10, &val);
1128 if (err)
1129 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001130
1131 val = SENSORS_LIMIT(val, 23, 1500000);
1132 val = fan_to_reg(val);
1133
1134 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001135 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1136 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001137 mutex_unlock(&data->update_lock);
1138
1139 return count;
1140}
1141
Hans de Goede45fb3662007-07-13 14:34:19 +02001142static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1143 *devattr, char *buf)
1144{
1145 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001146 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001147
1148 if (data->fan_beep & (1 << nr))
1149 return sprintf(buf, "1\n");
1150 else
1151 return sprintf(buf, "0\n");
1152}
1153
1154static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1155 *devattr, const char *buf, size_t count)
1156{
1157 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001158 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1159 unsigned long val;
1160
1161 err = strict_strtoul(buf, 10, &val);
1162 if (err)
1163 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001164
1165 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001166 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001167 if (val)
1168 data->fan_beep |= 1 << nr;
1169 else
1170 data->fan_beep &= ~(1 << nr);
1171
1172 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1173 mutex_unlock(&data->update_lock);
1174
1175 return count;
1176}
1177
1178static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1179 *devattr, char *buf)
1180{
1181 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001182 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001183
1184 if (data->fan_status & (1 << nr))
1185 return sprintf(buf, "1\n");
1186 else
1187 return sprintf(buf, "0\n");
1188}
1189
1190static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1191 char *buf)
1192{
1193 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001194 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001195
1196 return sprintf(buf, "%d\n", data->in[nr] * 8);
1197}
1198
1199static ssize_t show_in_max(struct device *dev, struct device_attribute
1200 *devattr, char *buf)
1201{
1202 struct f71882fg_data *data = f71882fg_update_device(dev);
1203
1204 return sprintf(buf, "%d\n", data->in1_max * 8);
1205}
1206
1207static ssize_t store_in_max(struct device *dev, struct device_attribute
1208 *devattr, const char *buf, size_t count)
1209{
1210 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001211 int err;
1212 long val;
1213
1214 err = strict_strtol(buf, 10, &val);
1215 if (err)
1216 return err;
1217
1218 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001219 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001220
1221 mutex_lock(&data->update_lock);
1222 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1223 data->in1_max = val;
1224 mutex_unlock(&data->update_lock);
1225
1226 return count;
1227}
1228
1229static ssize_t show_in_beep(struct device *dev, struct device_attribute
1230 *devattr, char *buf)
1231{
1232 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001233 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001234
1235 if (data->in_beep & (1 << nr))
1236 return sprintf(buf, "1\n");
1237 else
1238 return sprintf(buf, "0\n");
1239}
1240
1241static ssize_t store_in_beep(struct device *dev, struct device_attribute
1242 *devattr, const char *buf, size_t count)
1243{
1244 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001245 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1246 unsigned long val;
1247
1248 err = strict_strtoul(buf, 10, &val);
1249 if (err)
1250 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001251
1252 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001253 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001254 if (val)
1255 data->in_beep |= 1 << nr;
1256 else
1257 data->in_beep &= ~(1 << nr);
1258
1259 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1260 mutex_unlock(&data->update_lock);
1261
1262 return count;
1263}
1264
1265static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1266 *devattr, char *buf)
1267{
1268 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001269 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001270
1271 if (data->in_status & (1 << nr))
1272 return sprintf(buf, "1\n");
1273 else
1274 return sprintf(buf, "0\n");
1275}
1276
1277static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1278 char *buf)
1279{
1280 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001281 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001282 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001283
Hans de Goede09475d32009-06-15 18:39:52 +02001284 if (data->type == f71858fg) {
1285 /* TEMP_TABLE_SEL 1 or 3 ? */
1286 if (data->temp_config & 1) {
1287 sign = data->temp[nr] & 0x0001;
1288 temp = (data->temp[nr] >> 5) & 0x7ff;
1289 } else {
1290 sign = data->temp[nr] & 0x8000;
1291 temp = (data->temp[nr] >> 5) & 0x3ff;
1292 }
1293 temp *= 125;
1294 if (sign)
1295 temp -= 128000;
1296 } else
1297 temp = data->temp[nr] * 1000;
1298
1299 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001300}
1301
1302static ssize_t show_temp_max(struct device *dev, struct device_attribute
1303 *devattr, char *buf)
1304{
1305 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001306 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001307
1308 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1309}
1310
1311static ssize_t store_temp_max(struct device *dev, struct device_attribute
1312 *devattr, const char *buf, size_t count)
1313{
1314 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001315 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1316 long val;
1317
1318 err = strict_strtol(buf, 10, &val);
1319 if (err)
1320 return err;
1321
1322 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001323 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001324
1325 mutex_lock(&data->update_lock);
1326 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1327 data->temp_high[nr] = val;
1328 mutex_unlock(&data->update_lock);
1329
1330 return count;
1331}
1332
1333static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1334 *devattr, char *buf)
1335{
1336 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001337 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001338 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001339
Hans de Goedece0bfa52009-01-07 16:37:28 +01001340 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001341 if (nr & 1)
1342 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1343 else
1344 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1345 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001346 mutex_unlock(&data->update_lock);
1347
1348 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001349}
1350
1351static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1352 *devattr, const char *buf, size_t count)
1353{
1354 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001355 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001356 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001357 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001358 long val;
1359
1360 err = strict_strtol(buf, 10, &val);
1361 if (err)
1362 return err;
1363
1364 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001365
1366 mutex_lock(&data->update_lock);
1367
1368 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001369 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1370 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1371 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001372 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001373
1374 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001375 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1376 if (nr & 1)
1377 reg = (reg & 0x0f) | (val << 4);
1378 else
1379 reg = (reg & 0xf0) | val;
1380 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1381 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001382
Hans de Goede45fb3662007-07-13 14:34:19 +02001383 mutex_unlock(&data->update_lock);
1384 return ret;
1385}
1386
1387static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1388 *devattr, char *buf)
1389{
1390 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001391 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001392
1393 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1394}
1395
1396static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1397 *devattr, const char *buf, size_t count)
1398{
1399 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001400 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1401 long val;
1402
1403 err = strict_strtol(buf, 10, &val);
1404 if (err)
1405 return err;
1406
1407 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001408 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001409
1410 mutex_lock(&data->update_lock);
1411 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1412 data->temp_ovt[nr] = val;
1413 mutex_unlock(&data->update_lock);
1414
1415 return count;
1416}
1417
1418static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1419 *devattr, char *buf)
1420{
1421 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001422 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001423 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001424
Hans de Goedece0bfa52009-01-07 16:37:28 +01001425 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001426 if (nr & 1)
1427 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1428 else
1429 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1430 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001431 mutex_unlock(&data->update_lock);
1432
1433 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001434}
1435
1436static ssize_t show_temp_type(struct device *dev, struct device_attribute
1437 *devattr, char *buf)
1438{
1439 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001440 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001441
1442 return sprintf(buf, "%d\n", data->temp_type[nr]);
1443}
1444
1445static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1446 *devattr, char *buf)
1447{
1448 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001449 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001450
Hans de Goede7567a042009-01-07 16:37:28 +01001451 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001452 return sprintf(buf, "1\n");
1453 else
1454 return sprintf(buf, "0\n");
1455}
1456
1457static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1458 *devattr, const char *buf, size_t count)
1459{
1460 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001461 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1462 unsigned long val;
1463
1464 err = strict_strtoul(buf, 10, &val);
1465 if (err)
1466 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001467
1468 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001469 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001470 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001471 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001472 else
Hans de Goede7567a042009-01-07 16:37:28 +01001473 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001474
1475 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1476 mutex_unlock(&data->update_lock);
1477
1478 return count;
1479}
1480
1481static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1482 *devattr, char *buf)
1483{
1484 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001485 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001486
Hans de Goede7567a042009-01-07 16:37:28 +01001487 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001488 return sprintf(buf, "1\n");
1489 else
1490 return sprintf(buf, "0\n");
1491}
1492
1493static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1494 *devattr, char *buf)
1495{
1496 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001497 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001498
Hans de Goede7567a042009-01-07 16:37:28 +01001499 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001500 return sprintf(buf, "1\n");
1501 else
1502 return sprintf(buf, "0\n");
1503}
1504
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001505static ssize_t show_pwm(struct device *dev,
1506 struct device_attribute *devattr, char *buf)
1507{
1508 struct f71882fg_data *data = f71882fg_update_device(dev);
1509 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001510 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001511 if (data->pwm_enable & (1 << (2 * nr)))
1512 /* PWM mode */
1513 val = data->pwm[nr];
1514 else {
1515 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001516 val = 255 * fan_from_reg(data->fan_target[nr])
1517 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001518 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001519 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001520 return sprintf(buf, "%d\n", val);
1521}
1522
1523static ssize_t store_pwm(struct device *dev,
1524 struct device_attribute *devattr, const char *buf,
1525 size_t count)
1526{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001527 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001528 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1529 long val;
1530
1531 err = strict_strtol(buf, 10, &val);
1532 if (err)
1533 return err;
1534
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001535 val = SENSORS_LIMIT(val, 0, 255);
1536
1537 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001538 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001539 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1540 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1541 count = -EROFS;
1542 goto leave;
1543 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001544 if (data->pwm_enable & (1 << (2 * nr))) {
1545 /* PWM mode */
1546 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1547 data->pwm[nr] = val;
1548 } else {
1549 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001550 int target, full_speed;
1551 full_speed = f71882fg_read16(data,
1552 F71882FG_REG_FAN_FULL_SPEED(nr));
1553 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1554 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1555 data->fan_target[nr] = target;
1556 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001557 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001558leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001559 mutex_unlock(&data->update_lock);
1560
1561 return count;
1562}
1563
1564static ssize_t show_pwm_enable(struct device *dev,
1565 struct device_attribute *devattr, char *buf)
1566{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001567 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001568 struct f71882fg_data *data = f71882fg_update_device(dev);
1569 int nr = to_sensor_dev_attr_2(devattr)->index;
1570
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001571 switch ((data->pwm_enable >> 2 * nr) & 3) {
1572 case 0:
1573 case 1:
1574 result = 2; /* Normal auto mode */
1575 break;
1576 case 2:
1577 result = 1; /* Manual mode */
1578 break;
1579 case 3:
1580 if (data->type == f8000)
1581 result = 3; /* Thermostat mode */
1582 else
1583 result = 1; /* Manual mode */
1584 break;
1585 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001586
1587 return sprintf(buf, "%d\n", result);
1588}
1589
1590static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1591 *devattr, const char *buf, size_t count)
1592{
1593 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001594 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1595 long val;
1596
1597 err = strict_strtol(buf, 10, &val);
1598 if (err)
1599 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001600
Hans de Goede3fc78382009-06-15 18:39:50 +02001601 /* Special case for F8000 pwm channel 3 which only does auto mode */
1602 if (data->type == f8000 && nr == 2 && val != 2)
1603 return -EINVAL;
1604
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001605 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001606 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001607 /* Special case for F8000 auto PWM mode / Thermostat mode */
1608 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1609 switch (val) {
1610 case 2:
1611 data->pwm_enable &= ~(2 << (2 * nr));
1612 break; /* Normal auto mode */
1613 case 3:
1614 data->pwm_enable |= 2 << (2 * nr);
1615 break; /* Thermostat mode */
1616 default:
1617 count = -EINVAL;
1618 goto leave;
1619 }
1620 } else {
1621 switch (val) {
1622 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001623 /* The f71858fg does not support manual RPM mode */
1624 if (data->type == f71858fg &&
1625 ((data->pwm_enable >> (2 * nr)) & 1)) {
1626 count = -EINVAL;
1627 goto leave;
1628 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001629 data->pwm_enable |= 2 << (2 * nr);
1630 break; /* Manual */
1631 case 2:
1632 data->pwm_enable &= ~(2 << (2 * nr));
1633 break; /* Normal auto mode */
1634 default:
1635 count = -EINVAL;
1636 goto leave;
1637 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001638 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001639 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001640leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001641 mutex_unlock(&data->update_lock);
1642
1643 return count;
1644}
1645
1646static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1647 struct device_attribute *devattr,
1648 char *buf)
1649{
1650 int result;
1651 struct f71882fg_data *data = f71882fg_update_device(dev);
1652 int pwm = to_sensor_dev_attr_2(devattr)->index;
1653 int point = to_sensor_dev_attr_2(devattr)->nr;
1654
Hans de Goedece0bfa52009-01-07 16:37:28 +01001655 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001656 if (data->pwm_enable & (1 << (2 * pwm))) {
1657 /* PWM mode */
1658 result = data->pwm_auto_point_pwm[pwm][point];
1659 } else {
1660 /* RPM mode */
1661 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1662 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001663 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001664
1665 return sprintf(buf, "%d\n", result);
1666}
1667
1668static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1669 struct device_attribute *devattr,
1670 const char *buf, size_t count)
1671{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001672 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001673 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001674 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001675 long val;
1676
1677 err = strict_strtol(buf, 10, &val);
1678 if (err)
1679 return err;
1680
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001681 val = SENSORS_LIMIT(val, 0, 255);
1682
1683 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001684 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001685 if (data->pwm_enable & (1 << (2 * pwm))) {
1686 /* PWM mode */
1687 } else {
1688 /* RPM mode */
1689 if (val < 29) /* Prevent negative numbers */
1690 val = 255;
1691 else
1692 val = (255 - val) * 32 / val;
1693 }
1694 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1695 data->pwm_auto_point_pwm[pwm][point] = val;
1696 mutex_unlock(&data->update_lock);
1697
1698 return count;
1699}
1700
1701static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1702 struct device_attribute *devattr,
1703 char *buf)
1704{
1705 int result = 0;
1706 struct f71882fg_data *data = f71882fg_update_device(dev);
1707 int nr = to_sensor_dev_attr_2(devattr)->index;
1708 int point = to_sensor_dev_attr_2(devattr)->nr;
1709
1710 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001711 if (nr & 1)
1712 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1713 else
1714 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001715 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1716 mutex_unlock(&data->update_lock);
1717
1718 return sprintf(buf, "%d\n", result);
1719}
1720
1721static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1722 struct device_attribute *devattr,
1723 const char *buf, size_t count)
1724{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001725 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001726 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001727 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001728 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001729 long val;
1730
1731 err = strict_strtol(buf, 10, &val);
1732 if (err)
1733 return err;
1734
1735 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001736
1737 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001738 data->pwm_auto_point_temp[nr][point] =
1739 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001740 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1741 data->pwm_auto_point_temp[nr][point]);
1742 val = data->pwm_auto_point_temp[nr][point] - val;
1743
Hans de Goedebc274902009-01-07 16:37:29 +01001744 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1745 if (nr & 1)
1746 reg = (reg & 0x0f) | (val << 4);
1747 else
1748 reg = (reg & 0xf0) | val;
1749
1750 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1751 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001752 mutex_unlock(&data->update_lock);
1753
1754 return count;
1755}
1756
1757static ssize_t show_pwm_interpolate(struct device *dev,
1758 struct device_attribute *devattr, char *buf)
1759{
1760 int result;
1761 struct f71882fg_data *data = f71882fg_update_device(dev);
1762 int nr = to_sensor_dev_attr_2(devattr)->index;
1763
1764 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1765
1766 return sprintf(buf, "%d\n", result);
1767}
1768
1769static ssize_t store_pwm_interpolate(struct device *dev,
1770 struct device_attribute *devattr,
1771 const char *buf, size_t count)
1772{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001773 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001774 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1775 unsigned long val;
1776
1777 err = strict_strtoul(buf, 10, &val);
1778 if (err)
1779 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001780
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001781 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001782 data->pwm_auto_point_mapping[nr] =
1783 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001784 if (val)
1785 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1786 else
1787 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1788 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1789 data->pwm_auto_point_mapping[nr] = val;
1790 mutex_unlock(&data->update_lock);
1791
1792 return count;
1793}
1794
1795static ssize_t show_pwm_auto_point_channel(struct device *dev,
1796 struct device_attribute *devattr,
1797 char *buf)
1798{
1799 int result;
1800 struct f71882fg_data *data = f71882fg_update_device(dev);
1801 int nr = to_sensor_dev_attr_2(devattr)->index;
1802
Hans de Goede09475d32009-06-15 18:39:52 +02001803 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1804 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001805
1806 return sprintf(buf, "%d\n", result);
1807}
1808
1809static ssize_t store_pwm_auto_point_channel(struct device *dev,
1810 struct device_attribute *devattr,
1811 const char *buf, size_t count)
1812{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001813 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001814 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1815 long val;
1816
1817 err = strict_strtol(buf, 10, &val);
1818 if (err)
1819 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001820
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001821 switch (val) {
1822 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001823 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001824 break;
1825 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001826 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001827 break;
1828 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001829 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001830 break;
1831 default:
1832 return -EINVAL;
1833 }
Hans de Goede09475d32009-06-15 18:39:52 +02001834 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001835 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001836 data->pwm_auto_point_mapping[nr] =
1837 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001838 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1839 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1840 data->pwm_auto_point_mapping[nr] = val;
1841 mutex_unlock(&data->update_lock);
1842
1843 return count;
1844}
1845
1846static ssize_t show_pwm_auto_point_temp(struct device *dev,
1847 struct device_attribute *devattr,
1848 char *buf)
1849{
1850 int result;
1851 struct f71882fg_data *data = f71882fg_update_device(dev);
1852 int pwm = to_sensor_dev_attr_2(devattr)->index;
1853 int point = to_sensor_dev_attr_2(devattr)->nr;
1854
1855 result = data->pwm_auto_point_temp[pwm][point];
1856 return sprintf(buf, "%d\n", 1000 * result);
1857}
1858
1859static ssize_t store_pwm_auto_point_temp(struct device *dev,
1860 struct device_attribute *devattr,
1861 const char *buf, size_t count)
1862{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001863 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001864 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001865 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001866 long val;
1867
1868 err = strict_strtol(buf, 10, &val);
1869 if (err)
1870 return err;
1871
1872 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001873
1874 if (data->type == f71889fg)
1875 val = SENSORS_LIMIT(val, -128, 127);
1876 else
1877 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001878
1879 mutex_lock(&data->update_lock);
1880 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1881 data->pwm_auto_point_temp[pwm][point] = val;
1882 mutex_unlock(&data->update_lock);
1883
1884 return count;
1885}
1886
Hans de Goede45fb3662007-07-13 14:34:19 +02001887static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1888 char *buf)
1889{
Hans de Goede498be962009-01-07 16:37:28 +01001890 struct f71882fg_data *data = dev_get_drvdata(dev);
1891 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001892}
1893
Hans de Goedec13548c2009-01-07 16:37:27 +01001894static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1895 struct sensor_device_attribute_2 *attr, int count)
1896{
1897 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001898
Hans de Goedec13548c2009-01-07 16:37:27 +01001899 for (i = 0; i < count; i++) {
1900 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1901 if (err)
1902 return err;
1903 }
1904 return 0;
1905}
1906
Hans de Goedefc16c562009-12-09 20:36:01 +01001907static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1908 struct sensor_device_attribute_2 *attr, int count)
1909{
1910 int i;
1911
1912 for (i = 0; i < count; i++)
1913 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1914}
1915
Hans de Goedec13548c2009-01-07 16:37:27 +01001916static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001917{
1918 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001919 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001920 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001921 u8 start_reg;
1922
Hans de Goedec13548c2009-01-07 16:37:27 +01001923 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1924 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001925 return -ENOMEM;
1926
1927 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001928 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001929 data->temp_start =
1930 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001931 mutex_init(&data->update_lock);
1932 platform_set_drvdata(pdev, data);
1933
Hans de Goede3cc74752009-01-07 16:37:28 +01001934 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001935 if (start_reg & 0x04) {
1936 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1937 err = -ENODEV;
1938 goto exit_free;
1939 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001940 if (!(start_reg & 0x03)) {
1941 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1942 err = -ENODEV;
1943 goto exit_free;
1944 }
1945
Hans de Goede45fb3662007-07-13 14:34:19 +02001946 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001947 err = device_create_file(&pdev->dev, &dev_attr_name);
1948 if (err)
1949 goto exit_unregister_sysfs;
1950
Hans de Goedec13548c2009-01-07 16:37:27 +01001951 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001952 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001953 case f71858fg:
1954 data->temp_config =
1955 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1956 if (data->temp_config & 0x10)
1957 /* The f71858fg temperature alarms behave as
1958 the f8000 alarms in this mode */
1959 err = f71882fg_create_sysfs_files(pdev,
1960 f8000_in_temp_attr,
1961 ARRAY_SIZE(f8000_in_temp_attr));
1962 else
1963 err = f71882fg_create_sysfs_files(pdev,
1964 f71858fg_in_temp_attr,
1965 ARRAY_SIZE(f71858fg_in_temp_attr));
1966 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001967 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001968 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001969 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001970 fxxxx_in1_alarm_attr,
1971 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001972 if (err)
1973 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001974 /* fall through! */
1975 case f71862fg:
1976 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001977 fxxxx_in_temp_attr,
1978 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001979 break;
1980 case f8000:
1981 err = f71882fg_create_sysfs_files(pdev,
1982 f8000_in_temp_attr,
1983 ARRAY_SIZE(f8000_in_temp_attr));
1984 break;
Hans de Goede498be962009-01-07 16:37:28 +01001985 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001986 if (err)
1987 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001988 }
1989
Hans de Goede45fb3662007-07-13 14:34:19 +02001990 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001991 data->pwm_enable =
1992 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1993
1994 /* Sanity check the pwm settings */
1995 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001996 case f71858fg:
1997 err = 0;
1998 for (i = 0; i < nr_fans; i++)
1999 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2000 err = 1;
2001 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002002 case f71862fg:
2003 err = (data->pwm_enable & 0x15) != 0x15;
2004 break;
2005 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002006 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002007 err = 0;
2008 break;
2009 case f8000:
2010 err = data->pwm_enable & 0x20;
2011 break;
2012 }
2013 if (err) {
2014 dev_err(&pdev->dev,
2015 "Invalid (reserved) pwm settings: 0x%02x\n",
2016 (unsigned int)data->pwm_enable);
2017 err = -ENODEV;
2018 goto exit_unregister_sysfs;
2019 }
2020
Hans de Goedeb69b0392009-12-09 20:36:00 +01002021 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2022 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002023 if (err)
2024 goto exit_unregister_sysfs;
2025
Hans de Goede76698962009-12-09 20:36:01 +01002026 if (data->type == f71862fg || data->type == f71882fg ||
2027 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002028 err = f71882fg_create_sysfs_files(pdev,
2029 fxxxx_fan_beep_attr, nr_fans);
2030 if (err)
2031 goto exit_unregister_sysfs;
2032 }
2033
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002034 switch (data->type) {
2035 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002036 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002037 f71862fg_auto_pwm_attr,
2038 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002039 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002040 case f8000:
2041 err = f71882fg_create_sysfs_files(pdev,
2042 f8000_fan_attr,
2043 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002044 if (err)
2045 goto exit_unregister_sysfs;
2046 err = f71882fg_create_sysfs_files(pdev,
2047 f8000_auto_pwm_attr,
2048 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002049 break;
Hans de Goede76698962009-12-09 20:36:01 +01002050 case f71889fg:
2051 for (i = 0; i < nr_fans; i++) {
2052 data->pwm_auto_point_mapping[i] =
2053 f71882fg_read8(data,
2054 F71882FG_REG_POINT_MAPPING(i));
2055 if (data->pwm_auto_point_mapping[i] & 0x80)
2056 break;
2057 }
2058 if (i != nr_fans) {
2059 dev_warn(&pdev->dev,
2060 "Auto pwm controlled by raw digital "
2061 "data, disabling pwm auto_point "
2062 "sysfs attributes\n");
2063 break;
2064 }
2065 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002066 default: /* f71858fg / f71882fg */
2067 err = f71882fg_create_sysfs_files(pdev,
2068 &fxxxx_auto_pwm_attr[0][0],
2069 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002070 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002071 if (err)
2072 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002073
2074 for (i = 0; i < nr_fans; i++)
2075 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2076 (data->pwm_enable & (1 << 2 * i)) ?
2077 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002078 }
2079
Tony Jones1beeffe2007-08-20 13:46:20 -07002080 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2081 if (IS_ERR(data->hwmon_dev)) {
2082 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002083 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002084 goto exit_unregister_sysfs;
2085 }
2086
2087 return 0;
2088
2089exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002090 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002091 return err; /* f71882fg_remove() also frees our data */
2092exit_free:
2093 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002094 return err;
2095}
2096
Hans de Goedec13548c2009-01-07 16:37:27 +01002097static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002098{
Hans de Goede45fb3662007-07-13 14:34:19 +02002099 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002100 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2101 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002102
2103 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002104 if (data->hwmon_dev)
2105 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002106
Hans de Goedec13548c2009-01-07 16:37:27 +01002107 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002108
Hans de Goedefc16c562009-12-09 20:36:01 +01002109 if (start_reg & 0x01) {
2110 switch (data->type) {
2111 case f71858fg:
2112 if (data->temp_config & 0x10)
2113 f71882fg_remove_sysfs_files(pdev,
2114 f8000_in_temp_attr,
2115 ARRAY_SIZE(f8000_in_temp_attr));
2116 else
2117 f71882fg_remove_sysfs_files(pdev,
2118 f71858fg_in_temp_attr,
2119 ARRAY_SIZE(f71858fg_in_temp_attr));
2120 break;
2121 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002122 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002123 f71882fg_remove_sysfs_files(pdev,
2124 fxxxx_in1_alarm_attr,
2125 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2126 /* fall through! */
2127 case f71862fg:
2128 f71882fg_remove_sysfs_files(pdev,
2129 fxxxx_in_temp_attr,
2130 ARRAY_SIZE(fxxxx_in_temp_attr));
2131 break;
2132 case f8000:
2133 f71882fg_remove_sysfs_files(pdev,
2134 f8000_in_temp_attr,
2135 ARRAY_SIZE(f8000_in_temp_attr));
2136 break;
2137 }
2138 }
Hans de Goede498be962009-01-07 16:37:28 +01002139
Hans de Goedefc16c562009-12-09 20:36:01 +01002140 if (start_reg & 0x02) {
2141 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2142 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002143
Hans de Goede76698962009-12-09 20:36:01 +01002144 if (data->type == f71862fg || data->type == f71882fg ||
2145 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002146 f71882fg_remove_sysfs_files(pdev,
2147 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002148
Hans de Goedefc16c562009-12-09 20:36:01 +01002149 switch (data->type) {
2150 case f71862fg:
2151 f71882fg_remove_sysfs_files(pdev,
2152 f71862fg_auto_pwm_attr,
2153 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2154 break;
2155 case f8000:
2156 f71882fg_remove_sysfs_files(pdev,
2157 f8000_fan_attr,
2158 ARRAY_SIZE(f8000_fan_attr));
2159 f71882fg_remove_sysfs_files(pdev,
2160 f8000_auto_pwm_attr,
2161 ARRAY_SIZE(f8000_auto_pwm_attr));
2162 break;
2163 default: /* f71858fg / f71882fg / f71889fg */
2164 f71882fg_remove_sysfs_files(pdev,
2165 &fxxxx_auto_pwm_attr[0][0],
2166 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2167 }
2168 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002169
Hans de Goede45fb3662007-07-13 14:34:19 +02002170 kfree(data);
2171
2172 return 0;
2173}
2174
Hans de Goede498be962009-01-07 16:37:28 +01002175static int __init f71882fg_find(int sioaddr, unsigned short *address,
2176 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002177{
2178 int err = -ENODEV;
2179 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002180
Giel van Schijndel729d2732010-05-27 19:58:43 +02002181 /* Don't step on other drivers' I/O space by accident */
2182 if (!request_region(sioaddr, 2, DRVNAME)) {
2183 printk(KERN_ERR DRVNAME ": I/O address 0x%04x already in use\n",
2184 (int)sioaddr);
2185 return -EBUSY;
2186 }
2187
Hans de Goede45fb3662007-07-13 14:34:19 +02002188 superio_enter(sioaddr);
2189
2190 devid = superio_inw(sioaddr, SIO_REG_MANID);
2191 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002192 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002193 goto exit;
2194 }
2195
Jean Delvare67b671b2007-12-06 23:13:42 +01002196 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002197 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002198 case SIO_F71858_ID:
2199 sio_data->type = f71858fg;
2200 break;
Hans de Goede498be962009-01-07 16:37:28 +01002201 case SIO_F71862_ID:
2202 sio_data->type = f71862fg;
2203 break;
2204 case SIO_F71882_ID:
2205 sio_data->type = f71882fg;
2206 break;
Hans de Goede76698962009-12-09 20:36:01 +01002207 case SIO_F71889_ID:
2208 sio_data->type = f71889fg;
2209 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002210 case SIO_F8000_ID:
2211 sio_data->type = f8000;
2212 break;
Hans de Goede498be962009-01-07 16:37:28 +01002213 default:
Hans de Goede76698962009-12-09 20:36:01 +01002214 printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
2215 (unsigned int)devid);
Hans de Goede45fb3662007-07-13 14:34:19 +02002216 goto exit;
2217 }
2218
Hans de Goede09475d32009-06-15 18:39:52 +02002219 if (sio_data->type == f71858fg)
2220 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2221 else
2222 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2223
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002224 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002225 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2226 goto exit;
2227 }
2228
2229 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002230 if (*address == 0) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002231 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2232 goto exit;
2233 }
2234 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2235
Hans de Goede45fb3662007-07-13 14:34:19 +02002236 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002237 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2238 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002239 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2240exit:
2241 superio_exit(sioaddr);
Giel van Schijndel729d2732010-05-27 19:58:43 +02002242 release_region(sioaddr, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02002243 return err;
2244}
2245
Hans de Goede498be962009-01-07 16:37:28 +01002246static int __init f71882fg_device_add(unsigned short address,
2247 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002248{
2249 struct resource res = {
2250 .start = address,
2251 .end = address + REGION_LENGTH - 1,
2252 .flags = IORESOURCE_IO,
2253 };
2254 int err;
2255
2256 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002257 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002258 return -ENOMEM;
2259
2260 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002261 err = acpi_check_resource_conflict(&res);
2262 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002263 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002264
Hans de Goede45fb3662007-07-13 14:34:19 +02002265 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002266 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002267 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2268 goto exit_device_put;
2269 }
2270
Hans de Goede498be962009-01-07 16:37:28 +01002271 err = platform_device_add_data(f71882fg_pdev, sio_data,
2272 sizeof(struct f71882fg_sio_data));
2273 if (err) {
2274 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2275 goto exit_device_put;
2276 }
2277
Hans de Goede45fb3662007-07-13 14:34:19 +02002278 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002279 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002280 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2281 goto exit_device_put;
2282 }
2283
2284 return 0;
2285
2286exit_device_put:
2287 platform_device_put(f71882fg_pdev);
2288
2289 return err;
2290}
2291
2292static int __init f71882fg_init(void)
2293{
2294 int err = -ENODEV;
2295 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002296 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002297
Hans de Goede498be962009-01-07 16:37:28 +01002298 memset(&sio_data, 0, sizeof(sio_data));
2299
2300 if (f71882fg_find(0x2e, &address, &sio_data) &&
2301 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002302 goto exit;
2303
Hans de Goedec13548c2009-01-07 16:37:27 +01002304 err = platform_driver_register(&f71882fg_driver);
2305 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002306 goto exit;
2307
Hans de Goede498be962009-01-07 16:37:28 +01002308 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002309 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002310 goto exit_driver;
2311
2312 return 0;
2313
2314exit_driver:
2315 platform_driver_unregister(&f71882fg_driver);
2316exit:
2317 return err;
2318}
2319
2320static void __exit f71882fg_exit(void)
2321{
2322 platform_device_unregister(f71882fg_pdev);
2323 platform_driver_unregister(&f71882fg_driver);
2324}
2325
2326MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002327MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002328MODULE_LICENSE("GPL");
2329
2330module_init(f71882fg_init);
2331module_exit(f71882fg_exit);