blob: 5f81ddf7150871e67c7fe3ff1647df7e01c6c2c5 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goedec13548c2009-01-07 16:37:27 +01003 * Copyright (C) 2007,2008 by 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
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010035#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020036#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
37#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
38
39#define SIO_REG_LDSEL 0x07 /* Logical device select */
40#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
41#define SIO_REG_DEVREV 0x22 /* Device revision */
42#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
43#define SIO_REG_ENABLE 0x30 /* Logical device enable */
44#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
45
46#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede498be962009-01-07 16:37:28 +010047#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020048#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010049#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020050
51#define REGION_LENGTH 8
52#define ADDR_REG_OFFSET 5
53#define DATA_REG_OFFSET 6
54
55#define F71882FG_REG_PECI 0x0A
56
Hans de Goede498be962009-01-07 16:37:28 +010057#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
58#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020059#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020061
62#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010063#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
64#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020065#define F71882FG_REG_FAN_STATUS 0x92
66#define F71882FG_REG_FAN_BEEP 0x93
67
Hans de Goede7567a042009-01-07 16:37:28 +010068#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
69#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
70#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020071#define F71882FG_REG_TEMP_STATUS 0x62
72#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goedebc274902009-01-07 16:37:29 +010073#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_TYPE 0x6B
75#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
76
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010077#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
78#define F71882FG_REG_PWM_TYPE 0x94
79#define F71882FG_REG_PWM_ENABLE 0x96
80
Hans de Goedebc274902009-01-07 16:37:29 +010081#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010082
83#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
84#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
85#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
86
Hans de Goede45fb3662007-07-13 14:34:19 +020087#define F71882FG_REG_START 0x01
88
89#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
90
Jean Delvare67b671b2007-12-06 23:13:42 +010091static unsigned short force_id;
92module_param(force_id, ushort, 0);
93MODULE_PARM_DESC(force_id, "Override the detected device ID");
94
Hans de Goedeed4f7c22009-01-07 16:37:30 +010095enum chips { f71862fg, f71882fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +010096
97static const char *f71882fg_names[] = {
98 "f71862fg",
99 "f71882fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100100 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100101};
102
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100103static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200104
105/* Super-I/O Function prototypes */
106static inline int superio_inb(int base, int reg);
107static inline int superio_inw(int base, int reg);
108static inline void superio_enter(int base);
109static inline void superio_select(int base, int ld);
110static inline void superio_exit(int base);
111
Hans de Goede498be962009-01-07 16:37:28 +0100112struct f71882fg_sio_data {
113 enum chips type;
114};
115
Hans de Goede45fb3662007-07-13 14:34:19 +0200116struct f71882fg_data {
117 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100118 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700119 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200120
121 struct mutex update_lock;
122 char valid; /* !=0 if following fields are valid */
123 unsigned long last_updated; /* In jiffies */
124 unsigned long last_limits; /* In jiffies */
125
126 /* Register Values */
127 u8 in[9];
128 u8 in1_max;
129 u8 in_status;
130 u8 in_beep;
131 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100132 u16 fan_target[4];
133 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200134 u8 fan_status;
135 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100136 /* Note: all models have only 3 temperature channels, but on some
137 they are addressed as 0-2 and on others as 1-3, so for coding
138 convenience we reserve space for 4 channels */
139 u8 temp[4];
140 u8 temp_ovt[4];
141 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100142 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100143 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200144 u8 temp_status;
145 u8 temp_beep;
146 u8 temp_diode_open;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100147 u8 pwm[4];
148 u8 pwm_enable;
149 u8 pwm_auto_point_hyst[2];
150 u8 pwm_auto_point_mapping[4];
151 u8 pwm_auto_point_pwm[4][5];
152 u8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200153};
154
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100155/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200156static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
157 char *buf);
158static ssize_t show_in_max(struct device *dev, struct device_attribute
159 *devattr, char *buf);
160static ssize_t store_in_max(struct device *dev, struct device_attribute
161 *devattr, const char *buf, size_t count);
162static ssize_t show_in_beep(struct device *dev, struct device_attribute
163 *devattr, char *buf);
164static ssize_t store_in_beep(struct device *dev, struct device_attribute
165 *devattr, const char *buf, size_t count);
166static ssize_t show_in_alarm(struct device *dev, struct device_attribute
167 *devattr, char *buf);
168/* Sysfs Fan */
169static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
170 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100171static ssize_t show_fan_full_speed(struct device *dev,
172 struct device_attribute *devattr, char *buf);
173static ssize_t store_fan_full_speed(struct device *dev,
174 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200175static ssize_t show_fan_beep(struct device *dev, struct device_attribute
176 *devattr, char *buf);
177static ssize_t store_fan_beep(struct device *dev, struct device_attribute
178 *devattr, const char *buf, size_t count);
179static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
180 *devattr, char *buf);
181/* Sysfs Temp */
182static ssize_t show_temp(struct device *dev, struct device_attribute
183 *devattr, char *buf);
184static ssize_t show_temp_max(struct device *dev, struct device_attribute
185 *devattr, char *buf);
186static ssize_t store_temp_max(struct device *dev, struct device_attribute
187 *devattr, const char *buf, size_t count);
188static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
189 *devattr, char *buf);
190static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
191 *devattr, const char *buf, size_t count);
192static ssize_t show_temp_crit(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t store_temp_crit(struct device *dev, struct device_attribute
195 *devattr, const char *buf, size_t count);
196static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t show_temp_type(struct device *dev, struct device_attribute
199 *devattr, char *buf);
200static ssize_t show_temp_beep(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_temp_beep(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_fault(struct device *dev, struct device_attribute
207 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100208/* PWM and Auto point control */
209static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
210 char *buf);
211static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
212 const char *buf, size_t count);
213static ssize_t show_pwm_enable(struct device *dev,
214 struct device_attribute *devattr, char *buf);
215static ssize_t store_pwm_enable(struct device *dev,
216 struct device_attribute *devattr, const char *buf, size_t count);
217static ssize_t show_pwm_interpolate(struct device *dev,
218 struct device_attribute *devattr, char *buf);
219static ssize_t store_pwm_interpolate(struct device *dev,
220 struct device_attribute *devattr, const char *buf, size_t count);
221static ssize_t show_pwm_auto_point_channel(struct device *dev,
222 struct device_attribute *devattr, char *buf);
223static ssize_t store_pwm_auto_point_channel(struct device *dev,
224 struct device_attribute *devattr, const char *buf, size_t count);
225static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
226 struct device_attribute *devattr, char *buf);
227static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
228 struct device_attribute *devattr, const char *buf, size_t count);
229static ssize_t show_pwm_auto_point_pwm(struct device *dev,
230 struct device_attribute *devattr, char *buf);
231static ssize_t store_pwm_auto_point_pwm(struct device *dev,
232 struct device_attribute *devattr, const char *buf, size_t count);
233static ssize_t show_pwm_auto_point_temp(struct device *dev,
234 struct device_attribute *devattr, char *buf);
235static ssize_t store_pwm_auto_point_temp(struct device *dev,
236 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200237/* Sysfs misc */
238static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
239 char *buf);
240
241static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100242static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200243
244static struct platform_driver f71882fg_driver = {
245 .driver = {
246 .owner = THIS_MODULE,
247 .name = DRVNAME,
248 },
249 .probe = f71882fg_probe,
250 .remove = __devexit_p(f71882fg_remove),
251};
252
Hans de Goedec13548c2009-01-07 16:37:27 +0100253static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200254
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100255/* Temp and in attr common to both the f71862fg and f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100256static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100257 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
258 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100259 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
260 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
261 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
262 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
263 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
264 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
265 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100266 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100267 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100268 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100269 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100270 store_temp_max_hyst, 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100271 /* Should really be temp1_max_alarm, but older versions did not handle
272 the max and crit alarms separately and lm_sensors v2 depends on the
273 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
274 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
275 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
276 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100277 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100278 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100279 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100280 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100281 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
282 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
283 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100284 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100285 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
286 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
287 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100288 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100289 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100290 store_temp_max_hyst, 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100291 /* Should be temp2_max_alarm, see temp1_alarm note */
292 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
293 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
294 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100295 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100296 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100297 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100298 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100299 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
300 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
301 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100302 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100303 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
304 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
305 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
306 store_temp_max, 0, 3),
307 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
308 store_temp_max_hyst, 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100309 /* Should be temp3_max_alarm, see temp1_alarm note */
310 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
311 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
312 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100313 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
314 store_temp_crit, 0, 3),
315 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
316 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100317 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
318 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
319 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100320 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100321 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200322};
323
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100324/* Temp and in attr found only on the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100325static struct sensor_device_attribute_2 f71882fg_in_temp_attr[] = {
326 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
327 0, 1),
328 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
329 0, 1),
330 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
331};
332
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100333/* Temp and in attr for the f8000
334 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
335 is used as hysteresis value to clear alarms
336 */
337static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
338 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
339 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
340 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
341 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
342 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
343 store_temp_crit, 0, 0),
344 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
345 store_temp_max, 0, 0),
346 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
347 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
348 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
349 store_temp_crit, 0, 1),
350 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
351 store_temp_max, 0, 1),
352 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
353 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
354 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
355 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
356 store_temp_crit, 0, 2),
357 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
358 store_temp_max, 0, 2),
359 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
360};
361
362/* Fan / PWM attr common to all models */
363static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100364 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100365 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
366 show_fan_full_speed,
367 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100368 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
369 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100370 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
371 show_fan_full_speed,
372 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100373 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
374 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100375 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
376 show_fan_full_speed,
377 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100378 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100379
380 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
381 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
382 store_pwm_enable, 0, 0),
383 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
384 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
385 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
386 show_pwm_auto_point_channel,
387 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100388
389 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
390 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
391 store_pwm_enable, 0, 1),
392 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
393 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
394 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
395 show_pwm_auto_point_channel,
396 store_pwm_auto_point_channel, 0, 1),
397
Hans de Goede498be962009-01-07 16:37:28 +0100398 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
399 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
400 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
401 show_pwm_auto_point_channel,
402 store_pwm_auto_point_channel, 0, 2),
403};
404
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100405/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
406 f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100407static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100408 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
409 store_fan_beep, 0, 0),
410 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
411 store_fan_beep, 0, 1),
412 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
413 store_fan_beep, 0, 2),
414
Hans de Goede498be962009-01-07 16:37:28 +0100415 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
416 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
417 1, 0),
418 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
419 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
420 4, 0),
421 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
422 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
423 0, 0),
424 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
425 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
426 3, 0),
427 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
428 show_pwm_auto_point_temp_hyst,
429 store_pwm_auto_point_temp_hyst,
430 0, 0),
431 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
432 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
433
434 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
435 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
436 1, 1),
437 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
438 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
439 4, 1),
440 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
441 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
442 0, 1),
443 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
444 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
445 3, 1),
446 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
447 show_pwm_auto_point_temp_hyst,
448 store_pwm_auto_point_temp_hyst,
449 0, 1),
450 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
451 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100452
453 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
454 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
455 store_pwm_enable, 0, 2),
456 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
457 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
458 1, 2),
459 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
460 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
461 4, 2),
462 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
463 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
464 0, 2),
465 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
466 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
467 3, 2),
468 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
469 show_pwm_auto_point_temp_hyst,
470 store_pwm_auto_point_temp_hyst,
471 0, 2),
472 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
473 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100474};
475
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100476/* Fan / PWM attr for the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100477static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100478 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
479 store_fan_beep, 0, 0),
480 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
481 store_fan_beep, 0, 1),
482 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
483 store_fan_beep, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100484 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
485 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
486 show_fan_full_speed,
487 store_fan_full_speed, 0, 3),
488 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
489 store_fan_beep, 0, 3),
490 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
491
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100492 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
493 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
494 0, 0),
495 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
496 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
497 1, 0),
498 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
499 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
500 2, 0),
501 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
502 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
503 3, 0),
504 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
506 4, 0),
507 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
509 0, 0),
510 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
512 1, 0),
513 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 2, 0),
516 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 3, 0),
519 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp_hyst,
521 store_pwm_auto_point_temp_hyst,
522 0, 0),
523 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
524 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
525 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
526 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
527 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
528 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
529
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100530 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
531 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
532 0, 1),
533 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
534 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
535 1, 1),
536 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
537 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
538 2, 1),
539 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
540 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
541 3, 1),
542 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
543 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
544 4, 1),
545 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
546 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
547 0, 1),
548 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
549 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
550 1, 1),
551 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
553 2, 1),
554 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
556 3, 1),
557 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_temp_hyst,
559 store_pwm_auto_point_temp_hyst,
560 0, 1),
561 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
562 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
563 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
564 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
565 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
566 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
567
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100568 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
569 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
570 store_pwm_enable, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100571 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
572 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
573 0, 2),
574 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
575 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
576 1, 2),
577 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
578 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
579 2, 2),
580 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
581 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
582 3, 2),
583 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
584 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
585 4, 2),
586 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
587 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
588 0, 2),
589 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
590 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
591 1, 2),
592 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
593 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
594 2, 2),
595 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
596 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
597 3, 2),
598 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
599 show_pwm_auto_point_temp_hyst,
600 store_pwm_auto_point_temp_hyst,
601 0, 2),
602 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
603 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
604 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
605 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
606 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
607 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
608
609 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
610 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
611 store_pwm_enable, 0, 3),
612 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
613 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
614 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_channel,
616 store_pwm_auto_point_channel, 0, 3),
617 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
619 0, 3),
620 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
622 1, 3),
623 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
625 2, 3),
626 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
628 3, 3),
629 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
630 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
631 4, 3),
632 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
633 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
634 0, 3),
635 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
637 1, 3),
638 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
640 2, 3),
641 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
642 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
643 3, 3),
644 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
645 show_pwm_auto_point_temp_hyst,
646 store_pwm_auto_point_temp_hyst,
647 0, 3),
648 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
649 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
650 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
651 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
652 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
653 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200654};
655
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100656/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm!
657 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
658 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
659static struct sensor_device_attribute_2 f8000_fan_attr[] = {
660 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
661
662 SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2),
663
664 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
665 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
666 0, 2),
667 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
668 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
669 1, 2),
670 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
671 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
672 2, 2),
673 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
674 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
675 3, 2),
676 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
678 4, 2),
679 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
681 0, 2),
682 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
684 1, 2),
685 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
686 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
687 2, 2),
688 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
689 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
690 3, 2),
691 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
692 show_pwm_auto_point_temp_hyst,
693 store_pwm_auto_point_temp_hyst,
694 0, 2),
695 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
696 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
697 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
698 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
699 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
700 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
701
702 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
704 0, 0),
705 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
707 1, 0),
708 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
710 2, 0),
711 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
712 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
713 3, 0),
714 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
715 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
716 4, 0),
717 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
718 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
719 0, 0),
720 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
721 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
722 1, 0),
723 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
724 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
725 2, 0),
726 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
727 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
728 3, 0),
729 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
730 show_pwm_auto_point_temp_hyst,
731 store_pwm_auto_point_temp_hyst,
732 0, 0),
733 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
734 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
735 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
736 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
737 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
738 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
739
740 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
742 0, 1),
743 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
745 1, 1),
746 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
748 2, 1),
749 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
751 3, 1),
752 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
754 4, 1),
755 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
757 0, 1),
758 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
759 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
760 1, 1),
761 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
762 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
763 2, 1),
764 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
766 3, 1),
767 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_temp_hyst,
769 store_pwm_auto_point_temp_hyst,
770 0, 1),
771 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
772 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
773 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
774 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
775 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
776 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
777};
Hans de Goede45fb3662007-07-13 14:34:19 +0200778
779/* Super I/O functions */
780static inline int superio_inb(int base, int reg)
781{
782 outb(reg, base);
783 return inb(base + 1);
784}
785
786static int superio_inw(int base, int reg)
787{
788 int val;
789 outb(reg++, base);
790 val = inb(base + 1) << 8;
791 outb(reg, base);
792 val |= inb(base + 1);
793 return val;
794}
795
796static inline void superio_enter(int base)
797{
798 /* according to the datasheet the key must be send twice! */
799 outb( SIO_UNLOCK_KEY, base);
800 outb( SIO_UNLOCK_KEY, base);
801}
802
803static inline void superio_select( int base, int ld)
804{
805 outb(SIO_REG_LDSEL, base);
806 outb(ld, base + 1);
807}
808
809static inline void superio_exit(int base)
810{
811 outb(SIO_LOCK_KEY, base);
812}
813
Hans de Goede2f650632009-01-07 16:37:31 +0100814static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200815{
816 return reg ? (1500000 / reg) : 0;
817}
818
Hans de Goede2f650632009-01-07 16:37:31 +0100819static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100820{
821 return fan ? (1500000 / fan) : 0;
822}
823
Hans de Goede45fb3662007-07-13 14:34:19 +0200824static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
825{
826 u8 val;
827
828 outb(reg, data->addr + ADDR_REG_OFFSET);
829 val = inb(data->addr + DATA_REG_OFFSET);
830
831 return val;
832}
833
834static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
835{
836 u16 val;
837
838 outb(reg++, data->addr + ADDR_REG_OFFSET);
839 val = inb(data->addr + DATA_REG_OFFSET) << 8;
840 outb(reg, data->addr + ADDR_REG_OFFSET);
841 val |= inb(data->addr + DATA_REG_OFFSET);
842
843 return val;
844}
845
846static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
847{
848 outb(reg, data->addr + ADDR_REG_OFFSET);
849 outb(val, data->addr + DATA_REG_OFFSET);
850}
851
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100852static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
853{
854 outb(reg++, data->addr + ADDR_REG_OFFSET);
855 outb(val >> 8, data->addr + DATA_REG_OFFSET);
856 outb(reg, data->addr + ADDR_REG_OFFSET);
857 outb(val & 255, data->addr + DATA_REG_OFFSET);
858}
859
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100860static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200861{
862 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100863 int nr, reg = 0, reg2;
864 int nr_fans = (data->type == f71882fg) ? 4 : 3;
865 int nr_ins = (data->type == f8000) ? 3 : 9;
866 int temp_start = (data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +0200867
868 mutex_lock(&data->update_lock);
869
870 /* Update once every 60 seconds */
871 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
872 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100873 if (data->type == f71882fg) {
874 data->in1_max =
875 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
876 data->in_beep =
877 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
878 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200879
880 /* Get High & boundary temps*/
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100881 for (nr = temp_start; nr < 3 + temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200882 data->temp_ovt[nr] = f71882fg_read8(data,
883 F71882FG_REG_TEMP_OVT(nr));
884 data->temp_high[nr] = f71882fg_read8(data,
885 F71882FG_REG_TEMP_HIGH(nr));
886 }
887
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100888 if (data->type != f8000) {
889 data->fan_beep = f71882fg_read8(data,
890 F71882FG_REG_FAN_BEEP);
891 data->temp_beep = f71882fg_read8(data,
892 F71882FG_REG_TEMP_BEEP);
893 data->temp_hyst[0] = f71882fg_read8(data,
894 F71882FG_REG_TEMP_HYST(0));
895 data->temp_hyst[1] = f71882fg_read8(data,
896 F71882FG_REG_TEMP_HYST(1));
897 /* Have to hardcode type, because temp1 is special */
898 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
899 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
900 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
901 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200902 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
903 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100904 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200905 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100906 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100907 else if (data->type != f8000)
Hans de Goede7567a042009-01-07 16:37:28 +0100908 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100909 else
910 data->temp_type[1] = 2; /* F8000 only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200911
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100912 data->pwm_enable = f71882fg_read8(data,
913 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100914 data->pwm_auto_point_hyst[0] =
915 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
916 data->pwm_auto_point_hyst[1] =
917 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
918
Hans de Goede498be962009-01-07 16:37:28 +0100919 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100920 data->pwm_auto_point_mapping[nr] =
921 f71882fg_read8(data,
922 F71882FG_REG_POINT_MAPPING(nr));
923
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100924 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100925 int point;
926 for (point = 0; point < 5; point++) {
927 data->pwm_auto_point_pwm[nr][point] =
928 f71882fg_read8(data,
929 F71882FG_REG_POINT_PWM
930 (nr, point));
931 }
932 for (point = 0; point < 4; point++) {
933 data->pwm_auto_point_temp[nr][point] =
934 f71882fg_read8(data,
935 F71882FG_REG_POINT_TEMP
936 (nr, point));
937 }
938 } else {
939 data->pwm_auto_point_pwm[nr][1] =
940 f71882fg_read8(data,
941 F71882FG_REG_POINT_PWM
942 (nr, 1));
943 data->pwm_auto_point_pwm[nr][4] =
944 f71882fg_read8(data,
945 F71882FG_REG_POINT_PWM
946 (nr, 4));
947 data->pwm_auto_point_temp[nr][0] =
948 f71882fg_read8(data,
949 F71882FG_REG_POINT_TEMP
950 (nr, 0));
951 data->pwm_auto_point_temp[nr][3] =
952 f71882fg_read8(data,
953 F71882FG_REG_POINT_TEMP
954 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100955 }
956 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200957 data->last_limits = jiffies;
958 }
959
960 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400961 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200962 data->temp_status = f71882fg_read8(data,
963 F71882FG_REG_TEMP_STATUS);
964 data->temp_diode_open = f71882fg_read8(data,
965 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100966 for (nr = temp_start; nr < 3 + temp_start; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200967 data->temp[nr] = f71882fg_read8(data,
968 F71882FG_REG_TEMP(nr));
969
970 data->fan_status = f71882fg_read8(data,
971 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +0100972 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200973 data->fan[nr] = f71882fg_read16(data,
974 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100975 data->fan_target[nr] =
976 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
977 data->fan_full_speed[nr] =
978 f71882fg_read16(data,
979 F71882FG_REG_FAN_FULL_SPEED(nr));
980 data->pwm[nr] =
981 f71882fg_read8(data, F71882FG_REG_PWM(nr));
982 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200983
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100984 /* The f8000 can monitor 1 more fan, but has no pwm for it */
985 if (data->type == f8000)
986 data->fan[3] = f71882fg_read16(data,
987 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +0100988 if (data->type == f71882fg)
989 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +0200990 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100991 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200992 data->in[nr] = f71882fg_read8(data,
993 F71882FG_REG_IN(nr));
994
995 data->last_updated = jiffies;
996 data->valid = 1;
997 }
998
999 mutex_unlock(&data->update_lock);
1000
1001 return data;
1002}
1003
1004/* Sysfs Interface */
1005static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1006 char *buf)
1007{
1008 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001009 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001010 int speed = fan_from_reg(data->fan[nr]);
1011
1012 if (speed == FAN_MIN_DETECT)
1013 speed = 0;
1014
1015 return sprintf(buf, "%d\n", speed);
1016}
1017
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001018static ssize_t show_fan_full_speed(struct device *dev,
1019 struct device_attribute *devattr, char *buf)
1020{
1021 struct f71882fg_data *data = f71882fg_update_device(dev);
1022 int nr = to_sensor_dev_attr_2(devattr)->index;
1023 int speed = fan_from_reg(data->fan_full_speed[nr]);
1024 return sprintf(buf, "%d\n", speed);
1025}
1026
1027static ssize_t store_fan_full_speed(struct device *dev,
1028 struct device_attribute *devattr,
1029 const char *buf, size_t count)
1030{
1031 struct f71882fg_data *data = dev_get_drvdata(dev);
1032 int nr = to_sensor_dev_attr_2(devattr)->index;
1033 long val = simple_strtol(buf, NULL, 10);
1034
1035 val = SENSORS_LIMIT(val, 23, 1500000);
1036 val = fan_to_reg(val);
1037
1038 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001039 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1040 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001041 mutex_unlock(&data->update_lock);
1042
1043 return count;
1044}
1045
Hans de Goede45fb3662007-07-13 14:34:19 +02001046static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1047 *devattr, char *buf)
1048{
1049 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001050 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001051
1052 if (data->fan_beep & (1 << nr))
1053 return sprintf(buf, "1\n");
1054 else
1055 return sprintf(buf, "0\n");
1056}
1057
1058static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1059 *devattr, const char *buf, size_t count)
1060{
1061 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001062 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001063 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001064
1065 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001066 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001067 if (val)
1068 data->fan_beep |= 1 << nr;
1069 else
1070 data->fan_beep &= ~(1 << nr);
1071
1072 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1073 mutex_unlock(&data->update_lock);
1074
1075 return count;
1076}
1077
1078static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1079 *devattr, char *buf)
1080{
1081 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001082 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001083
1084 if (data->fan_status & (1 << nr))
1085 return sprintf(buf, "1\n");
1086 else
1087 return sprintf(buf, "0\n");
1088}
1089
1090static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1091 char *buf)
1092{
1093 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001094 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001095
1096 return sprintf(buf, "%d\n", data->in[nr] * 8);
1097}
1098
1099static ssize_t show_in_max(struct device *dev, struct device_attribute
1100 *devattr, char *buf)
1101{
1102 struct f71882fg_data *data = f71882fg_update_device(dev);
1103
1104 return sprintf(buf, "%d\n", data->in1_max * 8);
1105}
1106
1107static ssize_t store_in_max(struct device *dev, struct device_attribute
1108 *devattr, const char *buf, size_t count)
1109{
1110 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001111 long val = simple_strtol(buf, NULL, 10) / 8;
1112 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001113
1114 mutex_lock(&data->update_lock);
1115 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1116 data->in1_max = val;
1117 mutex_unlock(&data->update_lock);
1118
1119 return count;
1120}
1121
1122static ssize_t show_in_beep(struct device *dev, struct device_attribute
1123 *devattr, char *buf)
1124{
1125 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001126 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001127
1128 if (data->in_beep & (1 << nr))
1129 return sprintf(buf, "1\n");
1130 else
1131 return sprintf(buf, "0\n");
1132}
1133
1134static ssize_t store_in_beep(struct device *dev, struct device_attribute
1135 *devattr, const char *buf, size_t count)
1136{
1137 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001138 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001139 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001140
1141 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001142 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001143 if (val)
1144 data->in_beep |= 1 << nr;
1145 else
1146 data->in_beep &= ~(1 << nr);
1147
1148 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1149 mutex_unlock(&data->update_lock);
1150
1151 return count;
1152}
1153
1154static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1155 *devattr, char *buf)
1156{
1157 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001158 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001159
1160 if (data->in_status & (1 << nr))
1161 return sprintf(buf, "1\n");
1162 else
1163 return sprintf(buf, "0\n");
1164}
1165
1166static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1167 char *buf)
1168{
1169 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001170 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001171
1172 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
1173}
1174
1175static ssize_t show_temp_max(struct device *dev, struct device_attribute
1176 *devattr, char *buf)
1177{
1178 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001179 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001180
1181 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1182}
1183
1184static ssize_t store_temp_max(struct device *dev, struct device_attribute
1185 *devattr, const char *buf, size_t count)
1186{
1187 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001188 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001189 long val = simple_strtol(buf, NULL, 10) / 1000;
1190 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001191
1192 mutex_lock(&data->update_lock);
1193 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1194 data->temp_high[nr] = val;
1195 mutex_unlock(&data->update_lock);
1196
1197 return count;
1198}
1199
1200static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1201 *devattr, char *buf)
1202{
1203 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001204 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001205 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001206
Hans de Goedece0bfa52009-01-07 16:37:28 +01001207 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001208 if (nr & 1)
1209 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1210 else
1211 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1212 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001213 mutex_unlock(&data->update_lock);
1214
1215 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001216}
1217
1218static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1219 *devattr, const char *buf, size_t count)
1220{
1221 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001222 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001223 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001224 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001225 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001226
1227 mutex_lock(&data->update_lock);
1228
1229 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001230 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1231 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1232 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001233 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001234
1235 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001236 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1237 if (nr & 1)
1238 reg = (reg & 0x0f) | (val << 4);
1239 else
1240 reg = (reg & 0xf0) | val;
1241 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1242 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001243
Hans de Goede45fb3662007-07-13 14:34:19 +02001244 mutex_unlock(&data->update_lock);
1245 return ret;
1246}
1247
1248static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1249 *devattr, char *buf)
1250{
1251 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001252 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001253
1254 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1255}
1256
1257static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1258 *devattr, const char *buf, size_t count)
1259{
1260 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001261 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001262 long val = simple_strtol(buf, NULL, 10) / 1000;
1263 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001264
1265 mutex_lock(&data->update_lock);
1266 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1267 data->temp_ovt[nr] = val;
1268 mutex_unlock(&data->update_lock);
1269
1270 return count;
1271}
1272
1273static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1274 *devattr, char *buf)
1275{
1276 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001277 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001278 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001279
Hans de Goedece0bfa52009-01-07 16:37:28 +01001280 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001281 if (nr & 1)
1282 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1283 else
1284 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1285 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001286 mutex_unlock(&data->update_lock);
1287
1288 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001289}
1290
1291static ssize_t show_temp_type(struct device *dev, struct device_attribute
1292 *devattr, char *buf)
1293{
1294 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001295 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001296
1297 return sprintf(buf, "%d\n", data->temp_type[nr]);
1298}
1299
1300static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1301 *devattr, char *buf)
1302{
1303 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001304 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001305
Hans de Goede7567a042009-01-07 16:37:28 +01001306 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001307 return sprintf(buf, "1\n");
1308 else
1309 return sprintf(buf, "0\n");
1310}
1311
1312static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1313 *devattr, const char *buf, size_t count)
1314{
1315 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001316 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001317 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001318
1319 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001320 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001321 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001322 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001323 else
Hans de Goede7567a042009-01-07 16:37:28 +01001324 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001325
1326 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1327 mutex_unlock(&data->update_lock);
1328
1329 return count;
1330}
1331
1332static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1333 *devattr, char *buf)
1334{
1335 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001336 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001337
Hans de Goede7567a042009-01-07 16:37:28 +01001338 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001339 return sprintf(buf, "1\n");
1340 else
1341 return sprintf(buf, "0\n");
1342}
1343
1344static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1345 *devattr, char *buf)
1346{
1347 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001348 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001349
Hans de Goede7567a042009-01-07 16:37:28 +01001350 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001351 return sprintf(buf, "1\n");
1352 else
1353 return sprintf(buf, "0\n");
1354}
1355
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001356static ssize_t show_pwm(struct device *dev,
1357 struct device_attribute *devattr, char *buf)
1358{
1359 struct f71882fg_data *data = f71882fg_update_device(dev);
1360 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001361 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001362 if (data->pwm_enable & (1 << (2 * nr)))
1363 /* PWM mode */
1364 val = data->pwm[nr];
1365 else {
1366 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001367 val = 255 * fan_from_reg(data->fan_target[nr])
1368 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001369 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001370 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001371 return sprintf(buf, "%d\n", val);
1372}
1373
1374static ssize_t store_pwm(struct device *dev,
1375 struct device_attribute *devattr, const char *buf,
1376 size_t count)
1377{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001378 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001379 int nr = to_sensor_dev_attr_2(devattr)->index;
1380 long val = simple_strtol(buf, NULL, 10);
1381 val = SENSORS_LIMIT(val, 0, 255);
1382
1383 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001384 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001385 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1386 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1387 count = -EROFS;
1388 goto leave;
1389 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001390 if (data->pwm_enable & (1 << (2 * nr))) {
1391 /* PWM mode */
1392 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1393 data->pwm[nr] = val;
1394 } else {
1395 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001396 int target, full_speed;
1397 full_speed = f71882fg_read16(data,
1398 F71882FG_REG_FAN_FULL_SPEED(nr));
1399 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1400 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1401 data->fan_target[nr] = target;
1402 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001403 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001404leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001405 mutex_unlock(&data->update_lock);
1406
1407 return count;
1408}
1409
1410static ssize_t show_pwm_enable(struct device *dev,
1411 struct device_attribute *devattr, char *buf)
1412{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001413 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001414 struct f71882fg_data *data = f71882fg_update_device(dev);
1415 int nr = to_sensor_dev_attr_2(devattr)->index;
1416
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001417 switch ((data->pwm_enable >> 2 * nr) & 3) {
1418 case 0:
1419 case 1:
1420 result = 2; /* Normal auto mode */
1421 break;
1422 case 2:
1423 result = 1; /* Manual mode */
1424 break;
1425 case 3:
1426 if (data->type == f8000)
1427 result = 3; /* Thermostat mode */
1428 else
1429 result = 1; /* Manual mode */
1430 break;
1431 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001432
1433 return sprintf(buf, "%d\n", result);
1434}
1435
1436static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1437 *devattr, const char *buf, size_t count)
1438{
1439 struct f71882fg_data *data = dev_get_drvdata(dev);
1440 int nr = to_sensor_dev_attr_2(devattr)->index;
1441 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001442
1443 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001444 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001445 /* Special case for F8000 auto PWM mode / Thermostat mode */
1446 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1447 switch (val) {
1448 case 2:
1449 data->pwm_enable &= ~(2 << (2 * nr));
1450 break; /* Normal auto mode */
1451 case 3:
1452 data->pwm_enable |= 2 << (2 * nr);
1453 break; /* Thermostat mode */
1454 default:
1455 count = -EINVAL;
1456 goto leave;
1457 }
1458 } else {
1459 switch (val) {
1460 case 1:
1461 data->pwm_enable |= 2 << (2 * nr);
1462 break; /* Manual */
1463 case 2:
1464 data->pwm_enable &= ~(2 << (2 * nr));
1465 break; /* Normal auto mode */
1466 default:
1467 count = -EINVAL;
1468 goto leave;
1469 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001470 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001471 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001472leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001473 mutex_unlock(&data->update_lock);
1474
1475 return count;
1476}
1477
1478static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1479 struct device_attribute *devattr,
1480 char *buf)
1481{
1482 int result;
1483 struct f71882fg_data *data = f71882fg_update_device(dev);
1484 int pwm = to_sensor_dev_attr_2(devattr)->index;
1485 int point = to_sensor_dev_attr_2(devattr)->nr;
1486
Hans de Goedece0bfa52009-01-07 16:37:28 +01001487 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001488 if (data->pwm_enable & (1 << (2 * pwm))) {
1489 /* PWM mode */
1490 result = data->pwm_auto_point_pwm[pwm][point];
1491 } else {
1492 /* RPM mode */
1493 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1494 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001495 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001496
1497 return sprintf(buf, "%d\n", result);
1498}
1499
1500static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1501 struct device_attribute *devattr,
1502 const char *buf, size_t count)
1503{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001504 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001505 int pwm = to_sensor_dev_attr_2(devattr)->index;
1506 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001507 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001508 val = SENSORS_LIMIT(val, 0, 255);
1509
1510 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001511 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001512 if (data->pwm_enable & (1 << (2 * pwm))) {
1513 /* PWM mode */
1514 } else {
1515 /* RPM mode */
1516 if (val < 29) /* Prevent negative numbers */
1517 val = 255;
1518 else
1519 val = (255 - val) * 32 / val;
1520 }
1521 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1522 data->pwm_auto_point_pwm[pwm][point] = val;
1523 mutex_unlock(&data->update_lock);
1524
1525 return count;
1526}
1527
1528static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1529 struct device_attribute *devattr,
1530 char *buf)
1531{
1532 int result = 0;
1533 struct f71882fg_data *data = f71882fg_update_device(dev);
1534 int nr = to_sensor_dev_attr_2(devattr)->index;
1535 int point = to_sensor_dev_attr_2(devattr)->nr;
1536
1537 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001538 if (nr & 1)
1539 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1540 else
1541 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001542 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1543 mutex_unlock(&data->update_lock);
1544
1545 return sprintf(buf, "%d\n", result);
1546}
1547
1548static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1549 struct device_attribute *devattr,
1550 const char *buf, size_t count)
1551{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001552 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001553 int nr = to_sensor_dev_attr_2(devattr)->index;
1554 int point = to_sensor_dev_attr_2(devattr)->nr;
1555 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001556 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001557
1558 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001559 data->pwm_auto_point_temp[nr][point] =
1560 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001561 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1562 data->pwm_auto_point_temp[nr][point]);
1563 val = data->pwm_auto_point_temp[nr][point] - val;
1564
Hans de Goedebc274902009-01-07 16:37:29 +01001565 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1566 if (nr & 1)
1567 reg = (reg & 0x0f) | (val << 4);
1568 else
1569 reg = (reg & 0xf0) | val;
1570
1571 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1572 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001573 mutex_unlock(&data->update_lock);
1574
1575 return count;
1576}
1577
1578static ssize_t show_pwm_interpolate(struct device *dev,
1579 struct device_attribute *devattr, char *buf)
1580{
1581 int result;
1582 struct f71882fg_data *data = f71882fg_update_device(dev);
1583 int nr = to_sensor_dev_attr_2(devattr)->index;
1584
1585 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1586
1587 return sprintf(buf, "%d\n", result);
1588}
1589
1590static ssize_t store_pwm_interpolate(struct device *dev,
1591 struct device_attribute *devattr,
1592 const char *buf, size_t count)
1593{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001594 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001595 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001596 unsigned long val = simple_strtoul(buf, NULL, 10);
1597
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001598 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001599 data->pwm_auto_point_mapping[nr] =
1600 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001601 if (val)
1602 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1603 else
1604 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1605 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1606 data->pwm_auto_point_mapping[nr] = val;
1607 mutex_unlock(&data->update_lock);
1608
1609 return count;
1610}
1611
1612static ssize_t show_pwm_auto_point_channel(struct device *dev,
1613 struct device_attribute *devattr,
1614 char *buf)
1615{
1616 int result;
1617 struct f71882fg_data *data = f71882fg_update_device(dev);
1618 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001619 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001620
Hans de Goede30453012009-01-07 16:37:30 +01001621 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001622
1623 return sprintf(buf, "%d\n", result);
1624}
1625
1626static ssize_t store_pwm_auto_point_channel(struct device *dev,
1627 struct device_attribute *devattr,
1628 const char *buf, size_t count)
1629{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001630 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001631 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001632 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001633 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001634
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001635 switch (val) {
1636 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001637 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001638 break;
1639 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001640 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001641 break;
1642 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001643 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001644 break;
1645 default:
1646 return -EINVAL;
1647 }
Hans de Goede30453012009-01-07 16:37:30 +01001648 val += temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001649 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001650 data->pwm_auto_point_mapping[nr] =
1651 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001652 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1653 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1654 data->pwm_auto_point_mapping[nr] = val;
1655 mutex_unlock(&data->update_lock);
1656
1657 return count;
1658}
1659
1660static ssize_t show_pwm_auto_point_temp(struct device *dev,
1661 struct device_attribute *devattr,
1662 char *buf)
1663{
1664 int result;
1665 struct f71882fg_data *data = f71882fg_update_device(dev);
1666 int pwm = to_sensor_dev_attr_2(devattr)->index;
1667 int point = to_sensor_dev_attr_2(devattr)->nr;
1668
1669 result = data->pwm_auto_point_temp[pwm][point];
1670 return sprintf(buf, "%d\n", 1000 * result);
1671}
1672
1673static ssize_t store_pwm_auto_point_temp(struct device *dev,
1674 struct device_attribute *devattr,
1675 const char *buf, size_t count)
1676{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001677 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001678 int pwm = to_sensor_dev_attr_2(devattr)->index;
1679 int point = to_sensor_dev_attr_2(devattr)->nr;
1680 long val = simple_strtol(buf, NULL, 10) / 1000;
1681 val = SENSORS_LIMIT(val, 0, 255);
1682
1683 mutex_lock(&data->update_lock);
1684 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1685 data->pwm_auto_point_temp[pwm][point] = val;
1686 mutex_unlock(&data->update_lock);
1687
1688 return count;
1689}
1690
Hans de Goede45fb3662007-07-13 14:34:19 +02001691static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1692 char *buf)
1693{
Hans de Goede498be962009-01-07 16:37:28 +01001694 struct f71882fg_data *data = dev_get_drvdata(dev);
1695 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001696}
1697
Hans de Goedec13548c2009-01-07 16:37:27 +01001698static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1699 struct sensor_device_attribute_2 *attr, int count)
1700{
1701 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001702
Hans de Goedec13548c2009-01-07 16:37:27 +01001703 for (i = 0; i < count; i++) {
1704 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1705 if (err)
1706 return err;
1707 }
1708 return 0;
1709}
1710
1711static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001712{
1713 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001714 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001715 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001716 u8 start_reg;
1717
Hans de Goedec13548c2009-01-07 16:37:27 +01001718 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1719 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001720 return -ENOMEM;
1721
1722 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001723 data->type = sio_data->type;
Hans de Goede45fb3662007-07-13 14:34:19 +02001724 mutex_init(&data->update_lock);
1725 platform_set_drvdata(pdev, data);
1726
Hans de Goede3cc74752009-01-07 16:37:28 +01001727 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001728 if (start_reg & 0x04) {
1729 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1730 err = -ENODEV;
1731 goto exit_free;
1732 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001733 if (!(start_reg & 0x03)) {
1734 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1735 err = -ENODEV;
1736 goto exit_free;
1737 }
1738
Hans de Goede28ba8582009-01-07 16:37:31 +01001739 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goede3cc74752009-01-07 16:37:28 +01001740 /* If it is a 71862 and the fan / pwm part is enabled sanity check
1741 the pwm settings */
1742 if (data->type == f71862fg && (start_reg & 0x02)) {
Hans de Goede28ba8582009-01-07 16:37:31 +01001743 if ((data->pwm_enable & 0x15) != 0x15) {
Hans de Goede3cc74752009-01-07 16:37:28 +01001744 dev_err(&pdev->dev,
1745 "Invalid (reserved) pwm settings: 0x%02x\n",
Hans de Goede28ba8582009-01-07 16:37:31 +01001746 (unsigned int)data->pwm_enable);
Hans de Goede3cc74752009-01-07 16:37:28 +01001747 err = -ENODEV;
1748 goto exit_free;
1749 }
1750 }
1751
Hans de Goede45fb3662007-07-13 14:34:19 +02001752 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001753 err = device_create_file(&pdev->dev, &dev_attr_name);
1754 if (err)
1755 goto exit_unregister_sysfs;
1756
Hans de Goedec13548c2009-01-07 16:37:27 +01001757 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001758 switch (data->type) {
1759 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001760 err = f71882fg_create_sysfs_files(pdev,
1761 f71882fg_in_temp_attr,
1762 ARRAY_SIZE(f71882fg_in_temp_attr));
1763 if (err)
1764 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001765 /* fall through! */
1766 case f71862fg:
1767 err = f71882fg_create_sysfs_files(pdev,
1768 f718x2fg_in_temp_attr,
1769 ARRAY_SIZE(f718x2fg_in_temp_attr));
1770 break;
1771 case f8000:
1772 err = f71882fg_create_sysfs_files(pdev,
1773 f8000_in_temp_attr,
1774 ARRAY_SIZE(f8000_in_temp_attr));
1775 break;
Hans de Goede498be962009-01-07 16:37:28 +01001776 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001777 if (err)
1778 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001779 }
1780
Hans de Goede45fb3662007-07-13 14:34:19 +02001781 if (start_reg & 0x02) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001782 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1783 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001784 if (err)
1785 goto exit_unregister_sysfs;
1786
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001787 switch (data->type) {
1788 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001789 err = f71882fg_create_sysfs_files(pdev,
1790 f71862fg_fan_attr,
1791 ARRAY_SIZE(f71862fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001792 break;
1793 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001794 err = f71882fg_create_sysfs_files(pdev,
1795 f71882fg_fan_attr,
Hans de Goedec13548c2009-01-07 16:37:27 +01001796 ARRAY_SIZE(f71882fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001797 break;
1798 case f8000:
1799 err = f71882fg_create_sysfs_files(pdev,
1800 f8000_fan_attr,
1801 ARRAY_SIZE(f8000_fan_attr));
1802 break;
Hans de Goede498be962009-01-07 16:37:28 +01001803 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001804 if (err)
1805 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001806
1807 for (i = 0; i < nr_fans; i++)
1808 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1809 (data->pwm_enable & (1 << 2 * i)) ?
1810 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001811 }
1812
Tony Jones1beeffe2007-08-20 13:46:20 -07001813 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1814 if (IS_ERR(data->hwmon_dev)) {
1815 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001816 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001817 goto exit_unregister_sysfs;
1818 }
1819
1820 return 0;
1821
1822exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001823 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001824 return err; /* f71882fg_remove() also frees our data */
1825exit_free:
1826 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001827 return err;
1828}
1829
Hans de Goedec13548c2009-01-07 16:37:27 +01001830static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001831{
1832 int i;
1833 struct f71882fg_data *data = platform_get_drvdata(pdev);
1834
1835 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001836 if (data->hwmon_dev)
1837 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001838
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001839 /* Note we are not looping over all attr arrays we have as the ones
1840 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001841 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001842
Hans de Goede498be962009-01-07 16:37:28 +01001843 for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
1844 device_remove_file(&pdev->dev,
1845 &f718x2fg_in_temp_attr[i].dev_attr);
1846
Hans de Goede45fb3662007-07-13 14:34:19 +02001847 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1848 device_remove_file(&pdev->dev,
1849 &f71882fg_in_temp_attr[i].dev_attr);
1850
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001851 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
1852 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001853
Hans de Goede45fb3662007-07-13 14:34:19 +02001854 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1855 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1856
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001857 for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
1858 device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
1859
Hans de Goede45fb3662007-07-13 14:34:19 +02001860 kfree(data);
1861
1862 return 0;
1863}
1864
Hans de Goede498be962009-01-07 16:37:28 +01001865static int __init f71882fg_find(int sioaddr, unsigned short *address,
1866 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001867{
1868 int err = -ENODEV;
1869 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02001870
1871 superio_enter(sioaddr);
1872
1873 devid = superio_inw(sioaddr, SIO_REG_MANID);
1874 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01001875 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02001876 goto exit;
1877 }
1878
Jean Delvare67b671b2007-12-06 23:13:42 +01001879 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01001880 switch (devid) {
1881 case SIO_F71862_ID:
1882 sio_data->type = f71862fg;
1883 break;
1884 case SIO_F71882_ID:
1885 sio_data->type = f71882fg;
1886 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001887 case SIO_F8000_ID:
1888 sio_data->type = f8000;
1889 break;
Hans de Goede498be962009-01-07 16:37:28 +01001890 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02001891 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
1892 goto exit;
1893 }
1894
1895 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001896 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001897 printk(KERN_WARNING DRVNAME ": Device not activated\n");
1898 goto exit;
1899 }
1900
1901 *address = superio_inw(sioaddr, SIO_REG_ADDR);
1902 if (*address == 0)
1903 {
1904 printk(KERN_WARNING DRVNAME ": Base address not set\n");
1905 goto exit;
1906 }
1907 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
1908
Hans de Goede45fb3662007-07-13 14:34:19 +02001909 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01001910 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
1911 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02001912 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
1913exit:
1914 superio_exit(sioaddr);
1915 return err;
1916}
1917
Hans de Goede498be962009-01-07 16:37:28 +01001918static int __init f71882fg_device_add(unsigned short address,
1919 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001920{
1921 struct resource res = {
1922 .start = address,
1923 .end = address + REGION_LENGTH - 1,
1924 .flags = IORESOURCE_IO,
1925 };
1926 int err;
1927
1928 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001929 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001930 return -ENOMEM;
1931
1932 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01001933 err = acpi_check_resource_conflict(&res);
1934 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001935 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001936
Hans de Goede45fb3662007-07-13 14:34:19 +02001937 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001938 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001939 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
1940 goto exit_device_put;
1941 }
1942
Hans de Goede498be962009-01-07 16:37:28 +01001943 err = platform_device_add_data(f71882fg_pdev, sio_data,
1944 sizeof(struct f71882fg_sio_data));
1945 if (err) {
1946 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1947 goto exit_device_put;
1948 }
1949
Hans de Goede45fb3662007-07-13 14:34:19 +02001950 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001951 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001952 printk(KERN_ERR DRVNAME ": Device addition failed\n");
1953 goto exit_device_put;
1954 }
1955
1956 return 0;
1957
1958exit_device_put:
1959 platform_device_put(f71882fg_pdev);
1960
1961 return err;
1962}
1963
1964static int __init f71882fg_init(void)
1965{
1966 int err = -ENODEV;
1967 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01001968 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02001969
Hans de Goede498be962009-01-07 16:37:28 +01001970 memset(&sio_data, 0, sizeof(sio_data));
1971
1972 if (f71882fg_find(0x2e, &address, &sio_data) &&
1973 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02001974 goto exit;
1975
Hans de Goedec13548c2009-01-07 16:37:27 +01001976 err = platform_driver_register(&f71882fg_driver);
1977 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001978 goto exit;
1979
Hans de Goede498be962009-01-07 16:37:28 +01001980 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01001981 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001982 goto exit_driver;
1983
1984 return 0;
1985
1986exit_driver:
1987 platform_driver_unregister(&f71882fg_driver);
1988exit:
1989 return err;
1990}
1991
1992static void __exit f71882fg_exit(void)
1993{
1994 platform_device_unregister(f71882fg_pdev);
1995 platform_driver_unregister(&f71882fg_driver);
1996}
1997
1998MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01001999MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002000MODULE_LICENSE("GPL");
2001
2002module_init(f71882fg_init);
2003module_exit(f71882fg_exit);