blob: eb324e60410588c37800ccf80f1124251a34483c [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
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,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200250 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200251};
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 Goede3fc78382009-06-15 18:39:50 +0200398 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
399 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
400 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100401 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
402 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
403 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
404 show_pwm_auto_point_channel,
405 store_pwm_auto_point_channel, 0, 2),
406};
407
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100408/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
409 f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100410static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100411 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
412 store_fan_beep, 0, 0),
413 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
414 store_fan_beep, 0, 1),
415 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
416 store_fan_beep, 0, 2),
417
Hans de Goede498be962009-01-07 16:37:28 +0100418 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
419 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
420 1, 0),
421 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
422 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
423 4, 0),
424 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
425 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
426 0, 0),
427 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
428 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
429 3, 0),
430 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
431 show_pwm_auto_point_temp_hyst,
432 store_pwm_auto_point_temp_hyst,
433 0, 0),
434 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
435 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
436
437 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
438 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
439 1, 1),
440 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
441 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
442 4, 1),
443 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
444 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
445 0, 1),
446 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
447 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
448 3, 1),
449 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
450 show_pwm_auto_point_temp_hyst,
451 store_pwm_auto_point_temp_hyst,
452 0, 1),
453 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
454 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100455
Hans de Goede49010622009-01-07 16:37:30 +0100456 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
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100568 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
569 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
570 0, 2),
571 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
572 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
573 1, 2),
574 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
575 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
576 2, 2),
577 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
578 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
579 3, 2),
580 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
581 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
582 4, 2),
583 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
584 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
585 0, 2),
586 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
587 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
588 1, 2),
589 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
590 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
591 2, 2),
592 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
593 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
594 3, 2),
595 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
596 show_pwm_auto_point_temp_hyst,
597 store_pwm_auto_point_temp_hyst,
598 0, 2),
599 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
600 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
601 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
602 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
603 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
604 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
605
606 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
607 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
608 store_pwm_enable, 0, 3),
609 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
610 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
611 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_channel,
613 store_pwm_auto_point_channel, 0, 3),
614 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
616 0, 3),
617 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
619 1, 3),
620 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
622 2, 3),
623 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
625 3, 3),
626 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
628 4, 3),
629 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
630 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
631 0, 3),
632 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
633 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
634 1, 3),
635 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
637 2, 3),
638 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
640 3, 3),
641 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
642 show_pwm_auto_point_temp_hyst,
643 store_pwm_auto_point_temp_hyst,
644 0, 3),
645 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
646 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
647 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
648 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
649 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
650 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200651};
652
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100653/* Fan / PWM attr for the f8000, zones mapped to temp instead of to pwm!
654 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
655 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
656static struct sensor_device_attribute_2 f8000_fan_attr[] = {
657 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
658
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100659 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
661 0, 2),
662 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
664 1, 2),
665 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
667 2, 2),
668 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
670 3, 2),
671 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
672 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
673 4, 2),
674 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
676 0, 2),
677 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
679 1, 2),
680 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
682 2, 2),
683 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
685 3, 2),
686 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_temp_hyst,
688 store_pwm_auto_point_temp_hyst,
689 0, 2),
690 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
691 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
692 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
693 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
694 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
695 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
696
697 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
698 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
699 0, 0),
700 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
701 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
702 1, 0),
703 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
705 2, 0),
706 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
708 3, 0),
709 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
710 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
711 4, 0),
712 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
713 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
714 0, 0),
715 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
716 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
717 1, 0),
718 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
719 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
720 2, 0),
721 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
722 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
723 3, 0),
724 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
725 show_pwm_auto_point_temp_hyst,
726 store_pwm_auto_point_temp_hyst,
727 0, 0),
728 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
729 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
730 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
731 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
732 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
733 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
734
735 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
736 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
737 0, 1),
738 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
739 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
740 1, 1),
741 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
742 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
743 2, 1),
744 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
746 3, 1),
747 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
749 4, 1),
750 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
752 0, 1),
753 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
755 1, 1),
756 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
758 2, 1),
759 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
761 3, 1),
762 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_temp_hyst,
764 store_pwm_auto_point_temp_hyst,
765 0, 1),
766 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
767 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
768 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
769 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
770 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
771 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
772};
Hans de Goede45fb3662007-07-13 14:34:19 +0200773
774/* Super I/O functions */
775static inline int superio_inb(int base, int reg)
776{
777 outb(reg, base);
778 return inb(base + 1);
779}
780
781static int superio_inw(int base, int reg)
782{
783 int val;
784 outb(reg++, base);
785 val = inb(base + 1) << 8;
786 outb(reg, base);
787 val |= inb(base + 1);
788 return val;
789}
790
791static inline void superio_enter(int base)
792{
793 /* according to the datasheet the key must be send twice! */
794 outb( SIO_UNLOCK_KEY, base);
795 outb( SIO_UNLOCK_KEY, base);
796}
797
798static inline void superio_select( int base, int ld)
799{
800 outb(SIO_REG_LDSEL, base);
801 outb(ld, base + 1);
802}
803
804static inline void superio_exit(int base)
805{
806 outb(SIO_LOCK_KEY, base);
807}
808
Hans de Goede2f650632009-01-07 16:37:31 +0100809static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200810{
811 return reg ? (1500000 / reg) : 0;
812}
813
Hans de Goede2f650632009-01-07 16:37:31 +0100814static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100815{
816 return fan ? (1500000 / fan) : 0;
817}
818
Hans de Goede45fb3662007-07-13 14:34:19 +0200819static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
820{
821 u8 val;
822
823 outb(reg, data->addr + ADDR_REG_OFFSET);
824 val = inb(data->addr + DATA_REG_OFFSET);
825
826 return val;
827}
828
829static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
830{
831 u16 val;
832
833 outb(reg++, data->addr + ADDR_REG_OFFSET);
834 val = inb(data->addr + DATA_REG_OFFSET) << 8;
835 outb(reg, data->addr + ADDR_REG_OFFSET);
836 val |= inb(data->addr + DATA_REG_OFFSET);
837
838 return val;
839}
840
841static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
842{
843 outb(reg, data->addr + ADDR_REG_OFFSET);
844 outb(val, data->addr + DATA_REG_OFFSET);
845}
846
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100847static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
848{
849 outb(reg++, data->addr + ADDR_REG_OFFSET);
850 outb(val >> 8, data->addr + DATA_REG_OFFSET);
851 outb(reg, data->addr + ADDR_REG_OFFSET);
852 outb(val & 255, data->addr + DATA_REG_OFFSET);
853}
854
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100855static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200856{
857 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100858 int nr, reg = 0, reg2;
859 int nr_fans = (data->type == f71882fg) ? 4 : 3;
860 int nr_ins = (data->type == f8000) ? 3 : 9;
861 int temp_start = (data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +0200862
863 mutex_lock(&data->update_lock);
864
865 /* Update once every 60 seconds */
866 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
867 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100868 if (data->type == f71882fg) {
869 data->in1_max =
870 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
871 data->in_beep =
872 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
873 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200874
875 /* Get High & boundary temps*/
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100876 for (nr = temp_start; nr < 3 + temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200877 data->temp_ovt[nr] = f71882fg_read8(data,
878 F71882FG_REG_TEMP_OVT(nr));
879 data->temp_high[nr] = f71882fg_read8(data,
880 F71882FG_REG_TEMP_HIGH(nr));
881 }
882
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100883 if (data->type != f8000) {
884 data->fan_beep = f71882fg_read8(data,
885 F71882FG_REG_FAN_BEEP);
886 data->temp_beep = f71882fg_read8(data,
887 F71882FG_REG_TEMP_BEEP);
888 data->temp_hyst[0] = f71882fg_read8(data,
889 F71882FG_REG_TEMP_HYST(0));
890 data->temp_hyst[1] = f71882fg_read8(data,
891 F71882FG_REG_TEMP_HYST(1));
892 /* Have to hardcode type, because temp1 is special */
893 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
894 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
895 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
896 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200897 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
898 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100899 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200900 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100901 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100902 else if (data->type != f8000)
Hans de Goede7567a042009-01-07 16:37:28 +0100903 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100904 else
905 data->temp_type[1] = 2; /* F8000 only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200906
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100907 data->pwm_enable = f71882fg_read8(data,
908 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100909 data->pwm_auto_point_hyst[0] =
910 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
911 data->pwm_auto_point_hyst[1] =
912 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
913
Hans de Goede498be962009-01-07 16:37:28 +0100914 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100915 data->pwm_auto_point_mapping[nr] =
916 f71882fg_read8(data,
917 F71882FG_REG_POINT_MAPPING(nr));
918
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100919 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100920 int point;
921 for (point = 0; point < 5; point++) {
922 data->pwm_auto_point_pwm[nr][point] =
923 f71882fg_read8(data,
924 F71882FG_REG_POINT_PWM
925 (nr, point));
926 }
927 for (point = 0; point < 4; point++) {
928 data->pwm_auto_point_temp[nr][point] =
929 f71882fg_read8(data,
930 F71882FG_REG_POINT_TEMP
931 (nr, point));
932 }
933 } else {
934 data->pwm_auto_point_pwm[nr][1] =
935 f71882fg_read8(data,
936 F71882FG_REG_POINT_PWM
937 (nr, 1));
938 data->pwm_auto_point_pwm[nr][4] =
939 f71882fg_read8(data,
940 F71882FG_REG_POINT_PWM
941 (nr, 4));
942 data->pwm_auto_point_temp[nr][0] =
943 f71882fg_read8(data,
944 F71882FG_REG_POINT_TEMP
945 (nr, 0));
946 data->pwm_auto_point_temp[nr][3] =
947 f71882fg_read8(data,
948 F71882FG_REG_POINT_TEMP
949 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100950 }
951 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200952 data->last_limits = jiffies;
953 }
954
955 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400956 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200957 data->temp_status = f71882fg_read8(data,
958 F71882FG_REG_TEMP_STATUS);
959 data->temp_diode_open = f71882fg_read8(data,
960 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100961 for (nr = temp_start; nr < 3 + temp_start; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200962 data->temp[nr] = f71882fg_read8(data,
963 F71882FG_REG_TEMP(nr));
964
965 data->fan_status = f71882fg_read8(data,
966 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +0100967 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200968 data->fan[nr] = f71882fg_read16(data,
969 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100970 data->fan_target[nr] =
971 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
972 data->fan_full_speed[nr] =
973 f71882fg_read16(data,
974 F71882FG_REG_FAN_FULL_SPEED(nr));
975 data->pwm[nr] =
976 f71882fg_read8(data, F71882FG_REG_PWM(nr));
977 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200978
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100979 /* The f8000 can monitor 1 more fan, but has no pwm for it */
980 if (data->type == f8000)
981 data->fan[3] = f71882fg_read16(data,
982 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +0100983 if (data->type == f71882fg)
984 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +0200985 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100986 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200987 data->in[nr] = f71882fg_read8(data,
988 F71882FG_REG_IN(nr));
989
990 data->last_updated = jiffies;
991 data->valid = 1;
992 }
993
994 mutex_unlock(&data->update_lock);
995
996 return data;
997}
998
999/* Sysfs Interface */
1000static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1001 char *buf)
1002{
1003 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001004 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001005 int speed = fan_from_reg(data->fan[nr]);
1006
1007 if (speed == FAN_MIN_DETECT)
1008 speed = 0;
1009
1010 return sprintf(buf, "%d\n", speed);
1011}
1012
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001013static ssize_t show_fan_full_speed(struct device *dev,
1014 struct device_attribute *devattr, char *buf)
1015{
1016 struct f71882fg_data *data = f71882fg_update_device(dev);
1017 int nr = to_sensor_dev_attr_2(devattr)->index;
1018 int speed = fan_from_reg(data->fan_full_speed[nr]);
1019 return sprintf(buf, "%d\n", speed);
1020}
1021
1022static ssize_t store_fan_full_speed(struct device *dev,
1023 struct device_attribute *devattr,
1024 const char *buf, size_t count)
1025{
1026 struct f71882fg_data *data = dev_get_drvdata(dev);
1027 int nr = to_sensor_dev_attr_2(devattr)->index;
1028 long val = simple_strtol(buf, NULL, 10);
1029
1030 val = SENSORS_LIMIT(val, 23, 1500000);
1031 val = fan_to_reg(val);
1032
1033 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001034 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1035 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001036 mutex_unlock(&data->update_lock);
1037
1038 return count;
1039}
1040
Hans de Goede45fb3662007-07-13 14:34:19 +02001041static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1042 *devattr, char *buf)
1043{
1044 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001045 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001046
1047 if (data->fan_beep & (1 << nr))
1048 return sprintf(buf, "1\n");
1049 else
1050 return sprintf(buf, "0\n");
1051}
1052
1053static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1054 *devattr, const char *buf, size_t count)
1055{
1056 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001057 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001058 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001059
1060 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001061 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001062 if (val)
1063 data->fan_beep |= 1 << nr;
1064 else
1065 data->fan_beep &= ~(1 << nr);
1066
1067 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1068 mutex_unlock(&data->update_lock);
1069
1070 return count;
1071}
1072
1073static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1074 *devattr, char *buf)
1075{
1076 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001077 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001078
1079 if (data->fan_status & (1 << nr))
1080 return sprintf(buf, "1\n");
1081 else
1082 return sprintf(buf, "0\n");
1083}
1084
1085static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1086 char *buf)
1087{
1088 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001089 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001090
1091 return sprintf(buf, "%d\n", data->in[nr] * 8);
1092}
1093
1094static ssize_t show_in_max(struct device *dev, struct device_attribute
1095 *devattr, char *buf)
1096{
1097 struct f71882fg_data *data = f71882fg_update_device(dev);
1098
1099 return sprintf(buf, "%d\n", data->in1_max * 8);
1100}
1101
1102static ssize_t store_in_max(struct device *dev, struct device_attribute
1103 *devattr, const char *buf, size_t count)
1104{
1105 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001106 long val = simple_strtol(buf, NULL, 10) / 8;
1107 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001108
1109 mutex_lock(&data->update_lock);
1110 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1111 data->in1_max = val;
1112 mutex_unlock(&data->update_lock);
1113
1114 return count;
1115}
1116
1117static ssize_t show_in_beep(struct device *dev, struct device_attribute
1118 *devattr, char *buf)
1119{
1120 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001121 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001122
1123 if (data->in_beep & (1 << nr))
1124 return sprintf(buf, "1\n");
1125 else
1126 return sprintf(buf, "0\n");
1127}
1128
1129static ssize_t store_in_beep(struct device *dev, struct device_attribute
1130 *devattr, const char *buf, size_t count)
1131{
1132 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001133 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001134 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001135
1136 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001137 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001138 if (val)
1139 data->in_beep |= 1 << nr;
1140 else
1141 data->in_beep &= ~(1 << nr);
1142
1143 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1144 mutex_unlock(&data->update_lock);
1145
1146 return count;
1147}
1148
1149static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1150 *devattr, char *buf)
1151{
1152 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001153 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001154
1155 if (data->in_status & (1 << nr))
1156 return sprintf(buf, "1\n");
1157 else
1158 return sprintf(buf, "0\n");
1159}
1160
1161static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1162 char *buf)
1163{
1164 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001165 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001166
1167 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
1168}
1169
1170static ssize_t show_temp_max(struct device *dev, struct device_attribute
1171 *devattr, char *buf)
1172{
1173 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001174 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001175
1176 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1177}
1178
1179static ssize_t store_temp_max(struct device *dev, struct device_attribute
1180 *devattr, const char *buf, size_t count)
1181{
1182 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001183 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001184 long val = simple_strtol(buf, NULL, 10) / 1000;
1185 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001186
1187 mutex_lock(&data->update_lock);
1188 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1189 data->temp_high[nr] = val;
1190 mutex_unlock(&data->update_lock);
1191
1192 return count;
1193}
1194
1195static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1196 *devattr, char *buf)
1197{
1198 struct f71882fg_data *data = f71882fg_update_device(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 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001201
Hans de Goedece0bfa52009-01-07 16:37:28 +01001202 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001203 if (nr & 1)
1204 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1205 else
1206 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1207 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001208 mutex_unlock(&data->update_lock);
1209
1210 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001211}
1212
1213static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1214 *devattr, const char *buf, size_t count)
1215{
1216 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001217 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001218 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001219 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001220 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001221
1222 mutex_lock(&data->update_lock);
1223
1224 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001225 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1226 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1227 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001228 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001229
1230 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001231 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1232 if (nr & 1)
1233 reg = (reg & 0x0f) | (val << 4);
1234 else
1235 reg = (reg & 0xf0) | val;
1236 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1237 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001238
Hans de Goede45fb3662007-07-13 14:34:19 +02001239 mutex_unlock(&data->update_lock);
1240 return ret;
1241}
1242
1243static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1244 *devattr, char *buf)
1245{
1246 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001247 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001248
1249 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1250}
1251
1252static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1253 *devattr, const char *buf, size_t count)
1254{
1255 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001256 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001257 long val = simple_strtol(buf, NULL, 10) / 1000;
1258 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001259
1260 mutex_lock(&data->update_lock);
1261 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1262 data->temp_ovt[nr] = val;
1263 mutex_unlock(&data->update_lock);
1264
1265 return count;
1266}
1267
1268static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1269 *devattr, char *buf)
1270{
1271 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001272 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001273 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001274
Hans de Goedece0bfa52009-01-07 16:37:28 +01001275 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001276 if (nr & 1)
1277 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1278 else
1279 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1280 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001281 mutex_unlock(&data->update_lock);
1282
1283 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001284}
1285
1286static ssize_t show_temp_type(struct device *dev, struct device_attribute
1287 *devattr, char *buf)
1288{
1289 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001290 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001291
1292 return sprintf(buf, "%d\n", data->temp_type[nr]);
1293}
1294
1295static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1296 *devattr, char *buf)
1297{
1298 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001299 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001300
Hans de Goede7567a042009-01-07 16:37:28 +01001301 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001302 return sprintf(buf, "1\n");
1303 else
1304 return sprintf(buf, "0\n");
1305}
1306
1307static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1308 *devattr, const char *buf, size_t count)
1309{
1310 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001311 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001312 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001313
1314 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001315 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001316 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001317 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001318 else
Hans de Goede7567a042009-01-07 16:37:28 +01001319 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001320
1321 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1322 mutex_unlock(&data->update_lock);
1323
1324 return count;
1325}
1326
1327static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1328 *devattr, char *buf)
1329{
1330 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001331 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001332
Hans de Goede7567a042009-01-07 16:37:28 +01001333 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001334 return sprintf(buf, "1\n");
1335 else
1336 return sprintf(buf, "0\n");
1337}
1338
1339static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1340 *devattr, char *buf)
1341{
1342 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001343 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001344
Hans de Goede7567a042009-01-07 16:37:28 +01001345 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001346 return sprintf(buf, "1\n");
1347 else
1348 return sprintf(buf, "0\n");
1349}
1350
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001351static ssize_t show_pwm(struct device *dev,
1352 struct device_attribute *devattr, char *buf)
1353{
1354 struct f71882fg_data *data = f71882fg_update_device(dev);
1355 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001356 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001357 if (data->pwm_enable & (1 << (2 * nr)))
1358 /* PWM mode */
1359 val = data->pwm[nr];
1360 else {
1361 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001362 val = 255 * fan_from_reg(data->fan_target[nr])
1363 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001364 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001365 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001366 return sprintf(buf, "%d\n", val);
1367}
1368
1369static ssize_t store_pwm(struct device *dev,
1370 struct device_attribute *devattr, const char *buf,
1371 size_t count)
1372{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001373 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001374 int nr = to_sensor_dev_attr_2(devattr)->index;
1375 long val = simple_strtol(buf, NULL, 10);
1376 val = SENSORS_LIMIT(val, 0, 255);
1377
1378 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001379 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001380 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1381 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1382 count = -EROFS;
1383 goto leave;
1384 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001385 if (data->pwm_enable & (1 << (2 * nr))) {
1386 /* PWM mode */
1387 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1388 data->pwm[nr] = val;
1389 } else {
1390 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001391 int target, full_speed;
1392 full_speed = f71882fg_read16(data,
1393 F71882FG_REG_FAN_FULL_SPEED(nr));
1394 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1395 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1396 data->fan_target[nr] = target;
1397 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001398 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001399leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001400 mutex_unlock(&data->update_lock);
1401
1402 return count;
1403}
1404
1405static ssize_t show_pwm_enable(struct device *dev,
1406 struct device_attribute *devattr, char *buf)
1407{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001408 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001409 struct f71882fg_data *data = f71882fg_update_device(dev);
1410 int nr = to_sensor_dev_attr_2(devattr)->index;
1411
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001412 switch ((data->pwm_enable >> 2 * nr) & 3) {
1413 case 0:
1414 case 1:
1415 result = 2; /* Normal auto mode */
1416 break;
1417 case 2:
1418 result = 1; /* Manual mode */
1419 break;
1420 case 3:
1421 if (data->type == f8000)
1422 result = 3; /* Thermostat mode */
1423 else
1424 result = 1; /* Manual mode */
1425 break;
1426 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001427
1428 return sprintf(buf, "%d\n", result);
1429}
1430
1431static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1432 *devattr, const char *buf, size_t count)
1433{
1434 struct f71882fg_data *data = dev_get_drvdata(dev);
1435 int nr = to_sensor_dev_attr_2(devattr)->index;
1436 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001437
Hans de Goede3fc78382009-06-15 18:39:50 +02001438 /* Special case for F8000 pwm channel 3 which only does auto mode */
1439 if (data->type == f8000 && nr == 2 && val != 2)
1440 return -EINVAL;
1441
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001442 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001443 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001444 /* Special case for F8000 auto PWM mode / Thermostat mode */
1445 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1446 switch (val) {
1447 case 2:
1448 data->pwm_enable &= ~(2 << (2 * nr));
1449 break; /* Normal auto mode */
1450 case 3:
1451 data->pwm_enable |= 2 << (2 * nr);
1452 break; /* Thermostat mode */
1453 default:
1454 count = -EINVAL;
1455 goto leave;
1456 }
1457 } else {
1458 switch (val) {
1459 case 1:
1460 data->pwm_enable |= 2 << (2 * nr);
1461 break; /* Manual */
1462 case 2:
1463 data->pwm_enable &= ~(2 << (2 * nr));
1464 break; /* Normal auto mode */
1465 default:
1466 count = -EINVAL;
1467 goto leave;
1468 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001469 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001470 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001471leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001472 mutex_unlock(&data->update_lock);
1473
1474 return count;
1475}
1476
1477static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1478 struct device_attribute *devattr,
1479 char *buf)
1480{
1481 int result;
1482 struct f71882fg_data *data = f71882fg_update_device(dev);
1483 int pwm = to_sensor_dev_attr_2(devattr)->index;
1484 int point = to_sensor_dev_attr_2(devattr)->nr;
1485
Hans de Goedece0bfa52009-01-07 16:37:28 +01001486 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001487 if (data->pwm_enable & (1 << (2 * pwm))) {
1488 /* PWM mode */
1489 result = data->pwm_auto_point_pwm[pwm][point];
1490 } else {
1491 /* RPM mode */
1492 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1493 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001494 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001495
1496 return sprintf(buf, "%d\n", result);
1497}
1498
1499static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1500 struct device_attribute *devattr,
1501 const char *buf, size_t count)
1502{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001503 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001504 int pwm = to_sensor_dev_attr_2(devattr)->index;
1505 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001506 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001507 val = SENSORS_LIMIT(val, 0, 255);
1508
1509 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001510 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001511 if (data->pwm_enable & (1 << (2 * pwm))) {
1512 /* PWM mode */
1513 } else {
1514 /* RPM mode */
1515 if (val < 29) /* Prevent negative numbers */
1516 val = 255;
1517 else
1518 val = (255 - val) * 32 / val;
1519 }
1520 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1521 data->pwm_auto_point_pwm[pwm][point] = val;
1522 mutex_unlock(&data->update_lock);
1523
1524 return count;
1525}
1526
1527static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1528 struct device_attribute *devattr,
1529 char *buf)
1530{
1531 int result = 0;
1532 struct f71882fg_data *data = f71882fg_update_device(dev);
1533 int nr = to_sensor_dev_attr_2(devattr)->index;
1534 int point = to_sensor_dev_attr_2(devattr)->nr;
1535
1536 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001537 if (nr & 1)
1538 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1539 else
1540 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001541 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1542 mutex_unlock(&data->update_lock);
1543
1544 return sprintf(buf, "%d\n", result);
1545}
1546
1547static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1548 struct device_attribute *devattr,
1549 const char *buf, size_t count)
1550{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001551 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001552 int nr = to_sensor_dev_attr_2(devattr)->index;
1553 int point = to_sensor_dev_attr_2(devattr)->nr;
1554 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001555 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001556
1557 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001558 data->pwm_auto_point_temp[nr][point] =
1559 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001560 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1561 data->pwm_auto_point_temp[nr][point]);
1562 val = data->pwm_auto_point_temp[nr][point] - val;
1563
Hans de Goedebc274902009-01-07 16:37:29 +01001564 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1565 if (nr & 1)
1566 reg = (reg & 0x0f) | (val << 4);
1567 else
1568 reg = (reg & 0xf0) | val;
1569
1570 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1571 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001572 mutex_unlock(&data->update_lock);
1573
1574 return count;
1575}
1576
1577static ssize_t show_pwm_interpolate(struct device *dev,
1578 struct device_attribute *devattr, char *buf)
1579{
1580 int result;
1581 struct f71882fg_data *data = f71882fg_update_device(dev);
1582 int nr = to_sensor_dev_attr_2(devattr)->index;
1583
1584 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1585
1586 return sprintf(buf, "%d\n", result);
1587}
1588
1589static ssize_t store_pwm_interpolate(struct device *dev,
1590 struct device_attribute *devattr,
1591 const char *buf, size_t count)
1592{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001593 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001594 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001595 unsigned long val = simple_strtoul(buf, NULL, 10);
1596
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001597 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001598 data->pwm_auto_point_mapping[nr] =
1599 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001600 if (val)
1601 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1602 else
1603 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1604 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1605 data->pwm_auto_point_mapping[nr] = val;
1606 mutex_unlock(&data->update_lock);
1607
1608 return count;
1609}
1610
1611static ssize_t show_pwm_auto_point_channel(struct device *dev,
1612 struct device_attribute *devattr,
1613 char *buf)
1614{
1615 int result;
1616 struct f71882fg_data *data = f71882fg_update_device(dev);
1617 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001618 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001619
Hans de Goede30453012009-01-07 16:37:30 +01001620 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001621
1622 return sprintf(buf, "%d\n", result);
1623}
1624
1625static ssize_t store_pwm_auto_point_channel(struct device *dev,
1626 struct device_attribute *devattr,
1627 const char *buf, size_t count)
1628{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001629 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001630 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001631 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001632 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001633
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001634 switch (val) {
1635 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001636 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001637 break;
1638 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001639 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001640 break;
1641 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001642 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001643 break;
1644 default:
1645 return -EINVAL;
1646 }
Hans de Goede30453012009-01-07 16:37:30 +01001647 val += temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001648 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001649 data->pwm_auto_point_mapping[nr] =
1650 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001651 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1652 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1653 data->pwm_auto_point_mapping[nr] = val;
1654 mutex_unlock(&data->update_lock);
1655
1656 return count;
1657}
1658
1659static ssize_t show_pwm_auto_point_temp(struct device *dev,
1660 struct device_attribute *devattr,
1661 char *buf)
1662{
1663 int result;
1664 struct f71882fg_data *data = f71882fg_update_device(dev);
1665 int pwm = to_sensor_dev_attr_2(devattr)->index;
1666 int point = to_sensor_dev_attr_2(devattr)->nr;
1667
1668 result = data->pwm_auto_point_temp[pwm][point];
1669 return sprintf(buf, "%d\n", 1000 * result);
1670}
1671
1672static ssize_t store_pwm_auto_point_temp(struct device *dev,
1673 struct device_attribute *devattr,
1674 const char *buf, size_t count)
1675{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001676 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001677 int pwm = to_sensor_dev_attr_2(devattr)->index;
1678 int point = to_sensor_dev_attr_2(devattr)->nr;
1679 long val = simple_strtol(buf, NULL, 10) / 1000;
1680 val = SENSORS_LIMIT(val, 0, 255);
1681
1682 mutex_lock(&data->update_lock);
1683 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1684 data->pwm_auto_point_temp[pwm][point] = val;
1685 mutex_unlock(&data->update_lock);
1686
1687 return count;
1688}
1689
Hans de Goede45fb3662007-07-13 14:34:19 +02001690static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1691 char *buf)
1692{
Hans de Goede498be962009-01-07 16:37:28 +01001693 struct f71882fg_data *data = dev_get_drvdata(dev);
1694 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001695}
1696
Hans de Goedec13548c2009-01-07 16:37:27 +01001697static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1698 struct sensor_device_attribute_2 *attr, int count)
1699{
1700 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001701
Hans de Goedec13548c2009-01-07 16:37:27 +01001702 for (i = 0; i < count; i++) {
1703 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1704 if (err)
1705 return err;
1706 }
1707 return 0;
1708}
1709
1710static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001711{
1712 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001713 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001714 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001715 u8 start_reg;
1716
Hans de Goedec13548c2009-01-07 16:37:27 +01001717 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1718 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001719 return -ENOMEM;
1720
1721 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001722 data->type = sio_data->type;
Hans de Goede45fb3662007-07-13 14:34:19 +02001723 mutex_init(&data->update_lock);
1724 platform_set_drvdata(pdev, data);
1725
Hans de Goede3cc74752009-01-07 16:37:28 +01001726 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001727 if (start_reg & 0x04) {
1728 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1729 err = -ENODEV;
1730 goto exit_free;
1731 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001732 if (!(start_reg & 0x03)) {
1733 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1734 err = -ENODEV;
1735 goto exit_free;
1736 }
1737
Hans de Goede28ba8582009-01-07 16:37:31 +01001738 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goede3cc74752009-01-07 16:37:28 +01001739 /* If it is a 71862 and the fan / pwm part is enabled sanity check
1740 the pwm settings */
1741 if (data->type == f71862fg && (start_reg & 0x02)) {
Hans de Goede28ba8582009-01-07 16:37:31 +01001742 if ((data->pwm_enable & 0x15) != 0x15) {
Hans de Goede3cc74752009-01-07 16:37:28 +01001743 dev_err(&pdev->dev,
1744 "Invalid (reserved) pwm settings: 0x%02x\n",
Hans de Goede28ba8582009-01-07 16:37:31 +01001745 (unsigned int)data->pwm_enable);
Hans de Goede3cc74752009-01-07 16:37:28 +01001746 err = -ENODEV;
1747 goto exit_free;
1748 }
1749 }
1750
Hans de Goede45fb3662007-07-13 14:34:19 +02001751 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001752 err = device_create_file(&pdev->dev, &dev_attr_name);
1753 if (err)
1754 goto exit_unregister_sysfs;
1755
Hans de Goedec13548c2009-01-07 16:37:27 +01001756 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001757 switch (data->type) {
1758 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001759 err = f71882fg_create_sysfs_files(pdev,
1760 f71882fg_in_temp_attr,
1761 ARRAY_SIZE(f71882fg_in_temp_attr));
1762 if (err)
1763 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001764 /* fall through! */
1765 case f71862fg:
1766 err = f71882fg_create_sysfs_files(pdev,
1767 f718x2fg_in_temp_attr,
1768 ARRAY_SIZE(f718x2fg_in_temp_attr));
1769 break;
1770 case f8000:
1771 err = f71882fg_create_sysfs_files(pdev,
1772 f8000_in_temp_attr,
1773 ARRAY_SIZE(f8000_in_temp_attr));
1774 break;
Hans de Goede498be962009-01-07 16:37:28 +01001775 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001776 if (err)
1777 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001778 }
1779
Hans de Goede45fb3662007-07-13 14:34:19 +02001780 if (start_reg & 0x02) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001781 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1782 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001783 if (err)
1784 goto exit_unregister_sysfs;
1785
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001786 switch (data->type) {
1787 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001788 err = f71882fg_create_sysfs_files(pdev,
1789 f71862fg_fan_attr,
1790 ARRAY_SIZE(f71862fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001791 break;
1792 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001793 err = f71882fg_create_sysfs_files(pdev,
1794 f71882fg_fan_attr,
Hans de Goedec13548c2009-01-07 16:37:27 +01001795 ARRAY_SIZE(f71882fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001796 break;
1797 case f8000:
1798 err = f71882fg_create_sysfs_files(pdev,
1799 f8000_fan_attr,
1800 ARRAY_SIZE(f8000_fan_attr));
1801 break;
Hans de Goede498be962009-01-07 16:37:28 +01001802 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001803 if (err)
1804 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001805
1806 for (i = 0; i < nr_fans; i++)
1807 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1808 (data->pwm_enable & (1 << 2 * i)) ?
1809 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001810 }
1811
Tony Jones1beeffe2007-08-20 13:46:20 -07001812 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1813 if (IS_ERR(data->hwmon_dev)) {
1814 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001815 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001816 goto exit_unregister_sysfs;
1817 }
1818
1819 return 0;
1820
1821exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001822 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001823 return err; /* f71882fg_remove() also frees our data */
1824exit_free:
1825 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001826 return err;
1827}
1828
Hans de Goedec13548c2009-01-07 16:37:27 +01001829static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001830{
1831 int i;
1832 struct f71882fg_data *data = platform_get_drvdata(pdev);
1833
1834 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001835 if (data->hwmon_dev)
1836 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001837
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001838 /* Note we are not looping over all attr arrays we have as the ones
1839 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001840 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001841
Hans de Goede498be962009-01-07 16:37:28 +01001842 for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
1843 device_remove_file(&pdev->dev,
1844 &f718x2fg_in_temp_attr[i].dev_attr);
1845
Hans de Goede45fb3662007-07-13 14:34:19 +02001846 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1847 device_remove_file(&pdev->dev,
1848 &f71882fg_in_temp_attr[i].dev_attr);
1849
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001850 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
1851 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001852
Hans de Goede45fb3662007-07-13 14:34:19 +02001853 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1854 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1855
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001856 for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
1857 device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
1858
Hans de Goede45fb3662007-07-13 14:34:19 +02001859 kfree(data);
1860
1861 return 0;
1862}
1863
Hans de Goede498be962009-01-07 16:37:28 +01001864static int __init f71882fg_find(int sioaddr, unsigned short *address,
1865 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001866{
1867 int err = -ENODEV;
1868 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02001869
1870 superio_enter(sioaddr);
1871
1872 devid = superio_inw(sioaddr, SIO_REG_MANID);
1873 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01001874 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02001875 goto exit;
1876 }
1877
Jean Delvare67b671b2007-12-06 23:13:42 +01001878 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01001879 switch (devid) {
1880 case SIO_F71862_ID:
1881 sio_data->type = f71862fg;
1882 break;
1883 case SIO_F71882_ID:
1884 sio_data->type = f71882fg;
1885 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001886 case SIO_F8000_ID:
1887 sio_data->type = f8000;
1888 break;
Hans de Goede498be962009-01-07 16:37:28 +01001889 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02001890 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
1891 goto exit;
1892 }
1893
1894 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001895 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001896 printk(KERN_WARNING DRVNAME ": Device not activated\n");
1897 goto exit;
1898 }
1899
1900 *address = superio_inw(sioaddr, SIO_REG_ADDR);
1901 if (*address == 0)
1902 {
1903 printk(KERN_WARNING DRVNAME ": Base address not set\n");
1904 goto exit;
1905 }
1906 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
1907
Hans de Goede45fb3662007-07-13 14:34:19 +02001908 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01001909 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
1910 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02001911 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
1912exit:
1913 superio_exit(sioaddr);
1914 return err;
1915}
1916
Hans de Goede498be962009-01-07 16:37:28 +01001917static int __init f71882fg_device_add(unsigned short address,
1918 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001919{
1920 struct resource res = {
1921 .start = address,
1922 .end = address + REGION_LENGTH - 1,
1923 .flags = IORESOURCE_IO,
1924 };
1925 int err;
1926
1927 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001928 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001929 return -ENOMEM;
1930
1931 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01001932 err = acpi_check_resource_conflict(&res);
1933 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001934 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001935
Hans de Goede45fb3662007-07-13 14:34:19 +02001936 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001937 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001938 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
1939 goto exit_device_put;
1940 }
1941
Hans de Goede498be962009-01-07 16:37:28 +01001942 err = platform_device_add_data(f71882fg_pdev, sio_data,
1943 sizeof(struct f71882fg_sio_data));
1944 if (err) {
1945 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1946 goto exit_device_put;
1947 }
1948
Hans de Goede45fb3662007-07-13 14:34:19 +02001949 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001950 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001951 printk(KERN_ERR DRVNAME ": Device addition failed\n");
1952 goto exit_device_put;
1953 }
1954
1955 return 0;
1956
1957exit_device_put:
1958 platform_device_put(f71882fg_pdev);
1959
1960 return err;
1961}
1962
1963static int __init f71882fg_init(void)
1964{
1965 int err = -ENODEV;
1966 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01001967 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02001968
Hans de Goede498be962009-01-07 16:37:28 +01001969 memset(&sio_data, 0, sizeof(sio_data));
1970
1971 if (f71882fg_find(0x2e, &address, &sio_data) &&
1972 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02001973 goto exit;
1974
Hans de Goedec13548c2009-01-07 16:37:27 +01001975 err = platform_driver_register(&f71882fg_driver);
1976 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001977 goto exit;
1978
Hans de Goede498be962009-01-07 16:37:28 +01001979 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01001980 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001981 goto exit_driver;
1982
1983 return 0;
1984
1985exit_driver:
1986 platform_driver_unregister(&f71882fg_driver);
1987exit:
1988 return err;
1989}
1990
1991static void __exit f71882fg_exit(void)
1992{
1993 platform_device_unregister(f71882fg_pdev);
1994 platform_driver_unregister(&f71882fg_driver);
1995}
1996
1997MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01001998MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02001999MODULE_LICENSE("GPL");
2000
2001module_init(f71882fg_init);
2002module_exit(f71882fg_exit);