blob: 6c3de065e04ba8abc33947c59f6d5270b9151bda [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 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
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010053#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010054#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020055
56#define REGION_LENGTH 8
57#define ADDR_REG_OFFSET 5
58#define DATA_REG_OFFSET 6
59
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
61#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010063#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010066#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
67#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_FAN_STATUS 0x92
69#define F71882FG_REG_FAN_BEEP 0x93
70
Hans de Goede7567a042009-01-07 16:37:28 +010071#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
72#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
73#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_STATUS 0x62
75#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020076#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010077#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020078#define F71882FG_REG_TEMP_TYPE 0x6B
79#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
80
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
82#define F71882FG_REG_PWM_TYPE 0x94
83#define F71882FG_REG_PWM_ENABLE 0x96
84
Hans de Goedebc274902009-01-07 16:37:29 +010085#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010086
87#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
88#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
89#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
90
Hans de Goede45fb3662007-07-13 14:34:19 +020091#define F71882FG_REG_START 0x01
92
93#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
94
Jean Delvare67b671b2007-12-06 23:13:42 +010095static unsigned short force_id;
96module_param(force_id, ushort, 0);
97MODULE_PARM_DESC(force_id, "Override the detected device ID");
98
Andrew Mortonf2e41e92010-08-19 14:13:31 -070099enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100100
101static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200102 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100103 "f71862fg",
104 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100105 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100106 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100107};
108
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100109static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200110
111/* Super-I/O Function prototypes */
112static inline int superio_inb(int base, int reg);
113static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400114static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200115static inline void superio_select(int base, int ld);
116static inline void superio_exit(int base);
117
Hans de Goede498be962009-01-07 16:37:28 +0100118struct f71882fg_sio_data {
119 enum chips type;
120};
121
Hans de Goede45fb3662007-07-13 14:34:19 +0200122struct f71882fg_data {
123 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100124 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700125 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200126
127 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200128 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200129 char valid; /* !=0 if following fields are valid */
130 unsigned long last_updated; /* In jiffies */
131 unsigned long last_limits; /* In jiffies */
132
133 /* Register Values */
134 u8 in[9];
135 u8 in1_max;
136 u8 in_status;
137 u8 in_beep;
138 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100139 u16 fan_target[4];
140 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200141 u8 fan_status;
142 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100143 /* Note: all models have only 3 temperature channels, but on some
144 they are addressed as 0-2 and on others as 1-3, so for coding
145 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200146 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100147 u8 temp_ovt[4];
148 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100149 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100150 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200151 u8 temp_status;
152 u8 temp_beep;
153 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200154 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100155 u8 pwm[4];
156 u8 pwm_enable;
157 u8 pwm_auto_point_hyst[2];
158 u8 pwm_auto_point_mapping[4];
159 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100160 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200161};
162
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100163/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200164static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
165 char *buf);
166static ssize_t show_in_max(struct device *dev, struct device_attribute
167 *devattr, char *buf);
168static ssize_t store_in_max(struct device *dev, struct device_attribute
169 *devattr, const char *buf, size_t count);
170static ssize_t show_in_beep(struct device *dev, struct device_attribute
171 *devattr, char *buf);
172static ssize_t store_in_beep(struct device *dev, struct device_attribute
173 *devattr, const char *buf, size_t count);
174static ssize_t show_in_alarm(struct device *dev, struct device_attribute
175 *devattr, char *buf);
176/* Sysfs Fan */
177static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
178 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100179static ssize_t show_fan_full_speed(struct device *dev,
180 struct device_attribute *devattr, char *buf);
181static ssize_t store_fan_full_speed(struct device *dev,
182 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200183static ssize_t show_fan_beep(struct device *dev, struct device_attribute
184 *devattr, char *buf);
185static ssize_t store_fan_beep(struct device *dev, struct device_attribute
186 *devattr, const char *buf, size_t count);
187static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189/* Sysfs Temp */
190static ssize_t show_temp(struct device *dev, struct device_attribute
191 *devattr, char *buf);
192static ssize_t show_temp_max(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t store_temp_max(struct device *dev, struct device_attribute
195 *devattr, const char *buf, size_t count);
196static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
199 *devattr, const char *buf, size_t count);
200static ssize_t show_temp_crit(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_temp_crit(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_type(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t show_temp_beep(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t store_temp_beep(struct device *dev, struct device_attribute
211 *devattr, const char *buf, size_t count);
212static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
213 *devattr, char *buf);
214static ssize_t show_temp_fault(struct device *dev, struct device_attribute
215 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100216/* PWM and Auto point control */
217static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
218 char *buf);
219static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
220 const char *buf, size_t count);
221static ssize_t show_pwm_enable(struct device *dev,
222 struct device_attribute *devattr, char *buf);
223static ssize_t store_pwm_enable(struct device *dev,
224 struct device_attribute *devattr, const char *buf, size_t count);
225static ssize_t show_pwm_interpolate(struct device *dev,
226 struct device_attribute *devattr, char *buf);
227static ssize_t store_pwm_interpolate(struct device *dev,
228 struct device_attribute *devattr, const char *buf, size_t count);
229static ssize_t show_pwm_auto_point_channel(struct device *dev,
230 struct device_attribute *devattr, char *buf);
231static ssize_t store_pwm_auto_point_channel(struct device *dev,
232 struct device_attribute *devattr, const char *buf, size_t count);
233static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
234 struct device_attribute *devattr, char *buf);
235static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
236 struct device_attribute *devattr, const char *buf, size_t count);
237static ssize_t show_pwm_auto_point_pwm(struct device *dev,
238 struct device_attribute *devattr, char *buf);
239static ssize_t store_pwm_auto_point_pwm(struct device *dev,
240 struct device_attribute *devattr, const char *buf, size_t count);
241static ssize_t show_pwm_auto_point_temp(struct device *dev,
242 struct device_attribute *devattr, char *buf);
243static ssize_t store_pwm_auto_point_temp(struct device *dev,
244 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200245/* Sysfs misc */
246static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
247 char *buf);
248
249static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100250static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200251
252static struct platform_driver f71882fg_driver = {
253 .driver = {
254 .owner = THIS_MODULE,
255 .name = DRVNAME,
256 },
257 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200258 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200259};
260
Hans de Goedec13548c2009-01-07 16:37:27 +0100261static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200262
Hans de Goede66344aa2009-12-09 20:35:59 +0100263/* Temp and in attr for the f71858fg, the f71858fg is special as it
264 has its temperature indexes start at 0 (the others start at 1) and
265 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200266static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
267 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
268 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
269 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
270 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
271 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
272 store_temp_max, 0, 0),
273 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
274 store_temp_max_hyst, 0, 0),
275 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
276 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
277 store_temp_crit, 0, 0),
278 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
279 0, 0),
280 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
281 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
282 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
283 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
284 store_temp_max, 0, 1),
285 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
286 store_temp_max_hyst, 0, 1),
287 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
288 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
289 store_temp_crit, 0, 1),
290 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
291 0, 1),
292 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
293 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
294 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
295 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
296 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
297 store_temp_max, 0, 2),
298 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
299 store_temp_max_hyst, 0, 2),
300 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
301 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
302 store_temp_crit, 0, 2),
303 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
304 0, 2),
305 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
306 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
307};
308
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700309/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
310static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100311 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
312 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100313 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
314 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
315 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
316 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
317 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
318 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
319 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100320 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100321 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100322 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100323 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100324 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100325 /* Should really be temp1_max_alarm, but older versions did not handle
326 the max and crit alarms separately and lm_sensors v2 depends on the
327 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
328 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
329 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
330 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100331 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100332 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100333 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100334 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100335 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
336 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
337 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100338 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100339 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
340 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
341 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100342 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100343 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100344 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100345 /* Should be temp2_max_alarm, see temp1_alarm note */
346 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
347 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
348 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100349 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100350 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100353 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
354 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
355 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100357 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
358 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
359 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
360 store_temp_max, 0, 3),
361 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
362 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100363 /* Should be temp3_max_alarm, see temp1_alarm note */
364 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
365 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
366 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
368 store_temp_crit, 0, 3),
369 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
370 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100371 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
372 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
373 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100374 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200376};
377
Hans de Goede66344aa2009-12-09 20:35:59 +0100378/* For models with in1 alarm capability */
379static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100380 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
381 0, 1),
382 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
383 0, 1),
384 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
385};
386
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100387/* Temp and in attr for the f8000
388 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
389 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100390 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100391 */
392static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
393 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
394 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
395 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
396 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
397 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
398 store_temp_crit, 0, 0),
399 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
400 store_temp_max, 0, 0),
401 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200402 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100403 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
404 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
405 store_temp_crit, 0, 1),
406 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
407 store_temp_max, 0, 1),
408 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
409 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200410 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100411 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
412 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
413 store_temp_crit, 0, 2),
414 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
415 store_temp_max, 0, 2),
416 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200417 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100418};
419
420/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100421static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100422 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100423 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
424 show_fan_full_speed,
425 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100427 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
428 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
429 store_pwm_enable, 0, 0),
430 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
431 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100432}, {
433 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
434 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
435 show_fan_full_speed,
436 store_fan_full_speed, 0, 1),
437 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100438 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
439 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
440 store_pwm_enable, 0, 1),
441 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
442 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100443}, {
444 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
445 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
446 show_fan_full_speed,
447 store_fan_full_speed, 0, 2),
448 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200449 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
450 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
451 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100452 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
453 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100454}, {
455 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
456 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
457 show_fan_full_speed,
458 store_fan_full_speed, 0, 3),
459 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
460 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
461 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
462 store_pwm_enable, 0, 3),
463 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
464 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
465} };
Hans de Goede498be962009-01-07 16:37:28 +0100466
Hans de Goede66344aa2009-12-09 20:35:59 +0100467/* Attr for models which can beep on Fan alarm */
468static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100469 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
470 store_fan_beep, 0, 0),
471 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
472 store_fan_beep, 0, 1),
473 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100475 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
476 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100477};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100478
Hans de Goede66344aa2009-12-09 20:35:59 +0100479/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
480 f71858fg / f71882fg / f71889fg */
481static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
482 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
483 show_pwm_auto_point_channel,
484 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100485 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
486 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
487 1, 0),
488 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
489 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
490 4, 0),
491 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
492 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
493 0, 0),
494 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
495 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
496 3, 0),
497 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
498 show_pwm_auto_point_temp_hyst,
499 store_pwm_auto_point_temp_hyst,
500 0, 0),
501 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
502 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
503
Hans de Goede66344aa2009-12-09 20:35:59 +0100504 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_channel,
506 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100507 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 1, 1),
510 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
512 4, 1),
513 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 0, 1),
516 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 3, 1),
519 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp_hyst,
521 store_pwm_auto_point_temp_hyst,
522 0, 1),
523 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
524 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100525
Hans de Goede66344aa2009-12-09 20:35:59 +0100526 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_channel,
528 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100529 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 1, 2),
532 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
534 4, 2),
535 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 0, 2),
538 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
540 3, 2),
541 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp_hyst,
543 store_pwm_auto_point_temp_hyst,
544 0, 2),
545 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
546 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100547};
548
Hans de Goede66344aa2009-12-09 20:35:59 +0100549/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100550static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100551 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_channel,
553 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100554 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
556 0, 0),
557 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
559 1, 0),
560 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
562 2, 0),
563 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
565 3, 0),
566 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
567 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
568 4, 0),
569 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
571 0, 0),
572 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
573 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
574 1, 0),
575 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
576 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
577 2, 0),
578 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
580 3, 0),
581 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_temp_hyst,
583 store_pwm_auto_point_temp_hyst,
584 0, 0),
585 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
586 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
587 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
588 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
589 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100591}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100592 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
593 show_pwm_auto_point_channel,
594 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100595 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
596 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
597 0, 1),
598 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
599 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
600 1, 1),
601 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
602 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
603 2, 1),
604 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
605 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
606 3, 1),
607 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
609 4, 1),
610 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
612 0, 1),
613 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
615 1, 1),
616 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
618 2, 1),
619 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
621 3, 1),
622 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_temp_hyst,
624 store_pwm_auto_point_temp_hyst,
625 0, 1),
626 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
627 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
628 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
630 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
631 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100632}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100633 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
634 show_pwm_auto_point_channel,
635 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100636 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
637 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
638 0, 2),
639 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
640 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
641 1, 2),
642 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
643 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
644 2, 2),
645 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
646 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
647 3, 2),
648 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
649 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
650 4, 2),
651 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
652 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
653 0, 2),
654 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
656 1, 2),
657 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
659 2, 2),
660 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
662 3, 2),
663 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_temp_hyst,
665 store_pwm_auto_point_temp_hyst,
666 0, 2),
667 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
668 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
669 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
671 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
672 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100673}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100674 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_channel,
676 store_pwm_auto_point_channel, 0, 3),
677 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
679 0, 3),
680 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
682 1, 3),
683 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
685 2, 3),
686 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
688 3, 3),
689 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
691 4, 3),
692 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
693 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
694 0, 3),
695 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
697 1, 3),
698 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
700 2, 3),
701 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
703 3, 3),
704 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_temp_hyst,
706 store_pwm_auto_point_temp_hyst,
707 0, 3),
708 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
709 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
710 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
712 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100714} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200715
Hans de Goede66344aa2009-12-09 20:35:59 +0100716/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100717static struct sensor_device_attribute_2 f8000_fan_attr[] = {
718 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100719};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100720
Hans de Goede66344aa2009-12-09 20:35:59 +0100721/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
722 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
723 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
724static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
725 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_channel,
727 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100728 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 0, 2),
731 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 1, 2),
734 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
736 2, 2),
737 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
739 3, 2),
740 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
742 4, 2),
743 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
745 0, 2),
746 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
748 1, 2),
749 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
751 2, 2),
752 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
754 3, 2),
755 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_temp_hyst,
757 store_pwm_auto_point_temp_hyst,
758 0, 2),
759 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
760 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
761 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
763 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
765
Hans de Goede66344aa2009-12-09 20:35:59 +0100766 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_channel,
768 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100769 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
771 0, 0),
772 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
774 1, 0),
775 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
777 2, 0),
778 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
780 3, 0),
781 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
783 4, 0),
784 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
785 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
786 0, 0),
787 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
789 1, 0),
790 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
791 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
792 2, 0),
793 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
794 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
795 3, 0),
796 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
797 show_pwm_auto_point_temp_hyst,
798 store_pwm_auto_point_temp_hyst,
799 0, 0),
800 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
801 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
802 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
804 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
806
Hans de Goede66344aa2009-12-09 20:35:59 +0100807 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_channel,
809 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100810 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
812 0, 1),
813 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
815 1, 1),
816 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
818 2, 1),
819 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
821 3, 1),
822 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
823 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
824 4, 1),
825 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
826 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
827 0, 1),
828 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
830 1, 1),
831 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
832 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
833 2, 1),
834 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
835 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
836 3, 1),
837 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
838 show_pwm_auto_point_temp_hyst,
839 store_pwm_auto_point_temp_hyst,
840 0, 1),
841 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
842 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
843 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
845 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
847};
Hans de Goede45fb3662007-07-13 14:34:19 +0200848
849/* Super I/O functions */
850static inline int superio_inb(int base, int reg)
851{
852 outb(reg, base);
853 return inb(base + 1);
854}
855
856static int superio_inw(int base, int reg)
857{
858 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200859 val = superio_inb(base, reg) << 8;
860 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200861 return val;
862}
863
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400864static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200865{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400866 /* Don't step on other drivers' I/O space by accident */
867 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000868 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400869 return -EBUSY;
870 }
871
Hans de Goede45fb3662007-07-13 14:34:19 +0200872 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200873 outb(SIO_UNLOCK_KEY, base);
874 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400875
876 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200877}
878
Giel van Schijndel162bb592010-05-27 19:58:40 +0200879static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200880{
881 outb(SIO_REG_LDSEL, base);
882 outb(ld, base + 1);
883}
884
885static inline void superio_exit(int base)
886{
887 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400888 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200889}
890
Hans de Goede2f650632009-01-07 16:37:31 +0100891static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200892{
893 return reg ? (1500000 / reg) : 0;
894}
895
Hans de Goede2f650632009-01-07 16:37:31 +0100896static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100897{
898 return fan ? (1500000 / fan) : 0;
899}
900
Hans de Goede45fb3662007-07-13 14:34:19 +0200901static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
902{
903 u8 val;
904
905 outb(reg, data->addr + ADDR_REG_OFFSET);
906 val = inb(data->addr + DATA_REG_OFFSET);
907
908 return val;
909}
910
911static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
912{
913 u16 val;
914
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200915 val = f71882fg_read8(data, reg) << 8;
916 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200917
918 return val;
919}
920
921static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
922{
923 outb(reg, data->addr + ADDR_REG_OFFSET);
924 outb(val, data->addr + DATA_REG_OFFSET);
925}
926
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100927static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
928{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200929 f71882fg_write8(data, reg, val >> 8);
930 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100931}
932
Hans de Goede09475d32009-06-15 18:39:52 +0200933static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
934{
935 if (data->type == f71858fg)
936 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
937 else
938 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
939}
940
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100941static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200942{
943 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100944 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100945 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200946 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200947
948 mutex_lock(&data->update_lock);
949
950 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200951 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200952 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100953 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100954 data->in1_max =
955 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
956 data->in_beep =
957 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
958 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200959
960 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200961 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200962 data->temp_ovt[nr] = f71882fg_read8(data,
963 F71882FG_REG_TEMP_OVT(nr));
964 data->temp_high[nr] = f71882fg_read8(data,
965 F71882FG_REG_TEMP_HIGH(nr));
966 }
967
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100968 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100969 data->temp_hyst[0] = f71882fg_read8(data,
970 F71882FG_REG_TEMP_HYST(0));
971 data->temp_hyst[1] = f71882fg_read8(data,
972 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200973 }
974
Hans de Goede76698962009-12-09 20:36:01 +0100975 if (data->type == f71862fg || data->type == f71882fg ||
976 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200977 data->fan_beep = f71882fg_read8(data,
978 F71882FG_REG_FAN_BEEP);
979 data->temp_beep = f71882fg_read8(data,
980 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100981 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100982 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100983 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
984 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
985 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200986
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100987 data->pwm_enable = f71882fg_read8(data,
988 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100989 data->pwm_auto_point_hyst[0] =
990 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
991 data->pwm_auto_point_hyst[1] =
992 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
993
Hans de Goede498be962009-01-07 16:37:28 +0100994 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100995 data->pwm_auto_point_mapping[nr] =
996 f71882fg_read8(data,
997 F71882FG_REG_POINT_MAPPING(nr));
998
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100999 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001000 int point;
1001 for (point = 0; point < 5; point++) {
1002 data->pwm_auto_point_pwm[nr][point] =
1003 f71882fg_read8(data,
1004 F71882FG_REG_POINT_PWM
1005 (nr, point));
1006 }
1007 for (point = 0; point < 4; point++) {
1008 data->pwm_auto_point_temp[nr][point] =
1009 f71882fg_read8(data,
1010 F71882FG_REG_POINT_TEMP
1011 (nr, point));
1012 }
1013 } else {
1014 data->pwm_auto_point_pwm[nr][1] =
1015 f71882fg_read8(data,
1016 F71882FG_REG_POINT_PWM
1017 (nr, 1));
1018 data->pwm_auto_point_pwm[nr][4] =
1019 f71882fg_read8(data,
1020 F71882FG_REG_POINT_PWM
1021 (nr, 4));
1022 data->pwm_auto_point_temp[nr][0] =
1023 f71882fg_read8(data,
1024 F71882FG_REG_POINT_TEMP
1025 (nr, 0));
1026 data->pwm_auto_point_temp[nr][3] =
1027 f71882fg_read8(data,
1028 F71882FG_REG_POINT_TEMP
1029 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001030 }
1031 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001032 data->last_limits = jiffies;
1033 }
1034
1035 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001036 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001037 data->temp_status = f71882fg_read8(data,
1038 F71882FG_REG_TEMP_STATUS);
1039 data->temp_diode_open = f71882fg_read8(data,
1040 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001041 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1042 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001043
1044 data->fan_status = f71882fg_read8(data,
1045 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001046 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001047 data->fan[nr] = f71882fg_read16(data,
1048 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001049 data->fan_target[nr] =
1050 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1051 data->fan_full_speed[nr] =
1052 f71882fg_read16(data,
1053 F71882FG_REG_FAN_FULL_SPEED(nr));
1054 data->pwm[nr] =
1055 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1056 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001057
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001058 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1059 if (data->type == f8000)
1060 data->fan[3] = f71882fg_read16(data,
1061 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001062 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001063 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001064 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001065 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001066 data->in[nr] = f71882fg_read8(data,
1067 F71882FG_REG_IN(nr));
1068
1069 data->last_updated = jiffies;
1070 data->valid = 1;
1071 }
1072
1073 mutex_unlock(&data->update_lock);
1074
1075 return data;
1076}
1077
1078/* Sysfs Interface */
1079static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1080 char *buf)
1081{
1082 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001083 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001084 int speed = fan_from_reg(data->fan[nr]);
1085
1086 if (speed == FAN_MIN_DETECT)
1087 speed = 0;
1088
1089 return sprintf(buf, "%d\n", speed);
1090}
1091
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001092static ssize_t show_fan_full_speed(struct device *dev,
1093 struct device_attribute *devattr, char *buf)
1094{
1095 struct f71882fg_data *data = f71882fg_update_device(dev);
1096 int nr = to_sensor_dev_attr_2(devattr)->index;
1097 int speed = fan_from_reg(data->fan_full_speed[nr]);
1098 return sprintf(buf, "%d\n", speed);
1099}
1100
1101static ssize_t store_fan_full_speed(struct device *dev,
1102 struct device_attribute *devattr,
1103 const char *buf, size_t count)
1104{
1105 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001106 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1107 long val;
1108
1109 err = strict_strtol(buf, 10, &val);
1110 if (err)
1111 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001112
1113 val = SENSORS_LIMIT(val, 23, 1500000);
1114 val = fan_to_reg(val);
1115
1116 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001117 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1118 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001119 mutex_unlock(&data->update_lock);
1120
1121 return count;
1122}
1123
Hans de Goede45fb3662007-07-13 14:34:19 +02001124static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1125 *devattr, char *buf)
1126{
1127 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001128 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001129
1130 if (data->fan_beep & (1 << nr))
1131 return sprintf(buf, "1\n");
1132 else
1133 return sprintf(buf, "0\n");
1134}
1135
1136static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1137 *devattr, const char *buf, size_t count)
1138{
1139 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001140 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1141 unsigned long val;
1142
1143 err = strict_strtoul(buf, 10, &val);
1144 if (err)
1145 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001146
1147 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001148 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001149 if (val)
1150 data->fan_beep |= 1 << nr;
1151 else
1152 data->fan_beep &= ~(1 << nr);
1153
1154 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1155 mutex_unlock(&data->update_lock);
1156
1157 return count;
1158}
1159
1160static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1161 *devattr, char *buf)
1162{
1163 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001164 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001165
1166 if (data->fan_status & (1 << nr))
1167 return sprintf(buf, "1\n");
1168 else
1169 return sprintf(buf, "0\n");
1170}
1171
1172static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1173 char *buf)
1174{
1175 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001176 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001177
1178 return sprintf(buf, "%d\n", data->in[nr] * 8);
1179}
1180
1181static ssize_t show_in_max(struct device *dev, struct device_attribute
1182 *devattr, char *buf)
1183{
1184 struct f71882fg_data *data = f71882fg_update_device(dev);
1185
1186 return sprintf(buf, "%d\n", data->in1_max * 8);
1187}
1188
1189static ssize_t store_in_max(struct device *dev, struct device_attribute
1190 *devattr, const char *buf, size_t count)
1191{
1192 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001193 int err;
1194 long val;
1195
1196 err = strict_strtol(buf, 10, &val);
1197 if (err)
1198 return err;
1199
1200 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001201 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001202
1203 mutex_lock(&data->update_lock);
1204 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1205 data->in1_max = val;
1206 mutex_unlock(&data->update_lock);
1207
1208 return count;
1209}
1210
1211static ssize_t show_in_beep(struct device *dev, struct device_attribute
1212 *devattr, char *buf)
1213{
1214 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001215 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001216
1217 if (data->in_beep & (1 << nr))
1218 return sprintf(buf, "1\n");
1219 else
1220 return sprintf(buf, "0\n");
1221}
1222
1223static ssize_t store_in_beep(struct device *dev, struct device_attribute
1224 *devattr, const char *buf, size_t count)
1225{
1226 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001227 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1228 unsigned long val;
1229
1230 err = strict_strtoul(buf, 10, &val);
1231 if (err)
1232 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001233
1234 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001235 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001236 if (val)
1237 data->in_beep |= 1 << nr;
1238 else
1239 data->in_beep &= ~(1 << nr);
1240
1241 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1242 mutex_unlock(&data->update_lock);
1243
1244 return count;
1245}
1246
1247static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1248 *devattr, char *buf)
1249{
1250 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001251 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001252
1253 if (data->in_status & (1 << nr))
1254 return sprintf(buf, "1\n");
1255 else
1256 return sprintf(buf, "0\n");
1257}
1258
1259static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1260 char *buf)
1261{
1262 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001263 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001264 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001265
Hans de Goede09475d32009-06-15 18:39:52 +02001266 if (data->type == f71858fg) {
1267 /* TEMP_TABLE_SEL 1 or 3 ? */
1268 if (data->temp_config & 1) {
1269 sign = data->temp[nr] & 0x0001;
1270 temp = (data->temp[nr] >> 5) & 0x7ff;
1271 } else {
1272 sign = data->temp[nr] & 0x8000;
1273 temp = (data->temp[nr] >> 5) & 0x3ff;
1274 }
1275 temp *= 125;
1276 if (sign)
1277 temp -= 128000;
1278 } else
1279 temp = data->temp[nr] * 1000;
1280
1281 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001282}
1283
1284static ssize_t show_temp_max(struct device *dev, struct device_attribute
1285 *devattr, char *buf)
1286{
1287 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001288 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001289
1290 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1291}
1292
1293static ssize_t store_temp_max(struct device *dev, struct device_attribute
1294 *devattr, const char *buf, size_t count)
1295{
1296 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001297 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1298 long val;
1299
1300 err = strict_strtol(buf, 10, &val);
1301 if (err)
1302 return err;
1303
1304 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001305 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001306
1307 mutex_lock(&data->update_lock);
1308 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1309 data->temp_high[nr] = val;
1310 mutex_unlock(&data->update_lock);
1311
1312 return count;
1313}
1314
1315static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1316 *devattr, char *buf)
1317{
1318 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001319 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001320 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001321
Hans de Goedece0bfa52009-01-07 16:37:28 +01001322 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001323 if (nr & 1)
1324 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1325 else
1326 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1327 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001328 mutex_unlock(&data->update_lock);
1329
1330 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001331}
1332
1333static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1334 *devattr, const char *buf, size_t count)
1335{
1336 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001337 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001338 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001339 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001340 long val;
1341
1342 err = strict_strtol(buf, 10, &val);
1343 if (err)
1344 return err;
1345
1346 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001347
1348 mutex_lock(&data->update_lock);
1349
1350 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001351 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1352 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1353 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001354 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001355
1356 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001357 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1358 if (nr & 1)
1359 reg = (reg & 0x0f) | (val << 4);
1360 else
1361 reg = (reg & 0xf0) | val;
1362 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1363 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001364
Hans de Goede45fb3662007-07-13 14:34:19 +02001365 mutex_unlock(&data->update_lock);
1366 return ret;
1367}
1368
1369static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1370 *devattr, char *buf)
1371{
1372 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001373 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001374
1375 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1376}
1377
1378static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1379 *devattr, const char *buf, size_t count)
1380{
1381 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001382 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1383 long val;
1384
1385 err = strict_strtol(buf, 10, &val);
1386 if (err)
1387 return err;
1388
1389 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001390 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001391
1392 mutex_lock(&data->update_lock);
1393 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1394 data->temp_ovt[nr] = val;
1395 mutex_unlock(&data->update_lock);
1396
1397 return count;
1398}
1399
1400static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1401 *devattr, char *buf)
1402{
1403 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001404 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001405 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001406
Hans de Goedece0bfa52009-01-07 16:37:28 +01001407 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001408 if (nr & 1)
1409 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1410 else
1411 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1412 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001413 mutex_unlock(&data->update_lock);
1414
1415 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001416}
1417
1418static ssize_t show_temp_type(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 Goede45fb3662007-07-13 14:34:19 +02001423
1424 return sprintf(buf, "%d\n", data->temp_type[nr]);
1425}
1426
1427static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1428 *devattr, char *buf)
1429{
1430 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001431 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001432
Hans de Goede7567a042009-01-07 16:37:28 +01001433 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001434 return sprintf(buf, "1\n");
1435 else
1436 return sprintf(buf, "0\n");
1437}
1438
1439static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1440 *devattr, const char *buf, size_t count)
1441{
1442 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001443 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1444 unsigned long val;
1445
1446 err = strict_strtoul(buf, 10, &val);
1447 if (err)
1448 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001449
1450 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001451 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001452 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001453 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001454 else
Hans de Goede7567a042009-01-07 16:37:28 +01001455 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001456
1457 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1458 mutex_unlock(&data->update_lock);
1459
1460 return count;
1461}
1462
1463static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1464 *devattr, char *buf)
1465{
1466 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001467 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001468
Hans de Goede7567a042009-01-07 16:37:28 +01001469 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001470 return sprintf(buf, "1\n");
1471 else
1472 return sprintf(buf, "0\n");
1473}
1474
1475static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1476 *devattr, char *buf)
1477{
1478 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001479 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001480
Hans de Goede7567a042009-01-07 16:37:28 +01001481 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001482 return sprintf(buf, "1\n");
1483 else
1484 return sprintf(buf, "0\n");
1485}
1486
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001487static ssize_t show_pwm(struct device *dev,
1488 struct device_attribute *devattr, char *buf)
1489{
1490 struct f71882fg_data *data = f71882fg_update_device(dev);
1491 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001492 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001493 if (data->pwm_enable & (1 << (2 * nr)))
1494 /* PWM mode */
1495 val = data->pwm[nr];
1496 else {
1497 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001498 val = 255 * fan_from_reg(data->fan_target[nr])
1499 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001500 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001501 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001502 return sprintf(buf, "%d\n", val);
1503}
1504
1505static ssize_t store_pwm(struct device *dev,
1506 struct device_attribute *devattr, const char *buf,
1507 size_t count)
1508{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001509 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001510 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1511 long val;
1512
1513 err = strict_strtol(buf, 10, &val);
1514 if (err)
1515 return err;
1516
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001517 val = SENSORS_LIMIT(val, 0, 255);
1518
1519 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001520 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001521 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1522 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1523 count = -EROFS;
1524 goto leave;
1525 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001526 if (data->pwm_enable & (1 << (2 * nr))) {
1527 /* PWM mode */
1528 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1529 data->pwm[nr] = val;
1530 } else {
1531 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001532 int target, full_speed;
1533 full_speed = f71882fg_read16(data,
1534 F71882FG_REG_FAN_FULL_SPEED(nr));
1535 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1536 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1537 data->fan_target[nr] = target;
1538 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001539 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001540leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001541 mutex_unlock(&data->update_lock);
1542
1543 return count;
1544}
1545
1546static ssize_t show_pwm_enable(struct device *dev,
1547 struct device_attribute *devattr, char *buf)
1548{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001549 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001550 struct f71882fg_data *data = f71882fg_update_device(dev);
1551 int nr = to_sensor_dev_attr_2(devattr)->index;
1552
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001553 switch ((data->pwm_enable >> 2 * nr) & 3) {
1554 case 0:
1555 case 1:
1556 result = 2; /* Normal auto mode */
1557 break;
1558 case 2:
1559 result = 1; /* Manual mode */
1560 break;
1561 case 3:
1562 if (data->type == f8000)
1563 result = 3; /* Thermostat mode */
1564 else
1565 result = 1; /* Manual mode */
1566 break;
1567 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001568
1569 return sprintf(buf, "%d\n", result);
1570}
1571
1572static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1573 *devattr, const char *buf, size_t count)
1574{
1575 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001576 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1577 long val;
1578
1579 err = strict_strtol(buf, 10, &val);
1580 if (err)
1581 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001582
Hans de Goede3fc78382009-06-15 18:39:50 +02001583 /* Special case for F8000 pwm channel 3 which only does auto mode */
1584 if (data->type == f8000 && nr == 2 && val != 2)
1585 return -EINVAL;
1586
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001587 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001588 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001589 /* Special case for F8000 auto PWM mode / Thermostat mode */
1590 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1591 switch (val) {
1592 case 2:
1593 data->pwm_enable &= ~(2 << (2 * nr));
1594 break; /* Normal auto mode */
1595 case 3:
1596 data->pwm_enable |= 2 << (2 * nr);
1597 break; /* Thermostat mode */
1598 default:
1599 count = -EINVAL;
1600 goto leave;
1601 }
1602 } else {
1603 switch (val) {
1604 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001605 /* The f71858fg does not support manual RPM mode */
1606 if (data->type == f71858fg &&
1607 ((data->pwm_enable >> (2 * nr)) & 1)) {
1608 count = -EINVAL;
1609 goto leave;
1610 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001611 data->pwm_enable |= 2 << (2 * nr);
1612 break; /* Manual */
1613 case 2:
1614 data->pwm_enable &= ~(2 << (2 * nr));
1615 break; /* Normal auto mode */
1616 default:
1617 count = -EINVAL;
1618 goto leave;
1619 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001620 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001621 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001622leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001623 mutex_unlock(&data->update_lock);
1624
1625 return count;
1626}
1627
1628static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1629 struct device_attribute *devattr,
1630 char *buf)
1631{
1632 int result;
1633 struct f71882fg_data *data = f71882fg_update_device(dev);
1634 int pwm = to_sensor_dev_attr_2(devattr)->index;
1635 int point = to_sensor_dev_attr_2(devattr)->nr;
1636
Hans de Goedece0bfa52009-01-07 16:37:28 +01001637 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001638 if (data->pwm_enable & (1 << (2 * pwm))) {
1639 /* PWM mode */
1640 result = data->pwm_auto_point_pwm[pwm][point];
1641 } else {
1642 /* RPM mode */
1643 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1644 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001645 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001646
1647 return sprintf(buf, "%d\n", result);
1648}
1649
1650static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1651 struct device_attribute *devattr,
1652 const char *buf, size_t count)
1653{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001654 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001655 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001656 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001657 long val;
1658
1659 err = strict_strtol(buf, 10, &val);
1660 if (err)
1661 return err;
1662
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001663 val = SENSORS_LIMIT(val, 0, 255);
1664
1665 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001666 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001667 if (data->pwm_enable & (1 << (2 * pwm))) {
1668 /* PWM mode */
1669 } else {
1670 /* RPM mode */
1671 if (val < 29) /* Prevent negative numbers */
1672 val = 255;
1673 else
1674 val = (255 - val) * 32 / val;
1675 }
1676 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1677 data->pwm_auto_point_pwm[pwm][point] = val;
1678 mutex_unlock(&data->update_lock);
1679
1680 return count;
1681}
1682
1683static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1684 struct device_attribute *devattr,
1685 char *buf)
1686{
1687 int result = 0;
1688 struct f71882fg_data *data = f71882fg_update_device(dev);
1689 int nr = to_sensor_dev_attr_2(devattr)->index;
1690 int point = to_sensor_dev_attr_2(devattr)->nr;
1691
1692 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001693 if (nr & 1)
1694 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1695 else
1696 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001697 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1698 mutex_unlock(&data->update_lock);
1699
1700 return sprintf(buf, "%d\n", result);
1701}
1702
1703static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1704 struct device_attribute *devattr,
1705 const char *buf, size_t count)
1706{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001707 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001708 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001709 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001710 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001711 long val;
1712
1713 err = strict_strtol(buf, 10, &val);
1714 if (err)
1715 return err;
1716
1717 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001718
1719 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001720 data->pwm_auto_point_temp[nr][point] =
1721 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001722 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1723 data->pwm_auto_point_temp[nr][point]);
1724 val = data->pwm_auto_point_temp[nr][point] - val;
1725
Hans de Goedebc274902009-01-07 16:37:29 +01001726 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1727 if (nr & 1)
1728 reg = (reg & 0x0f) | (val << 4);
1729 else
1730 reg = (reg & 0xf0) | val;
1731
1732 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1733 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001734 mutex_unlock(&data->update_lock);
1735
1736 return count;
1737}
1738
1739static ssize_t show_pwm_interpolate(struct device *dev,
1740 struct device_attribute *devattr, char *buf)
1741{
1742 int result;
1743 struct f71882fg_data *data = f71882fg_update_device(dev);
1744 int nr = to_sensor_dev_attr_2(devattr)->index;
1745
1746 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1747
1748 return sprintf(buf, "%d\n", result);
1749}
1750
1751static ssize_t store_pwm_interpolate(struct device *dev,
1752 struct device_attribute *devattr,
1753 const char *buf, size_t count)
1754{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001755 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001756 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1757 unsigned long val;
1758
1759 err = strict_strtoul(buf, 10, &val);
1760 if (err)
1761 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001762
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001763 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001764 data->pwm_auto_point_mapping[nr] =
1765 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001766 if (val)
1767 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1768 else
1769 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1770 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1771 data->pwm_auto_point_mapping[nr] = val;
1772 mutex_unlock(&data->update_lock);
1773
1774 return count;
1775}
1776
1777static ssize_t show_pwm_auto_point_channel(struct device *dev,
1778 struct device_attribute *devattr,
1779 char *buf)
1780{
1781 int result;
1782 struct f71882fg_data *data = f71882fg_update_device(dev);
1783 int nr = to_sensor_dev_attr_2(devattr)->index;
1784
Hans de Goede09475d32009-06-15 18:39:52 +02001785 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1786 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001787
1788 return sprintf(buf, "%d\n", result);
1789}
1790
1791static ssize_t store_pwm_auto_point_channel(struct device *dev,
1792 struct device_attribute *devattr,
1793 const char *buf, size_t count)
1794{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001795 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001796 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1797 long val;
1798
1799 err = strict_strtol(buf, 10, &val);
1800 if (err)
1801 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001802
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001803 switch (val) {
1804 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001805 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001806 break;
1807 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001808 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001809 break;
1810 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001811 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001812 break;
1813 default:
1814 return -EINVAL;
1815 }
Hans de Goede09475d32009-06-15 18:39:52 +02001816 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001817 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001818 data->pwm_auto_point_mapping[nr] =
1819 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001820 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1821 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1822 data->pwm_auto_point_mapping[nr] = val;
1823 mutex_unlock(&data->update_lock);
1824
1825 return count;
1826}
1827
1828static ssize_t show_pwm_auto_point_temp(struct device *dev,
1829 struct device_attribute *devattr,
1830 char *buf)
1831{
1832 int result;
1833 struct f71882fg_data *data = f71882fg_update_device(dev);
1834 int pwm = to_sensor_dev_attr_2(devattr)->index;
1835 int point = to_sensor_dev_attr_2(devattr)->nr;
1836
1837 result = data->pwm_auto_point_temp[pwm][point];
1838 return sprintf(buf, "%d\n", 1000 * result);
1839}
1840
1841static ssize_t store_pwm_auto_point_temp(struct device *dev,
1842 struct device_attribute *devattr,
1843 const char *buf, size_t count)
1844{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001845 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001846 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001847 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001848 long val;
1849
1850 err = strict_strtol(buf, 10, &val);
1851 if (err)
1852 return err;
1853
1854 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001855
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001856 if (data->type == f71889fg)
Hans de Goede76698962009-12-09 20:36:01 +01001857 val = SENSORS_LIMIT(val, -128, 127);
1858 else
1859 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001860
1861 mutex_lock(&data->update_lock);
1862 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1863 data->pwm_auto_point_temp[pwm][point] = val;
1864 mutex_unlock(&data->update_lock);
1865
1866 return count;
1867}
1868
Hans de Goede45fb3662007-07-13 14:34:19 +02001869static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1870 char *buf)
1871{
Hans de Goede498be962009-01-07 16:37:28 +01001872 struct f71882fg_data *data = dev_get_drvdata(dev);
1873 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001874}
1875
Hans de Goedec13548c2009-01-07 16:37:27 +01001876static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1877 struct sensor_device_attribute_2 *attr, int count)
1878{
1879 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001880
Hans de Goedec13548c2009-01-07 16:37:27 +01001881 for (i = 0; i < count; i++) {
1882 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1883 if (err)
1884 return err;
1885 }
1886 return 0;
1887}
1888
Hans de Goedefc16c562009-12-09 20:36:01 +01001889static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1890 struct sensor_device_attribute_2 *attr, int count)
1891{
1892 int i;
1893
1894 for (i = 0; i < count; i++)
1895 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1896}
1897
Hans de Goedec13548c2009-01-07 16:37:27 +01001898static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001899{
1900 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001901 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001902 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001903 u8 start_reg;
1904
Hans de Goedec13548c2009-01-07 16:37:27 +01001905 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1906 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001907 return -ENOMEM;
1908
1909 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001910 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001911 data->temp_start =
1912 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001913 mutex_init(&data->update_lock);
1914 platform_set_drvdata(pdev, data);
1915
Hans de Goede3cc74752009-01-07 16:37:28 +01001916 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001917 if (start_reg & 0x04) {
1918 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1919 err = -ENODEV;
1920 goto exit_free;
1921 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001922 if (!(start_reg & 0x03)) {
1923 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1924 err = -ENODEV;
1925 goto exit_free;
1926 }
1927
Hans de Goede45fb3662007-07-13 14:34:19 +02001928 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001929 err = device_create_file(&pdev->dev, &dev_attr_name);
1930 if (err)
1931 goto exit_unregister_sysfs;
1932
Hans de Goedec13548c2009-01-07 16:37:27 +01001933 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001934 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001935 case f71858fg:
1936 data->temp_config =
1937 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1938 if (data->temp_config & 0x10)
1939 /* The f71858fg temperature alarms behave as
1940 the f8000 alarms in this mode */
1941 err = f71882fg_create_sysfs_files(pdev,
1942 f8000_in_temp_attr,
1943 ARRAY_SIZE(f8000_in_temp_attr));
1944 else
1945 err = f71882fg_create_sysfs_files(pdev,
1946 f71858fg_in_temp_attr,
1947 ARRAY_SIZE(f71858fg_in_temp_attr));
1948 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001949 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001950 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001951 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001952 fxxxx_in1_alarm_attr,
1953 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001954 if (err)
1955 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001956 /* fall through! */
1957 case f71862fg:
1958 err = f71882fg_create_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001959 fxxxx_in_temp_attr,
1960 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001961 break;
1962 case f8000:
1963 err = f71882fg_create_sysfs_files(pdev,
1964 f8000_in_temp_attr,
1965 ARRAY_SIZE(f8000_in_temp_attr));
1966 break;
Hans de Goede498be962009-01-07 16:37:28 +01001967 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001968 if (err)
1969 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001970 }
1971
Hans de Goede45fb3662007-07-13 14:34:19 +02001972 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001973 data->pwm_enable =
1974 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1975
1976 /* Sanity check the pwm settings */
1977 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001978 case f71858fg:
1979 err = 0;
1980 for (i = 0; i < nr_fans; i++)
1981 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1982 err = 1;
1983 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001984 case f71862fg:
1985 err = (data->pwm_enable & 0x15) != 0x15;
1986 break;
1987 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001988 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02001989 err = 0;
1990 break;
1991 case f8000:
1992 err = data->pwm_enable & 0x20;
1993 break;
1994 }
1995 if (err) {
1996 dev_err(&pdev->dev,
1997 "Invalid (reserved) pwm settings: 0x%02x\n",
1998 (unsigned int)data->pwm_enable);
1999 err = -ENODEV;
2000 goto exit_unregister_sysfs;
2001 }
2002
Hans de Goedeb69b0392009-12-09 20:36:00 +01002003 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2004 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002005 if (err)
2006 goto exit_unregister_sysfs;
2007
Hans de Goede76698962009-12-09 20:36:01 +01002008 if (data->type == f71862fg || data->type == f71882fg ||
2009 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002010 err = f71882fg_create_sysfs_files(pdev,
2011 fxxxx_fan_beep_attr, nr_fans);
2012 if (err)
2013 goto exit_unregister_sysfs;
2014 }
2015
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002016 switch (data->type) {
2017 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002018 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002019 f71862fg_auto_pwm_attr,
2020 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002021 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002022 case f8000:
2023 err = f71882fg_create_sysfs_files(pdev,
2024 f8000_fan_attr,
2025 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002026 if (err)
2027 goto exit_unregister_sysfs;
2028 err = f71882fg_create_sysfs_files(pdev,
2029 f8000_auto_pwm_attr,
2030 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002031 break;
Hans de Goede76698962009-12-09 20:36:01 +01002032 case f71889fg:
2033 for (i = 0; i < nr_fans; i++) {
2034 data->pwm_auto_point_mapping[i] =
2035 f71882fg_read8(data,
2036 F71882FG_REG_POINT_MAPPING(i));
2037 if (data->pwm_auto_point_mapping[i] & 0x80)
2038 break;
2039 }
2040 if (i != nr_fans) {
2041 dev_warn(&pdev->dev,
2042 "Auto pwm controlled by raw digital "
2043 "data, disabling pwm auto_point "
2044 "sysfs attributes\n");
2045 break;
2046 }
2047 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002048 default: /* f71858fg / f71882fg */
2049 err = f71882fg_create_sysfs_files(pdev,
2050 &fxxxx_auto_pwm_attr[0][0],
2051 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002052 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002053 if (err)
2054 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002055
2056 for (i = 0; i < nr_fans; i++)
2057 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2058 (data->pwm_enable & (1 << 2 * i)) ?
2059 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002060 }
2061
Tony Jones1beeffe2007-08-20 13:46:20 -07002062 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2063 if (IS_ERR(data->hwmon_dev)) {
2064 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002065 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002066 goto exit_unregister_sysfs;
2067 }
2068
2069 return 0;
2070
2071exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002072 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002073 return err; /* f71882fg_remove() also frees our data */
2074exit_free:
2075 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002076 return err;
2077}
2078
Hans de Goedec13548c2009-01-07 16:37:27 +01002079static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002080{
Hans de Goede45fb3662007-07-13 14:34:19 +02002081 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002082 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2083 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002084
Hans de Goedec13548c2009-01-07 16:37:27 +01002085 if (data->hwmon_dev)
2086 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002087
Hans de Goedec13548c2009-01-07 16:37:27 +01002088 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002089
Hans de Goedefc16c562009-12-09 20:36:01 +01002090 if (start_reg & 0x01) {
2091 switch (data->type) {
2092 case f71858fg:
2093 if (data->temp_config & 0x10)
2094 f71882fg_remove_sysfs_files(pdev,
2095 f8000_in_temp_attr,
2096 ARRAY_SIZE(f8000_in_temp_attr));
2097 else
2098 f71882fg_remove_sysfs_files(pdev,
2099 f71858fg_in_temp_attr,
2100 ARRAY_SIZE(f71858fg_in_temp_attr));
2101 break;
2102 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002103 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002104 f71882fg_remove_sysfs_files(pdev,
2105 fxxxx_in1_alarm_attr,
2106 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2107 /* fall through! */
2108 case f71862fg:
2109 f71882fg_remove_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07002110 fxxxx_in_temp_attr,
2111 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002112 break;
2113 case f8000:
2114 f71882fg_remove_sysfs_files(pdev,
2115 f8000_in_temp_attr,
2116 ARRAY_SIZE(f8000_in_temp_attr));
2117 break;
2118 }
2119 }
Hans de Goede498be962009-01-07 16:37:28 +01002120
Hans de Goedefc16c562009-12-09 20:36:01 +01002121 if (start_reg & 0x02) {
2122 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2123 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002124
Hans de Goede76698962009-12-09 20:36:01 +01002125 if (data->type == f71862fg || data->type == f71882fg ||
2126 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002127 f71882fg_remove_sysfs_files(pdev,
2128 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002129
Hans de Goedefc16c562009-12-09 20:36:01 +01002130 switch (data->type) {
2131 case f71862fg:
2132 f71882fg_remove_sysfs_files(pdev,
2133 f71862fg_auto_pwm_attr,
2134 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2135 break;
2136 case f8000:
2137 f71882fg_remove_sysfs_files(pdev,
2138 f8000_fan_attr,
2139 ARRAY_SIZE(f8000_fan_attr));
2140 f71882fg_remove_sysfs_files(pdev,
2141 f8000_auto_pwm_attr,
2142 ARRAY_SIZE(f8000_auto_pwm_attr));
2143 break;
2144 default: /* f71858fg / f71882fg / f71889fg */
2145 f71882fg_remove_sysfs_files(pdev,
2146 &fxxxx_auto_pwm_attr[0][0],
2147 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2148 }
2149 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002150
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002151 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002152 kfree(data);
2153
2154 return 0;
2155}
2156
Hans de Goede498be962009-01-07 16:37:28 +01002157static int __init f71882fg_find(int sioaddr, unsigned short *address,
2158 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002159{
Hans de Goede45fb3662007-07-13 14:34:19 +02002160 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002161 int err = superio_enter(sioaddr);
2162 if (err)
2163 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002164
2165 devid = superio_inw(sioaddr, SIO_REG_MANID);
2166 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002167 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002168 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002169 goto exit;
2170 }
2171
Jean Delvare67b671b2007-12-06 23:13:42 +01002172 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002173 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002174 case SIO_F71858_ID:
2175 sio_data->type = f71858fg;
2176 break;
Hans de Goede498be962009-01-07 16:37:28 +01002177 case SIO_F71862_ID:
2178 sio_data->type = f71862fg;
2179 break;
2180 case SIO_F71882_ID:
2181 sio_data->type = f71882fg;
2182 break;
Hans de Goede76698962009-12-09 20:36:01 +01002183 case SIO_F71889_ID:
2184 sio_data->type = f71889fg;
2185 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002186 case SIO_F8000_ID:
2187 sio_data->type = f8000;
2188 break;
Hans de Goede498be962009-01-07 16:37:28 +01002189 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002190 pr_info("Unsupported Fintek device: %04x\n",
2191 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002192 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002193 goto exit;
2194 }
2195
Hans de Goede09475d32009-06-15 18:39:52 +02002196 if (sio_data->type == f71858fg)
2197 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2198 else
2199 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2200
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002201 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002202 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002203 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002204 goto exit;
2205 }
2206
2207 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002208 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002209 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002210 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002211 goto exit;
2212 }
2213 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2214
Hans de Goede45fb3662007-07-13 14:34:19 +02002215 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002216 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002217 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002218 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2219exit:
2220 superio_exit(sioaddr);
2221 return err;
2222}
2223
Hans de Goede498be962009-01-07 16:37:28 +01002224static int __init f71882fg_device_add(unsigned short address,
2225 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002226{
2227 struct resource res = {
2228 .start = address,
2229 .end = address + REGION_LENGTH - 1,
2230 .flags = IORESOURCE_IO,
2231 };
2232 int err;
2233
2234 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002235 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002236 return -ENOMEM;
2237
2238 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002239 err = acpi_check_resource_conflict(&res);
2240 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002241 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002242
Hans de Goede45fb3662007-07-13 14:34:19 +02002243 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002244 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002245 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002246 goto exit_device_put;
2247 }
2248
Hans de Goede498be962009-01-07 16:37:28 +01002249 err = platform_device_add_data(f71882fg_pdev, sio_data,
2250 sizeof(struct f71882fg_sio_data));
2251 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002252 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002253 goto exit_device_put;
2254 }
2255
Hans de Goede45fb3662007-07-13 14:34:19 +02002256 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002257 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002258 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002259 goto exit_device_put;
2260 }
2261
2262 return 0;
2263
2264exit_device_put:
2265 platform_device_put(f71882fg_pdev);
2266
2267 return err;
2268}
2269
2270static int __init f71882fg_init(void)
2271{
2272 int err = -ENODEV;
2273 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002274 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002275
Hans de Goede498be962009-01-07 16:37:28 +01002276 memset(&sio_data, 0, sizeof(sio_data));
2277
2278 if (f71882fg_find(0x2e, &address, &sio_data) &&
2279 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002280 goto exit;
2281
Hans de Goedec13548c2009-01-07 16:37:27 +01002282 err = platform_driver_register(&f71882fg_driver);
2283 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002284 goto exit;
2285
Hans de Goede498be962009-01-07 16:37:28 +01002286 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002287 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002288 goto exit_driver;
2289
2290 return 0;
2291
2292exit_driver:
2293 platform_driver_unregister(&f71882fg_driver);
2294exit:
2295 return err;
2296}
2297
2298static void __exit f71882fg_exit(void)
2299{
2300 platform_device_unregister(f71882fg_pdev);
2301 platform_driver_unregister(&f71882fg_driver);
2302}
2303
2304MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002305MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002306MODULE_LICENSE("GPL");
2307
2308module_init(f71882fg_init);
2309module_exit(f71882fg_exit);