blob: 4146105f1a5779a5de55006444b9de99e90e8319 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede3fc78382009-06-15 18:39:50 +02003 * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/jiffies.h>
25#include <linux/platform_device.h>
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h>
29#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010030#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010031#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020032
33#define DRVNAME "f71882fg"
34
Hans de Goede09475d32009-06-15 18:39:52 +020035#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010036#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020037#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
38#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
39
40#define SIO_REG_LDSEL 0x07 /* Logical device select */
41#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
42#define SIO_REG_DEVREV 0x22 /* Device revision */
43#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
44#define SIO_REG_ENABLE 0x30 /* Logical device enable */
45#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
46
47#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020048#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010049#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020050#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010051#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052
53#define REGION_LENGTH 8
54#define ADDR_REG_OFFSET 5
55#define DATA_REG_OFFSET 6
56
57#define F71882FG_REG_PECI 0x0A
58
Hans de Goede498be962009-01-07 16:37:28 +010059#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
60#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020061#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010062#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020063
64#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010065#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
66#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020067#define F71882FG_REG_FAN_STATUS 0x92
68#define F71882FG_REG_FAN_BEEP 0x93
69
Hans de Goede7567a042009-01-07 16:37:28 +010070#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
71#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
72#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020073#define F71882FG_REG_TEMP_STATUS 0x62
74#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020075#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010076#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020077#define F71882FG_REG_TEMP_TYPE 0x6B
78#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
79
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010080#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
81#define F71882FG_REG_PWM_TYPE 0x94
82#define F71882FG_REG_PWM_ENABLE 0x96
83
Hans de Goedebc274902009-01-07 16:37:29 +010084#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010085
86#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
87#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
88#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
89
Hans de Goede45fb3662007-07-13 14:34:19 +020090#define F71882FG_REG_START 0x01
91
92#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
93
Jean Delvare67b671b2007-12-06 23:13:42 +010094static unsigned short force_id;
95module_param(force_id, ushort, 0);
96MODULE_PARM_DESC(force_id, "Override the detected device ID");
97
Hans de Goede09475d32009-06-15 18:39:52 +020098enum chips { f71858fg, f71862fg, f71882fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +010099
100static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200101 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100102 "f71862fg",
103 "f71882fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100104 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100105};
106
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100107static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200108
109/* Super-I/O Function prototypes */
110static inline int superio_inb(int base, int reg);
111static inline int superio_inw(int base, int reg);
112static inline void superio_enter(int base);
113static inline void superio_select(int base, int ld);
114static inline void superio_exit(int base);
115
Hans de Goede498be962009-01-07 16:37:28 +0100116struct f71882fg_sio_data {
117 enum chips type;
118};
119
Hans de Goede45fb3662007-07-13 14:34:19 +0200120struct f71882fg_data {
121 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100122 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700123 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200124
125 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200126 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200127 char valid; /* !=0 if following fields are valid */
128 unsigned long last_updated; /* In jiffies */
129 unsigned long last_limits; /* In jiffies */
130
131 /* Register Values */
132 u8 in[9];
133 u8 in1_max;
134 u8 in_status;
135 u8 in_beep;
136 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100137 u16 fan_target[4];
138 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200139 u8 fan_status;
140 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100141 /* Note: all models have only 3 temperature channels, but on some
142 they are addressed as 0-2 and on others as 1-3, so for coding
143 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200144 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100145 u8 temp_ovt[4];
146 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100147 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100148 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200149 u8 temp_status;
150 u8 temp_beep;
151 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200152 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100153 u8 pwm[4];
154 u8 pwm_enable;
155 u8 pwm_auto_point_hyst[2];
156 u8 pwm_auto_point_mapping[4];
157 u8 pwm_auto_point_pwm[4][5];
158 u8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200159};
160
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100161/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200162static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
163 char *buf);
164static ssize_t show_in_max(struct device *dev, struct device_attribute
165 *devattr, char *buf);
166static ssize_t store_in_max(struct device *dev, struct device_attribute
167 *devattr, const char *buf, size_t count);
168static ssize_t show_in_beep(struct device *dev, struct device_attribute
169 *devattr, char *buf);
170static ssize_t store_in_beep(struct device *dev, struct device_attribute
171 *devattr, const char *buf, size_t count);
172static ssize_t show_in_alarm(struct device *dev, struct device_attribute
173 *devattr, char *buf);
174/* Sysfs Fan */
175static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
176 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100177static ssize_t show_fan_full_speed(struct device *dev,
178 struct device_attribute *devattr, char *buf);
179static ssize_t store_fan_full_speed(struct device *dev,
180 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200181static ssize_t show_fan_beep(struct device *dev, struct device_attribute
182 *devattr, char *buf);
183static ssize_t store_fan_beep(struct device *dev, struct device_attribute
184 *devattr, const char *buf, size_t count);
185static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
186 *devattr, char *buf);
187/* Sysfs Temp */
188static ssize_t show_temp(struct device *dev, struct device_attribute
189 *devattr, char *buf);
190static ssize_t show_temp_max(struct device *dev, struct device_attribute
191 *devattr, char *buf);
192static ssize_t store_temp_max(struct device *dev, struct device_attribute
193 *devattr, const char *buf, size_t count);
194static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
195 *devattr, char *buf);
196static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
197 *devattr, const char *buf, size_t count);
198static ssize_t show_temp_crit(struct device *dev, struct device_attribute
199 *devattr, char *buf);
200static ssize_t store_temp_crit(struct device *dev, struct device_attribute
201 *devattr, const char *buf, size_t count);
202static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
203 *devattr, char *buf);
204static ssize_t show_temp_type(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_beep(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t store_temp_beep(struct device *dev, struct device_attribute
209 *devattr, const char *buf, size_t count);
210static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212static ssize_t show_temp_fault(struct device *dev, struct device_attribute
213 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100214/* PWM and Auto point control */
215static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
216 char *buf);
217static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
218 const char *buf, size_t count);
219static ssize_t show_pwm_enable(struct device *dev,
220 struct device_attribute *devattr, char *buf);
221static ssize_t store_pwm_enable(struct device *dev,
222 struct device_attribute *devattr, const char *buf, size_t count);
223static ssize_t show_pwm_interpolate(struct device *dev,
224 struct device_attribute *devattr, char *buf);
225static ssize_t store_pwm_interpolate(struct device *dev,
226 struct device_attribute *devattr, const char *buf, size_t count);
227static ssize_t show_pwm_auto_point_channel(struct device *dev,
228 struct device_attribute *devattr, char *buf);
229static ssize_t store_pwm_auto_point_channel(struct device *dev,
230 struct device_attribute *devattr, const char *buf, size_t count);
231static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
232 struct device_attribute *devattr, char *buf);
233static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
234 struct device_attribute *devattr, const char *buf, size_t count);
235static ssize_t show_pwm_auto_point_pwm(struct device *dev,
236 struct device_attribute *devattr, char *buf);
237static ssize_t store_pwm_auto_point_pwm(struct device *dev,
238 struct device_attribute *devattr, const char *buf, size_t count);
239static ssize_t show_pwm_auto_point_temp(struct device *dev,
240 struct device_attribute *devattr, char *buf);
241static ssize_t store_pwm_auto_point_temp(struct device *dev,
242 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200243/* Sysfs misc */
244static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
245 char *buf);
246
247static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100248static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200249
250static struct platform_driver f71882fg_driver = {
251 .driver = {
252 .owner = THIS_MODULE,
253 .name = DRVNAME,
254 },
255 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200256 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200257};
258
Hans de Goedec13548c2009-01-07 16:37:27 +0100259static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200260
Hans de Goede09475d32009-06-15 18:39:52 +0200261/* Temp and in attr for the f71858fg */
262static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
263 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
264 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
265 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
266 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
267 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
268 store_temp_max, 0, 0),
269 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
270 store_temp_max_hyst, 0, 0),
271 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
272 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
273 store_temp_crit, 0, 0),
274 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
275 0, 0),
276 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
277 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
278 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
279 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
280 store_temp_max, 0, 1),
281 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
282 store_temp_max_hyst, 0, 1),
283 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
284 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
285 store_temp_crit, 0, 1),
286 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
287 0, 1),
288 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
289 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
290 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
291 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
292 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
293 store_temp_max, 0, 2),
294 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
295 store_temp_max_hyst, 0, 2),
296 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
297 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
298 store_temp_crit, 0, 2),
299 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
300 0, 2),
301 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
302 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
303};
304
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100305/* Temp and in attr common to both the f71862fg and f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100306static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100307 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
308 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100309 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
310 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
311 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
312 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
313 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
314 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
315 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100316 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100317 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100318 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100319 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100320 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100321 /* Should really be temp1_max_alarm, but older versions did not handle
322 the max and crit alarms separately and lm_sensors v2 depends on the
323 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
324 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
325 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
326 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100327 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100328 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100329 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100330 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100331 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
332 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
333 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100334 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100335 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
336 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
337 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100338 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100339 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100340 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100341 /* Should be temp2_max_alarm, see temp1_alarm note */
342 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
343 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
344 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100345 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100346 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100348 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100349 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
350 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
351 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100352 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
354 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
355 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
356 store_temp_max, 0, 3),
357 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
358 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100359 /* Should be temp3_max_alarm, see temp1_alarm note */
360 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
361 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
362 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100363 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
364 store_temp_crit, 0, 3),
365 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
366 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100367 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
368 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
369 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100370 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100371 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200372};
373
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100374/* Temp and in attr found only on the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100375static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = {
376 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
377 0, 1),
378 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
379 0, 1),
380 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
381};
382
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100383/* Temp and in attr for the f8000
384 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
385 is used as hysteresis value to clear alarms
386 */
387static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
388 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
389 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
390 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
391 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
392 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
393 store_temp_crit, 0, 0),
394 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
395 store_temp_max, 0, 0),
396 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200397 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100398 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
399 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
400 store_temp_crit, 0, 1),
401 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
402 store_temp_max, 0, 1),
403 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
404 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200405 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100406 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
407 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
408 store_temp_crit, 0, 2),
409 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
410 store_temp_max, 0, 2),
411 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200412 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100413};
414
415/* Fan / PWM attr common to all models */
416static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100417 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100418 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
419 show_fan_full_speed,
420 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100421 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
422 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100423 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
424 show_fan_full_speed,
425 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
427 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100428 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
429 show_fan_full_speed,
430 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100431 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100432
433 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
434 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
435 store_pwm_enable, 0, 0),
436 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
437 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
438 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
439 show_pwm_auto_point_channel,
440 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100441
442 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
443 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
444 store_pwm_enable, 0, 1),
445 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
446 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
447 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
448 show_pwm_auto_point_channel,
449 store_pwm_auto_point_channel, 0, 1),
450
Hans de Goede3fc78382009-06-15 18:39:50 +0200451 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
452 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
453 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100454 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
455 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
456 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
457 show_pwm_auto_point_channel,
458 store_pwm_auto_point_channel, 0, 2),
459};
460
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100461/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
462 f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100463static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100464 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
465 store_fan_beep, 0, 0),
466 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
467 store_fan_beep, 0, 1),
468 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
469 store_fan_beep, 0, 2),
470
Hans de Goede498be962009-01-07 16:37:28 +0100471 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
472 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
473 1, 0),
474 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
475 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
476 4, 0),
477 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
478 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
479 0, 0),
480 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
481 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
482 3, 0),
483 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
484 show_pwm_auto_point_temp_hyst,
485 store_pwm_auto_point_temp_hyst,
486 0, 0),
487 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
488 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
489
490 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
491 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
492 1, 1),
493 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
494 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
495 4, 1),
496 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
497 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
498 0, 1),
499 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
500 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
501 3, 1),
502 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
503 show_pwm_auto_point_temp_hyst,
504 store_pwm_auto_point_temp_hyst,
505 0, 1),
506 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
507 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100508
Hans de Goede49010622009-01-07 16:37:30 +0100509 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
510 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
511 1, 2),
512 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
513 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
514 4, 2),
515 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
517 0, 2),
518 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
520 3, 2),
521 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
522 show_pwm_auto_point_temp_hyst,
523 store_pwm_auto_point_temp_hyst,
524 0, 2),
525 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
526 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100527};
528
Hans de Goede09475d32009-06-15 18:39:52 +0200529/* Fan / PWM attr common to both the f71882fg and f71858fg */
530static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100531 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
532 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
533 0, 0),
534 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
535 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
536 1, 0),
537 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
538 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
539 2, 0),
540 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
541 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
542 3, 0),
543 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
544 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
545 4, 0),
546 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
547 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
548 0, 0),
549 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
550 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
551 1, 0),
552 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
553 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
554 2, 0),
555 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
556 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
557 3, 0),
558 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
559 show_pwm_auto_point_temp_hyst,
560 store_pwm_auto_point_temp_hyst,
561 0, 0),
562 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
563 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
564 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
565 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
566 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
567 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
568
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100569 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
571 0, 1),
572 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
573 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
574 1, 1),
575 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
576 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
577 2, 1),
578 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
580 3, 1),
581 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
583 4, 1),
584 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
585 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
586 0, 1),
587 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
588 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
589 1, 1),
590 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
592 2, 1),
593 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
595 3, 1),
596 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_temp_hyst,
598 store_pwm_auto_point_temp_hyst,
599 0, 1),
600 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
601 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
602 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
603 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
604 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
605 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
606
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100607 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
609 0, 2),
610 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
612 1, 2),
613 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
615 2, 2),
616 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
618 3, 2),
619 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
621 4, 2),
622 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
624 0, 2),
625 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
627 1, 2),
628 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
630 2, 2),
631 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
633 3, 2),
634 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_temp_hyst,
636 store_pwm_auto_point_temp_hyst,
637 0, 2),
638 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
639 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
640 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
641 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
642 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
643 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede09475d32009-06-15 18:39:52 +0200644};
645
646/* Fan / PWM attr found on the f71882fg but not on the f71858fg */
647static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
648 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
649 store_fan_beep, 0, 0),
650 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
651 store_fan_beep, 0, 1),
652 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
653 store_fan_beep, 0, 2),
654
655 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
656 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
657 show_fan_full_speed,
658 store_fan_full_speed, 0, 3),
659 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
660 store_fan_beep, 0, 3),
661 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100662
663 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
664 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
665 store_pwm_enable, 0, 3),
666 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
667 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
668 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_channel,
670 store_pwm_auto_point_channel, 0, 3),
671 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
672 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
673 0, 3),
674 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
676 1, 3),
677 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
679 2, 3),
680 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
682 3, 3),
683 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
685 4, 3),
686 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
688 0, 3),
689 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
691 1, 3),
692 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
693 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
694 2, 3),
695 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
697 3, 3),
698 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_temp_hyst,
700 store_pwm_auto_point_temp_hyst,
701 0, 3),
702 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
703 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
704 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
705 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
706 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
707 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200708};
709
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100710/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm!
711 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
712 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
713static struct sensor_device_attribute_2 f8000_fan_attr[] = {
714 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
715
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100716 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
718 0, 2),
719 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
721 1, 2),
722 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
724 2, 2),
725 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
727 3, 2),
728 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 4, 2),
731 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
733 0, 2),
734 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
736 1, 2),
737 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
739 2, 2),
740 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
742 3, 2),
743 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp_hyst,
745 store_pwm_auto_point_temp_hyst,
746 0, 2),
747 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
748 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
749 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
750 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
751 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
752 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
753
754 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
755 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
756 0, 0),
757 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
759 1, 0),
760 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
761 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
762 2, 0),
763 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
764 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
765 3, 0),
766 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
768 4, 0),
769 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
771 0, 0),
772 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
774 1, 0),
775 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
777 2, 0),
778 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
780 3, 0),
781 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_temp_hyst,
783 store_pwm_auto_point_temp_hyst,
784 0, 0),
785 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
786 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
787 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
788 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
789 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
790 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
791
792 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
793 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
794 0, 1),
795 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
796 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
797 1, 1),
798 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
799 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
800 2, 1),
801 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
802 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
803 3, 1),
804 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
805 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
806 4, 1),
807 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
809 0, 1),
810 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
812 1, 1),
813 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
815 2, 1),
816 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
818 3, 1),
819 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_temp_hyst,
821 store_pwm_auto_point_temp_hyst,
822 0, 1),
823 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
824 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
825 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
826 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
827 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
828 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
829};
Hans de Goede45fb3662007-07-13 14:34:19 +0200830
831/* Super I/O functions */
832static inline int superio_inb(int base, int reg)
833{
834 outb(reg, base);
835 return inb(base + 1);
836}
837
838static int superio_inw(int base, int reg)
839{
840 int val;
841 outb(reg++, base);
842 val = inb(base + 1) << 8;
843 outb(reg, base);
844 val |= inb(base + 1);
845 return val;
846}
847
848static inline void superio_enter(int base)
849{
850 /* according to the datasheet the key must be send twice! */
851 outb( SIO_UNLOCK_KEY, base);
852 outb( SIO_UNLOCK_KEY, base);
853}
854
855static inline void superio_select( int base, int ld)
856{
857 outb(SIO_REG_LDSEL, base);
858 outb(ld, base + 1);
859}
860
861static inline void superio_exit(int base)
862{
863 outb(SIO_LOCK_KEY, base);
864}
865
Hans de Goede2f650632009-01-07 16:37:31 +0100866static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200867{
868 return reg ? (1500000 / reg) : 0;
869}
870
Hans de Goede2f650632009-01-07 16:37:31 +0100871static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100872{
873 return fan ? (1500000 / fan) : 0;
874}
875
Hans de Goede45fb3662007-07-13 14:34:19 +0200876static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
877{
878 u8 val;
879
880 outb(reg, data->addr + ADDR_REG_OFFSET);
881 val = inb(data->addr + DATA_REG_OFFSET);
882
883 return val;
884}
885
886static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
887{
888 u16 val;
889
890 outb(reg++, data->addr + ADDR_REG_OFFSET);
891 val = inb(data->addr + DATA_REG_OFFSET) << 8;
892 outb(reg, data->addr + ADDR_REG_OFFSET);
893 val |= inb(data->addr + DATA_REG_OFFSET);
894
895 return val;
896}
897
898static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
899{
900 outb(reg, data->addr + ADDR_REG_OFFSET);
901 outb(val, data->addr + DATA_REG_OFFSET);
902}
903
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100904static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
905{
906 outb(reg++, data->addr + ADDR_REG_OFFSET);
907 outb(val >> 8, data->addr + DATA_REG_OFFSET);
908 outb(reg, data->addr + ADDR_REG_OFFSET);
909 outb(val & 255, data->addr + DATA_REG_OFFSET);
910}
911
Hans de Goede09475d32009-06-15 18:39:52 +0200912static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
913{
914 if (data->type == f71858fg)
915 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
916 else
917 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
918}
919
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100920static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200921{
922 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100923 int nr, reg = 0, reg2;
924 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200925 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200926
927 mutex_lock(&data->update_lock);
928
929 /* Update once every 60 seconds */
930 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
931 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100932 if (data->type == f71882fg) {
933 data->in1_max =
934 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
935 data->in_beep =
936 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
937 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200938
939 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200940 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200941 data->temp_ovt[nr] = f71882fg_read8(data,
942 F71882FG_REG_TEMP_OVT(nr));
943 data->temp_high[nr] = f71882fg_read8(data,
944 F71882FG_REG_TEMP_HIGH(nr));
945 }
946
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100947 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100948 data->temp_hyst[0] = f71882fg_read8(data,
949 F71882FG_REG_TEMP_HYST(0));
950 data->temp_hyst[1] = f71882fg_read8(data,
951 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200952 }
953
954 if (data->type == f71862fg || data->type == f71882fg) {
955 data->fan_beep = f71882fg_read8(data,
956 F71882FG_REG_FAN_BEEP);
957 data->temp_beep = f71882fg_read8(data,
958 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100959 /* Have to hardcode type, because temp1 is special */
960 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
961 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
962 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
963 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200964 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
965 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100966 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200967 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100968 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goede09475d32009-06-15 18:39:52 +0200969 else if (data->type == f71862fg || data->type == f71882fg)
Hans de Goede7567a042009-01-07 16:37:28 +0100970 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100971 else
Hans de Goede09475d32009-06-15 18:39:52 +0200972 data->temp_type[1] = 2; /* Only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200973
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100974 data->pwm_enable = f71882fg_read8(data,
975 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100976 data->pwm_auto_point_hyst[0] =
977 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
978 data->pwm_auto_point_hyst[1] =
979 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
980
Hans de Goede498be962009-01-07 16:37:28 +0100981 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100982 data->pwm_auto_point_mapping[nr] =
983 f71882fg_read8(data,
984 F71882FG_REG_POINT_MAPPING(nr));
985
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100986 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100987 int point;
988 for (point = 0; point < 5; point++) {
989 data->pwm_auto_point_pwm[nr][point] =
990 f71882fg_read8(data,
991 F71882FG_REG_POINT_PWM
992 (nr, point));
993 }
994 for (point = 0; point < 4; point++) {
995 data->pwm_auto_point_temp[nr][point] =
996 f71882fg_read8(data,
997 F71882FG_REG_POINT_TEMP
998 (nr, point));
999 }
1000 } else {
1001 data->pwm_auto_point_pwm[nr][1] =
1002 f71882fg_read8(data,
1003 F71882FG_REG_POINT_PWM
1004 (nr, 1));
1005 data->pwm_auto_point_pwm[nr][4] =
1006 f71882fg_read8(data,
1007 F71882FG_REG_POINT_PWM
1008 (nr, 4));
1009 data->pwm_auto_point_temp[nr][0] =
1010 f71882fg_read8(data,
1011 F71882FG_REG_POINT_TEMP
1012 (nr, 0));
1013 data->pwm_auto_point_temp[nr][3] =
1014 f71882fg_read8(data,
1015 F71882FG_REG_POINT_TEMP
1016 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001017 }
1018 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001019 data->last_limits = jiffies;
1020 }
1021
1022 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001023 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001024 data->temp_status = f71882fg_read8(data,
1025 F71882FG_REG_TEMP_STATUS);
1026 data->temp_diode_open = f71882fg_read8(data,
1027 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001028 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1029 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001030
1031 data->fan_status = f71882fg_read8(data,
1032 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001033 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001034 data->fan[nr] = f71882fg_read16(data,
1035 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001036 data->fan_target[nr] =
1037 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1038 data->fan_full_speed[nr] =
1039 f71882fg_read16(data,
1040 F71882FG_REG_FAN_FULL_SPEED(nr));
1041 data->pwm[nr] =
1042 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1043 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001044
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001045 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1046 if (data->type == f8000)
1047 data->fan[3] = f71882fg_read16(data,
1048 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +01001049 if (data->type == f71882fg)
1050 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001051 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001052 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001053 data->in[nr] = f71882fg_read8(data,
1054 F71882FG_REG_IN(nr));
1055
1056 data->last_updated = jiffies;
1057 data->valid = 1;
1058 }
1059
1060 mutex_unlock(&data->update_lock);
1061
1062 return data;
1063}
1064
1065/* Sysfs Interface */
1066static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1067 char *buf)
1068{
1069 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001070 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001071 int speed = fan_from_reg(data->fan[nr]);
1072
1073 if (speed == FAN_MIN_DETECT)
1074 speed = 0;
1075
1076 return sprintf(buf, "%d\n", speed);
1077}
1078
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001079static ssize_t show_fan_full_speed(struct device *dev,
1080 struct device_attribute *devattr, char *buf)
1081{
1082 struct f71882fg_data *data = f71882fg_update_device(dev);
1083 int nr = to_sensor_dev_attr_2(devattr)->index;
1084 int speed = fan_from_reg(data->fan_full_speed[nr]);
1085 return sprintf(buf, "%d\n", speed);
1086}
1087
1088static ssize_t store_fan_full_speed(struct device *dev,
1089 struct device_attribute *devattr,
1090 const char *buf, size_t count)
1091{
1092 struct f71882fg_data *data = dev_get_drvdata(dev);
1093 int nr = to_sensor_dev_attr_2(devattr)->index;
1094 long val = simple_strtol(buf, NULL, 10);
1095
1096 val = SENSORS_LIMIT(val, 23, 1500000);
1097 val = fan_to_reg(val);
1098
1099 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001100 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1101 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001102 mutex_unlock(&data->update_lock);
1103
1104 return count;
1105}
1106
Hans de Goede45fb3662007-07-13 14:34:19 +02001107static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1108 *devattr, char *buf)
1109{
1110 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001111 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001112
1113 if (data->fan_beep & (1 << nr))
1114 return sprintf(buf, "1\n");
1115 else
1116 return sprintf(buf, "0\n");
1117}
1118
1119static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1120 *devattr, const char *buf, size_t count)
1121{
1122 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001123 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001124 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001125
1126 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001127 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001128 if (val)
1129 data->fan_beep |= 1 << nr;
1130 else
1131 data->fan_beep &= ~(1 << nr);
1132
1133 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1134 mutex_unlock(&data->update_lock);
1135
1136 return count;
1137}
1138
1139static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1140 *devattr, char *buf)
1141{
1142 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001143 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001144
1145 if (data->fan_status & (1 << nr))
1146 return sprintf(buf, "1\n");
1147 else
1148 return sprintf(buf, "0\n");
1149}
1150
1151static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1152 char *buf)
1153{
1154 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001155 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001156
1157 return sprintf(buf, "%d\n", data->in[nr] * 8);
1158}
1159
1160static ssize_t show_in_max(struct device *dev, struct device_attribute
1161 *devattr, char *buf)
1162{
1163 struct f71882fg_data *data = f71882fg_update_device(dev);
1164
1165 return sprintf(buf, "%d\n", data->in1_max * 8);
1166}
1167
1168static ssize_t store_in_max(struct device *dev, struct device_attribute
1169 *devattr, const char *buf, size_t count)
1170{
1171 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001172 long val = simple_strtol(buf, NULL, 10) / 8;
1173 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001174
1175 mutex_lock(&data->update_lock);
1176 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1177 data->in1_max = val;
1178 mutex_unlock(&data->update_lock);
1179
1180 return count;
1181}
1182
1183static ssize_t show_in_beep(struct device *dev, struct device_attribute
1184 *devattr, char *buf)
1185{
1186 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001187 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001188
1189 if (data->in_beep & (1 << nr))
1190 return sprintf(buf, "1\n");
1191 else
1192 return sprintf(buf, "0\n");
1193}
1194
1195static ssize_t store_in_beep(struct device *dev, struct device_attribute
1196 *devattr, const char *buf, size_t count)
1197{
1198 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001199 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001200 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001201
1202 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001203 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001204 if (val)
1205 data->in_beep |= 1 << nr;
1206 else
1207 data->in_beep &= ~(1 << nr);
1208
1209 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1210 mutex_unlock(&data->update_lock);
1211
1212 return count;
1213}
1214
1215static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1216 *devattr, char *buf)
1217{
1218 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001219 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001220
1221 if (data->in_status & (1 << nr))
1222 return sprintf(buf, "1\n");
1223 else
1224 return sprintf(buf, "0\n");
1225}
1226
1227static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1228 char *buf)
1229{
1230 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001231 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001232 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001233
Hans de Goede09475d32009-06-15 18:39:52 +02001234 if (data->type == f71858fg) {
1235 /* TEMP_TABLE_SEL 1 or 3 ? */
1236 if (data->temp_config & 1) {
1237 sign = data->temp[nr] & 0x0001;
1238 temp = (data->temp[nr] >> 5) & 0x7ff;
1239 } else {
1240 sign = data->temp[nr] & 0x8000;
1241 temp = (data->temp[nr] >> 5) & 0x3ff;
1242 }
1243 temp *= 125;
1244 if (sign)
1245 temp -= 128000;
1246 } else
1247 temp = data->temp[nr] * 1000;
1248
1249 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001250}
1251
1252static ssize_t show_temp_max(struct device *dev, struct device_attribute
1253 *devattr, char *buf)
1254{
1255 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001256 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001257
1258 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1259}
1260
1261static ssize_t store_temp_max(struct device *dev, struct device_attribute
1262 *devattr, const char *buf, size_t count)
1263{
1264 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001265 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001266 long val = simple_strtol(buf, NULL, 10) / 1000;
1267 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001268
1269 mutex_lock(&data->update_lock);
1270 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1271 data->temp_high[nr] = val;
1272 mutex_unlock(&data->update_lock);
1273
1274 return count;
1275}
1276
1277static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1278 *devattr, char *buf)
1279{
1280 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001281 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001282 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001283
Hans de Goedece0bfa52009-01-07 16:37:28 +01001284 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001285 if (nr & 1)
1286 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1287 else
1288 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1289 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001290 mutex_unlock(&data->update_lock);
1291
1292 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001293}
1294
1295static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1296 *devattr, const char *buf, size_t count)
1297{
1298 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001299 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001300 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001301 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001302 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001303
1304 mutex_lock(&data->update_lock);
1305
1306 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001307 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1308 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1309 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001310 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001311
1312 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001313 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1314 if (nr & 1)
1315 reg = (reg & 0x0f) | (val << 4);
1316 else
1317 reg = (reg & 0xf0) | val;
1318 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1319 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001320
Hans de Goede45fb3662007-07-13 14:34:19 +02001321 mutex_unlock(&data->update_lock);
1322 return ret;
1323}
1324
1325static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1326 *devattr, char *buf)
1327{
1328 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001329 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001330
1331 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1332}
1333
1334static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1335 *devattr, const char *buf, size_t count)
1336{
1337 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001338 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001339 long val = simple_strtol(buf, NULL, 10) / 1000;
1340 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001341
1342 mutex_lock(&data->update_lock);
1343 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1344 data->temp_ovt[nr] = val;
1345 mutex_unlock(&data->update_lock);
1346
1347 return count;
1348}
1349
1350static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1351 *devattr, char *buf)
1352{
1353 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001354 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001355 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001356
Hans de Goedece0bfa52009-01-07 16:37:28 +01001357 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001358 if (nr & 1)
1359 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1360 else
1361 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1362 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001363 mutex_unlock(&data->update_lock);
1364
1365 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001366}
1367
1368static ssize_t show_temp_type(struct device *dev, struct device_attribute
1369 *devattr, char *buf)
1370{
1371 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001372 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001373
1374 return sprintf(buf, "%d\n", data->temp_type[nr]);
1375}
1376
1377static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1378 *devattr, char *buf)
1379{
1380 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001381 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001382
Hans de Goede7567a042009-01-07 16:37:28 +01001383 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001384 return sprintf(buf, "1\n");
1385 else
1386 return sprintf(buf, "0\n");
1387}
1388
1389static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1390 *devattr, const char *buf, size_t count)
1391{
1392 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001393 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001394 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001395
1396 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001397 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001398 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001399 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001400 else
Hans de Goede7567a042009-01-07 16:37:28 +01001401 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001402
1403 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1404 mutex_unlock(&data->update_lock);
1405
1406 return count;
1407}
1408
1409static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1410 *devattr, char *buf)
1411{
1412 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001413 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001414
Hans de Goede7567a042009-01-07 16:37:28 +01001415 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001416 return sprintf(buf, "1\n");
1417 else
1418 return sprintf(buf, "0\n");
1419}
1420
1421static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1422 *devattr, char *buf)
1423{
1424 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001425 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001426
Hans de Goede7567a042009-01-07 16:37:28 +01001427 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001428 return sprintf(buf, "1\n");
1429 else
1430 return sprintf(buf, "0\n");
1431}
1432
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001433static ssize_t show_pwm(struct device *dev,
1434 struct device_attribute *devattr, char *buf)
1435{
1436 struct f71882fg_data *data = f71882fg_update_device(dev);
1437 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001438 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001439 if (data->pwm_enable & (1 << (2 * nr)))
1440 /* PWM mode */
1441 val = data->pwm[nr];
1442 else {
1443 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001444 val = 255 * fan_from_reg(data->fan_target[nr])
1445 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001446 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001447 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001448 return sprintf(buf, "%d\n", val);
1449}
1450
1451static ssize_t store_pwm(struct device *dev,
1452 struct device_attribute *devattr, const char *buf,
1453 size_t count)
1454{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001455 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001456 int nr = to_sensor_dev_attr_2(devattr)->index;
1457 long val = simple_strtol(buf, NULL, 10);
1458 val = SENSORS_LIMIT(val, 0, 255);
1459
1460 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001461 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001462 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1463 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1464 count = -EROFS;
1465 goto leave;
1466 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001467 if (data->pwm_enable & (1 << (2 * nr))) {
1468 /* PWM mode */
1469 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1470 data->pwm[nr] = val;
1471 } else {
1472 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001473 int target, full_speed;
1474 full_speed = f71882fg_read16(data,
1475 F71882FG_REG_FAN_FULL_SPEED(nr));
1476 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1477 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1478 data->fan_target[nr] = target;
1479 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001480 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001481leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001482 mutex_unlock(&data->update_lock);
1483
1484 return count;
1485}
1486
1487static ssize_t show_pwm_enable(struct device *dev,
1488 struct device_attribute *devattr, char *buf)
1489{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001490 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001491 struct f71882fg_data *data = f71882fg_update_device(dev);
1492 int nr = to_sensor_dev_attr_2(devattr)->index;
1493
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001494 switch ((data->pwm_enable >> 2 * nr) & 3) {
1495 case 0:
1496 case 1:
1497 result = 2; /* Normal auto mode */
1498 break;
1499 case 2:
1500 result = 1; /* Manual mode */
1501 break;
1502 case 3:
1503 if (data->type == f8000)
1504 result = 3; /* Thermostat mode */
1505 else
1506 result = 1; /* Manual mode */
1507 break;
1508 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001509
1510 return sprintf(buf, "%d\n", result);
1511}
1512
1513static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1514 *devattr, const char *buf, size_t count)
1515{
1516 struct f71882fg_data *data = dev_get_drvdata(dev);
1517 int nr = to_sensor_dev_attr_2(devattr)->index;
1518 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001519
Hans de Goede3fc78382009-06-15 18:39:50 +02001520 /* Special case for F8000 pwm channel 3 which only does auto mode */
1521 if (data->type == f8000 && nr == 2 && val != 2)
1522 return -EINVAL;
1523
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001524 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001525 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001526 /* Special case for F8000 auto PWM mode / Thermostat mode */
1527 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1528 switch (val) {
1529 case 2:
1530 data->pwm_enable &= ~(2 << (2 * nr));
1531 break; /* Normal auto mode */
1532 case 3:
1533 data->pwm_enable |= 2 << (2 * nr);
1534 break; /* Thermostat mode */
1535 default:
1536 count = -EINVAL;
1537 goto leave;
1538 }
1539 } else {
1540 switch (val) {
1541 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001542 /* The f71858fg does not support manual RPM mode */
1543 if (data->type == f71858fg &&
1544 ((data->pwm_enable >> (2 * nr)) & 1)) {
1545 count = -EINVAL;
1546 goto leave;
1547 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001548 data->pwm_enable |= 2 << (2 * nr);
1549 break; /* Manual */
1550 case 2:
1551 data->pwm_enable &= ~(2 << (2 * nr));
1552 break; /* Normal auto mode */
1553 default:
1554 count = -EINVAL;
1555 goto leave;
1556 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001557 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001558 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001559leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001560 mutex_unlock(&data->update_lock);
1561
1562 return count;
1563}
1564
1565static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1566 struct device_attribute *devattr,
1567 char *buf)
1568{
1569 int result;
1570 struct f71882fg_data *data = f71882fg_update_device(dev);
1571 int pwm = to_sensor_dev_attr_2(devattr)->index;
1572 int point = to_sensor_dev_attr_2(devattr)->nr;
1573
Hans de Goedece0bfa52009-01-07 16:37:28 +01001574 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001575 if (data->pwm_enable & (1 << (2 * pwm))) {
1576 /* PWM mode */
1577 result = data->pwm_auto_point_pwm[pwm][point];
1578 } else {
1579 /* RPM mode */
1580 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1581 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001582 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001583
1584 return sprintf(buf, "%d\n", result);
1585}
1586
1587static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1588 struct device_attribute *devattr,
1589 const char *buf, size_t count)
1590{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001591 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001592 int pwm = to_sensor_dev_attr_2(devattr)->index;
1593 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001594 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001595 val = SENSORS_LIMIT(val, 0, 255);
1596
1597 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001598 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001599 if (data->pwm_enable & (1 << (2 * pwm))) {
1600 /* PWM mode */
1601 } else {
1602 /* RPM mode */
1603 if (val < 29) /* Prevent negative numbers */
1604 val = 255;
1605 else
1606 val = (255 - val) * 32 / val;
1607 }
1608 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1609 data->pwm_auto_point_pwm[pwm][point] = val;
1610 mutex_unlock(&data->update_lock);
1611
1612 return count;
1613}
1614
1615static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1616 struct device_attribute *devattr,
1617 char *buf)
1618{
1619 int result = 0;
1620 struct f71882fg_data *data = f71882fg_update_device(dev);
1621 int nr = to_sensor_dev_attr_2(devattr)->index;
1622 int point = to_sensor_dev_attr_2(devattr)->nr;
1623
1624 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001625 if (nr & 1)
1626 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1627 else
1628 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001629 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1630 mutex_unlock(&data->update_lock);
1631
1632 return sprintf(buf, "%d\n", result);
1633}
1634
1635static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1636 struct device_attribute *devattr,
1637 const char *buf, size_t count)
1638{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001639 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001640 int nr = to_sensor_dev_attr_2(devattr)->index;
1641 int point = to_sensor_dev_attr_2(devattr)->nr;
1642 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001643 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001644
1645 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001646 data->pwm_auto_point_temp[nr][point] =
1647 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001648 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1649 data->pwm_auto_point_temp[nr][point]);
1650 val = data->pwm_auto_point_temp[nr][point] - val;
1651
Hans de Goedebc274902009-01-07 16:37:29 +01001652 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1653 if (nr & 1)
1654 reg = (reg & 0x0f) | (val << 4);
1655 else
1656 reg = (reg & 0xf0) | val;
1657
1658 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1659 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001660 mutex_unlock(&data->update_lock);
1661
1662 return count;
1663}
1664
1665static ssize_t show_pwm_interpolate(struct device *dev,
1666 struct device_attribute *devattr, char *buf)
1667{
1668 int result;
1669 struct f71882fg_data *data = f71882fg_update_device(dev);
1670 int nr = to_sensor_dev_attr_2(devattr)->index;
1671
1672 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1673
1674 return sprintf(buf, "%d\n", result);
1675}
1676
1677static ssize_t store_pwm_interpolate(struct device *dev,
1678 struct device_attribute *devattr,
1679 const char *buf, size_t count)
1680{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001681 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001682 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001683 unsigned long val = simple_strtoul(buf, NULL, 10);
1684
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001685 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001686 data->pwm_auto_point_mapping[nr] =
1687 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001688 if (val)
1689 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1690 else
1691 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1692 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1693 data->pwm_auto_point_mapping[nr] = val;
1694 mutex_unlock(&data->update_lock);
1695
1696 return count;
1697}
1698
1699static ssize_t show_pwm_auto_point_channel(struct device *dev,
1700 struct device_attribute *devattr,
1701 char *buf)
1702{
1703 int result;
1704 struct f71882fg_data *data = f71882fg_update_device(dev);
1705 int nr = to_sensor_dev_attr_2(devattr)->index;
1706
Hans de Goede09475d32009-06-15 18:39:52 +02001707 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1708 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001709
1710 return sprintf(buf, "%d\n", result);
1711}
1712
1713static ssize_t store_pwm_auto_point_channel(struct device *dev,
1714 struct device_attribute *devattr,
1715 const char *buf, size_t count)
1716{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001717 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001718 int nr = to_sensor_dev_attr_2(devattr)->index;
1719 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001720
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001721 switch (val) {
1722 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001723 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001724 break;
1725 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001726 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001727 break;
1728 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001729 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001730 break;
1731 default:
1732 return -EINVAL;
1733 }
Hans de Goede09475d32009-06-15 18:39:52 +02001734 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001735 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001736 data->pwm_auto_point_mapping[nr] =
1737 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001738 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1739 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1740 data->pwm_auto_point_mapping[nr] = val;
1741 mutex_unlock(&data->update_lock);
1742
1743 return count;
1744}
1745
1746static ssize_t show_pwm_auto_point_temp(struct device *dev,
1747 struct device_attribute *devattr,
1748 char *buf)
1749{
1750 int result;
1751 struct f71882fg_data *data = f71882fg_update_device(dev);
1752 int pwm = to_sensor_dev_attr_2(devattr)->index;
1753 int point = to_sensor_dev_attr_2(devattr)->nr;
1754
1755 result = data->pwm_auto_point_temp[pwm][point];
1756 return sprintf(buf, "%d\n", 1000 * result);
1757}
1758
1759static ssize_t store_pwm_auto_point_temp(struct device *dev,
1760 struct device_attribute *devattr,
1761 const char *buf, size_t count)
1762{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001763 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001764 int pwm = to_sensor_dev_attr_2(devattr)->index;
1765 int point = to_sensor_dev_attr_2(devattr)->nr;
1766 long val = simple_strtol(buf, NULL, 10) / 1000;
1767 val = SENSORS_LIMIT(val, 0, 255);
1768
1769 mutex_lock(&data->update_lock);
1770 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1771 data->pwm_auto_point_temp[pwm][point] = val;
1772 mutex_unlock(&data->update_lock);
1773
1774 return count;
1775}
1776
Hans de Goede45fb3662007-07-13 14:34:19 +02001777static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1778 char *buf)
1779{
Hans de Goede498be962009-01-07 16:37:28 +01001780 struct f71882fg_data *data = dev_get_drvdata(dev);
1781 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001782}
1783
Hans de Goedec13548c2009-01-07 16:37:27 +01001784static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1785 struct sensor_device_attribute_2 *attr, int count)
1786{
1787 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001788
Hans de Goedec13548c2009-01-07 16:37:27 +01001789 for (i = 0; i < count; i++) {
1790 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1791 if (err)
1792 return err;
1793 }
1794 return 0;
1795}
1796
1797static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001798{
1799 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001800 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001801 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001802 u8 start_reg;
1803
Hans de Goedec13548c2009-01-07 16:37:27 +01001804 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1805 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001806 return -ENOMEM;
1807
1808 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001809 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001810 data->temp_start =
1811 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001812 mutex_init(&data->update_lock);
1813 platform_set_drvdata(pdev, data);
1814
Hans de Goede3cc74752009-01-07 16:37:28 +01001815 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001816 if (start_reg & 0x04) {
1817 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1818 err = -ENODEV;
1819 goto exit_free;
1820 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001821 if (!(start_reg & 0x03)) {
1822 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1823 err = -ENODEV;
1824 goto exit_free;
1825 }
1826
Hans de Goede45fb3662007-07-13 14:34:19 +02001827 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001828 err = device_create_file(&pdev->dev, &dev_attr_name);
1829 if (err)
1830 goto exit_unregister_sysfs;
1831
Hans de Goedec13548c2009-01-07 16:37:27 +01001832 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001833 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001834 case f71858fg:
1835 data->temp_config =
1836 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1837 if (data->temp_config & 0x10)
1838 /* The f71858fg temperature alarms behave as
1839 the f8000 alarms in this mode */
1840 err = f71882fg_create_sysfs_files(pdev,
1841 f8000_in_temp_attr,
1842 ARRAY_SIZE(f8000_in_temp_attr));
1843 else
1844 err = f71882fg_create_sysfs_files(pdev,
1845 f71858fg_in_temp_attr,
1846 ARRAY_SIZE(f71858fg_in_temp_attr));
1847 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001848 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001849 err = f71882fg_create_sysfs_files(pdev,
1850 f71882fg_in_temp_attr,
1851 ARRAY_SIZE(f71882fg_in_temp_attr));
1852 if (err)
1853 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001854 /* fall through! */
1855 case f71862fg:
1856 err = f71882fg_create_sysfs_files(pdev,
1857 f718x2fg_in_temp_attr,
1858 ARRAY_SIZE(f718x2fg_in_temp_attr));
1859 break;
1860 case f8000:
1861 err = f71882fg_create_sysfs_files(pdev,
1862 f8000_in_temp_attr,
1863 ARRAY_SIZE(f8000_in_temp_attr));
1864 break;
Hans de Goede498be962009-01-07 16:37:28 +01001865 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001866 if (err)
1867 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001868 }
1869
Hans de Goede45fb3662007-07-13 14:34:19 +02001870 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001871 data->pwm_enable =
1872 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1873
1874 /* Sanity check the pwm settings */
1875 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001876 case f71858fg:
1877 err = 0;
1878 for (i = 0; i < nr_fans; i++)
1879 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1880 err = 1;
1881 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001882 case f71862fg:
1883 err = (data->pwm_enable & 0x15) != 0x15;
1884 break;
1885 case f71882fg:
1886 err = 0;
1887 break;
1888 case f8000:
1889 err = data->pwm_enable & 0x20;
1890 break;
1891 }
1892 if (err) {
1893 dev_err(&pdev->dev,
1894 "Invalid (reserved) pwm settings: 0x%02x\n",
1895 (unsigned int)data->pwm_enable);
1896 err = -ENODEV;
1897 goto exit_unregister_sysfs;
1898 }
1899
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001900 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1901 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001902 if (err)
1903 goto exit_unregister_sysfs;
1904
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001905 switch (data->type) {
1906 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001907 err = f71882fg_create_sysfs_files(pdev,
1908 f71862fg_fan_attr,
1909 ARRAY_SIZE(f71862fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001910 break;
1911 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001912 err = f71882fg_create_sysfs_files(pdev,
1913 f71882fg_fan_attr,
Hans de Goedec13548c2009-01-07 16:37:27 +01001914 ARRAY_SIZE(f71882fg_fan_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001915 if (err)
1916 goto exit_unregister_sysfs;
1917 /* fall through! */
1918 case f71858fg:
1919 err = f71882fg_create_sysfs_files(pdev,
1920 f71882fg_f71858fg_fan_attr,
1921 ARRAY_SIZE(f71882fg_f71858fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001922 break;
1923 case f8000:
1924 err = f71882fg_create_sysfs_files(pdev,
1925 f8000_fan_attr,
1926 ARRAY_SIZE(f8000_fan_attr));
1927 break;
Hans de Goede498be962009-01-07 16:37:28 +01001928 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001929 if (err)
1930 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001931
1932 for (i = 0; i < nr_fans; i++)
1933 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1934 (data->pwm_enable & (1 << 2 * i)) ?
1935 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001936 }
1937
Tony Jones1beeffe2007-08-20 13:46:20 -07001938 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1939 if (IS_ERR(data->hwmon_dev)) {
1940 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001941 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001942 goto exit_unregister_sysfs;
1943 }
1944
1945 return 0;
1946
1947exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001948 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001949 return err; /* f71882fg_remove() also frees our data */
1950exit_free:
1951 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001952 return err;
1953}
1954
Hans de Goedec13548c2009-01-07 16:37:27 +01001955static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001956{
1957 int i;
1958 struct f71882fg_data *data = platform_get_drvdata(pdev);
1959
1960 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001961 if (data->hwmon_dev)
1962 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001963
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001964 /* Note we are not looping over all attr arrays we have as the ones
1965 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001966 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001967
Hans de Goede498be962009-01-07 16:37:28 +01001968 for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
1969 device_remove_file(&pdev->dev,
1970 &f718x2fg_in_temp_attr[i].dev_attr);
1971
Hans de Goede45fb3662007-07-13 14:34:19 +02001972 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1973 device_remove_file(&pdev->dev,
1974 &f71882fg_in_temp_attr[i].dev_attr);
1975
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001976 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
1977 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001978
Hans de Goede45fb3662007-07-13 14:34:19 +02001979 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1980 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1981
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001982 for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
1983 device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
1984
Hans de Goede45fb3662007-07-13 14:34:19 +02001985 kfree(data);
1986
1987 return 0;
1988}
1989
Hans de Goede498be962009-01-07 16:37:28 +01001990static int __init f71882fg_find(int sioaddr, unsigned short *address,
1991 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001992{
1993 int err = -ENODEV;
1994 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02001995
1996 superio_enter(sioaddr);
1997
1998 devid = superio_inw(sioaddr, SIO_REG_MANID);
1999 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002000 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002001 goto exit;
2002 }
2003
Jean Delvare67b671b2007-12-06 23:13:42 +01002004 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002005 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002006 case SIO_F71858_ID:
2007 sio_data->type = f71858fg;
2008 break;
Hans de Goede498be962009-01-07 16:37:28 +01002009 case SIO_F71862_ID:
2010 sio_data->type = f71862fg;
2011 break;
2012 case SIO_F71882_ID:
2013 sio_data->type = f71882fg;
2014 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002015 case SIO_F8000_ID:
2016 sio_data->type = f8000;
2017 break;
Hans de Goede498be962009-01-07 16:37:28 +01002018 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02002019 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
2020 goto exit;
2021 }
2022
Hans de Goede09475d32009-06-15 18:39:52 +02002023 if (sio_data->type == f71858fg)
2024 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2025 else
2026 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2027
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002028 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002029 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2030 goto exit;
2031 }
2032
2033 *address = superio_inw(sioaddr, SIO_REG_ADDR);
2034 if (*address == 0)
2035 {
2036 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2037 goto exit;
2038 }
2039 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2040
Hans de Goede45fb3662007-07-13 14:34:19 +02002041 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002042 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2043 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002044 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2045exit:
2046 superio_exit(sioaddr);
2047 return err;
2048}
2049
Hans de Goede498be962009-01-07 16:37:28 +01002050static int __init f71882fg_device_add(unsigned short address,
2051 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002052{
2053 struct resource res = {
2054 .start = address,
2055 .end = address + REGION_LENGTH - 1,
2056 .flags = IORESOURCE_IO,
2057 };
2058 int err;
2059
2060 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002061 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002062 return -ENOMEM;
2063
2064 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002065 err = acpi_check_resource_conflict(&res);
2066 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002067 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002068
Hans de Goede45fb3662007-07-13 14:34:19 +02002069 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002070 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002071 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2072 goto exit_device_put;
2073 }
2074
Hans de Goede498be962009-01-07 16:37:28 +01002075 err = platform_device_add_data(f71882fg_pdev, sio_data,
2076 sizeof(struct f71882fg_sio_data));
2077 if (err) {
2078 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2079 goto exit_device_put;
2080 }
2081
Hans de Goede45fb3662007-07-13 14:34:19 +02002082 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002083 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002084 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2085 goto exit_device_put;
2086 }
2087
2088 return 0;
2089
2090exit_device_put:
2091 platform_device_put(f71882fg_pdev);
2092
2093 return err;
2094}
2095
2096static int __init f71882fg_init(void)
2097{
2098 int err = -ENODEV;
2099 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002100 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002101
Hans de Goede498be962009-01-07 16:37:28 +01002102 memset(&sio_data, 0, sizeof(sio_data));
2103
2104 if (f71882fg_find(0x2e, &address, &sio_data) &&
2105 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002106 goto exit;
2107
Hans de Goedec13548c2009-01-07 16:37:27 +01002108 err = platform_driver_register(&f71882fg_driver);
2109 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002110 goto exit;
2111
Hans de Goede498be962009-01-07 16:37:28 +01002112 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002113 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002114 goto exit_driver;
2115
2116 return 0;
2117
2118exit_driver:
2119 platform_driver_unregister(&f71882fg_driver);
2120exit:
2121 return err;
2122}
2123
2124static void __exit f71882fg_exit(void)
2125{
2126 platform_device_unregister(f71882fg_pdev);
2127 platform_driver_unregister(&f71882fg_driver);
2128}
2129
2130MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002131MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002132MODULE_LICENSE("GPL");
2133
2134module_init(f71882fg_init);
2135module_exit(f71882fg_exit);