blob: 7e5b94c19443a720a6e429e3d3f1d6863e86fc2a [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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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 Goede754a5907b2009-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),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200347 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100348 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
349 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
350 store_temp_crit, 0, 1),
351 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
352 store_temp_max, 0, 1),
353 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
354 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200355 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100356 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
357 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
358 store_temp_crit, 0, 2),
359 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
360 store_temp_max, 0, 2),
361 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200362 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100363};
364
365/* Fan / PWM attr common to all models */
366static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100367 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100368 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
369 show_fan_full_speed,
370 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100371 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
372 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100373 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
374 show_fan_full_speed,
375 store_fan_full_speed, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100376 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
377 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100378 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
379 show_fan_full_speed,
380 store_fan_full_speed, 0, 2),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100381 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100382
383 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
384 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
385 store_pwm_enable, 0, 0),
386 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
387 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
388 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
389 show_pwm_auto_point_channel,
390 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100391
392 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
393 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
394 store_pwm_enable, 0, 1),
395 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
396 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
397 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
398 show_pwm_auto_point_channel,
399 store_pwm_auto_point_channel, 0, 1),
400
Hans de Goede3fc78382009-06-15 18:39:50 +0200401 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
402 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
403 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100404 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
405 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
406 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
407 show_pwm_auto_point_channel,
408 store_pwm_auto_point_channel, 0, 2),
409};
410
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100411/* Fan / PWM attr for the f71862fg, less pwms and less zones per pwm than the
412 f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100413static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100414 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
415 store_fan_beep, 0, 0),
416 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
417 store_fan_beep, 0, 1),
418 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
419 store_fan_beep, 0, 2),
420
Hans de Goede498be962009-01-07 16:37:28 +0100421 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
422 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
423 1, 0),
424 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
425 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
426 4, 0),
427 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
428 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
429 0, 0),
430 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
431 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
432 3, 0),
433 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
434 show_pwm_auto_point_temp_hyst,
435 store_pwm_auto_point_temp_hyst,
436 0, 0),
437 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
438 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
439
440 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
441 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
442 1, 1),
443 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
444 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
445 4, 1),
446 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
447 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
448 0, 1),
449 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
450 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
451 3, 1),
452 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
453 show_pwm_auto_point_temp_hyst,
454 store_pwm_auto_point_temp_hyst,
455 0, 1),
456 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
457 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100458
Hans de Goede49010622009-01-07 16:37:30 +0100459 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
460 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
461 1, 2),
462 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
463 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
464 4, 2),
465 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
466 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
467 0, 2),
468 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
469 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
470 3, 2),
471 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
472 show_pwm_auto_point_temp_hyst,
473 store_pwm_auto_point_temp_hyst,
474 0, 2),
475 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
476 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100477};
478
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100479/* Fan / PWM attr for the f71882fg */
Hans de Goede498be962009-01-07 16:37:28 +0100480static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100481 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
482 store_fan_beep, 0, 0),
483 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
484 store_fan_beep, 0, 1),
485 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
486 store_fan_beep, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100487 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
488 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
489 show_fan_full_speed,
490 store_fan_full_speed, 0, 3),
491 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
492 store_fan_beep, 0, 3),
493 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
494
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100495 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
496 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
497 0, 0),
498 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
499 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
500 1, 0),
501 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
502 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
503 2, 0),
504 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
506 3, 0),
507 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 4, 0),
510 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
512 0, 0),
513 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 1, 0),
516 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 2, 0),
519 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
521 3, 0),
522 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
523 show_pwm_auto_point_temp_hyst,
524 store_pwm_auto_point_temp_hyst,
525 0, 0),
526 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
527 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
528 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
529 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
530 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
531 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
532
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100533 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
534 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
535 0, 1),
536 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
537 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
538 1, 1),
539 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
540 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
541 2, 1),
542 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
543 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
544 3, 1),
545 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
546 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
547 4, 1),
548 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
549 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
550 0, 1),
551 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
553 1, 1),
554 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
556 2, 1),
557 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
559 3, 1),
560 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_temp_hyst,
562 store_pwm_auto_point_temp_hyst,
563 0, 1),
564 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
565 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
566 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
567 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
568 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
569 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
570
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
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100662 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
664 0, 2),
665 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
667 1, 2),
668 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
670 2, 2),
671 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
672 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
673 3, 2),
674 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
676 4, 2),
677 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
679 0, 2),
680 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
682 1, 2),
683 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
685 2, 2),
686 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
688 3, 2),
689 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_temp_hyst,
691 store_pwm_auto_point_temp_hyst,
692 0, 2),
693 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
694 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
695 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
696 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
697 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
698 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
699
700 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
701 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
702 0, 0),
703 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
705 1, 0),
706 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
708 2, 0),
709 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
710 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
711 3, 0),
712 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
713 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
714 4, 0),
715 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
716 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
717 0, 0),
718 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
719 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
720 1, 0),
721 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
722 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
723 2, 0),
724 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
725 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
726 3, 0),
727 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
728 show_pwm_auto_point_temp_hyst,
729 store_pwm_auto_point_temp_hyst,
730 0, 0),
731 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
732 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
733 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
734 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
735 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
736 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
737
738 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
739 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
740 0, 1),
741 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
742 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
743 1, 1),
744 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
746 2, 1),
747 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
749 3, 1),
750 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
752 4, 1),
753 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
755 0, 1),
756 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
758 1, 1),
759 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
761 2, 1),
762 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
764 3, 1),
765 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
766 show_pwm_auto_point_temp_hyst,
767 store_pwm_auto_point_temp_hyst,
768 0, 1),
769 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
770 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
771 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
772 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
773 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
774 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
775};
Hans de Goede45fb3662007-07-13 14:34:19 +0200776
777/* Super I/O functions */
778static inline int superio_inb(int base, int reg)
779{
780 outb(reg, base);
781 return inb(base + 1);
782}
783
784static int superio_inw(int base, int reg)
785{
786 int val;
787 outb(reg++, base);
788 val = inb(base + 1) << 8;
789 outb(reg, base);
790 val |= inb(base + 1);
791 return val;
792}
793
794static inline void superio_enter(int base)
795{
796 /* according to the datasheet the key must be send twice! */
797 outb( SIO_UNLOCK_KEY, base);
798 outb( SIO_UNLOCK_KEY, base);
799}
800
801static inline void superio_select( int base, int ld)
802{
803 outb(SIO_REG_LDSEL, base);
804 outb(ld, base + 1);
805}
806
807static inline void superio_exit(int base)
808{
809 outb(SIO_LOCK_KEY, base);
810}
811
Hans de Goede2f650632009-01-07 16:37:31 +0100812static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200813{
814 return reg ? (1500000 / reg) : 0;
815}
816
Hans de Goede2f650632009-01-07 16:37:31 +0100817static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100818{
819 return fan ? (1500000 / fan) : 0;
820}
821
Hans de Goede45fb3662007-07-13 14:34:19 +0200822static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
823{
824 u8 val;
825
826 outb(reg, data->addr + ADDR_REG_OFFSET);
827 val = inb(data->addr + DATA_REG_OFFSET);
828
829 return val;
830}
831
832static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
833{
834 u16 val;
835
836 outb(reg++, data->addr + ADDR_REG_OFFSET);
837 val = inb(data->addr + DATA_REG_OFFSET) << 8;
838 outb(reg, data->addr + ADDR_REG_OFFSET);
839 val |= inb(data->addr + DATA_REG_OFFSET);
840
841 return val;
842}
843
844static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
845{
846 outb(reg, data->addr + ADDR_REG_OFFSET);
847 outb(val, data->addr + DATA_REG_OFFSET);
848}
849
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100850static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
851{
852 outb(reg++, data->addr + ADDR_REG_OFFSET);
853 outb(val >> 8, data->addr + DATA_REG_OFFSET);
854 outb(reg, data->addr + ADDR_REG_OFFSET);
855 outb(val & 255, data->addr + DATA_REG_OFFSET);
856}
857
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100858static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200859{
860 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100861 int nr, reg = 0, reg2;
862 int nr_fans = (data->type == f71882fg) ? 4 : 3;
863 int nr_ins = (data->type == f8000) ? 3 : 9;
864 int temp_start = (data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +0200865
866 mutex_lock(&data->update_lock);
867
868 /* Update once every 60 seconds */
869 if ( time_after(jiffies, data->last_limits + 60 * HZ ) ||
870 !data->valid) {
Hans de Goede498be962009-01-07 16:37:28 +0100871 if (data->type == f71882fg) {
872 data->in1_max =
873 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
874 data->in_beep =
875 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
876 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200877
878 /* Get High & boundary temps*/
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100879 for (nr = temp_start; nr < 3 + temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200880 data->temp_ovt[nr] = f71882fg_read8(data,
881 F71882FG_REG_TEMP_OVT(nr));
882 data->temp_high[nr] = f71882fg_read8(data,
883 F71882FG_REG_TEMP_HIGH(nr));
884 }
885
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100886 if (data->type != f8000) {
887 data->fan_beep = f71882fg_read8(data,
888 F71882FG_REG_FAN_BEEP);
889 data->temp_beep = f71882fg_read8(data,
890 F71882FG_REG_TEMP_BEEP);
891 data->temp_hyst[0] = f71882fg_read8(data,
892 F71882FG_REG_TEMP_HYST(0));
893 data->temp_hyst[1] = f71882fg_read8(data,
894 F71882FG_REG_TEMP_HYST(1));
895 /* Have to hardcode type, because temp1 is special */
896 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
897 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
898 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
899 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200900 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
901 if ((reg2 & 0x03) == 0x01)
Hans de Goede7567a042009-01-07 16:37:28 +0100902 data->temp_type[1] = 6 /* PECI */;
Hans de Goede45fb3662007-07-13 14:34:19 +0200903 else if ((reg2 & 0x03) == 0x02)
Hans de Goede7567a042009-01-07 16:37:28 +0100904 data->temp_type[1] = 5 /* AMDSI */;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100905 else if (data->type != f8000)
Hans de Goede7567a042009-01-07 16:37:28 +0100906 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100907 else
908 data->temp_type[1] = 2; /* F8000 only supports BJT */
Hans de Goede45fb3662007-07-13 14:34:19 +0200909
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100910 data->pwm_enable = f71882fg_read8(data,
911 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100912 data->pwm_auto_point_hyst[0] =
913 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
914 data->pwm_auto_point_hyst[1] =
915 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
916
Hans de Goede498be962009-01-07 16:37:28 +0100917 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100918 data->pwm_auto_point_mapping[nr] =
919 f71882fg_read8(data,
920 F71882FG_REG_POINT_MAPPING(nr));
921
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100922 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100923 int point;
924 for (point = 0; point < 5; point++) {
925 data->pwm_auto_point_pwm[nr][point] =
926 f71882fg_read8(data,
927 F71882FG_REG_POINT_PWM
928 (nr, point));
929 }
930 for (point = 0; point < 4; point++) {
931 data->pwm_auto_point_temp[nr][point] =
932 f71882fg_read8(data,
933 F71882FG_REG_POINT_TEMP
934 (nr, point));
935 }
936 } else {
937 data->pwm_auto_point_pwm[nr][1] =
938 f71882fg_read8(data,
939 F71882FG_REG_POINT_PWM
940 (nr, 1));
941 data->pwm_auto_point_pwm[nr][4] =
942 f71882fg_read8(data,
943 F71882FG_REG_POINT_PWM
944 (nr, 4));
945 data->pwm_auto_point_temp[nr][0] =
946 f71882fg_read8(data,
947 F71882FG_REG_POINT_TEMP
948 (nr, 0));
949 data->pwm_auto_point_temp[nr][3] =
950 f71882fg_read8(data,
951 F71882FG_REG_POINT_TEMP
952 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100953 }
954 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200955 data->last_limits = jiffies;
956 }
957
958 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -0400959 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200960 data->temp_status = f71882fg_read8(data,
961 F71882FG_REG_TEMP_STATUS);
962 data->temp_diode_open = f71882fg_read8(data,
963 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100964 for (nr = temp_start; nr < 3 + temp_start; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200965 data->temp[nr] = f71882fg_read8(data,
966 F71882FG_REG_TEMP(nr));
967
968 data->fan_status = f71882fg_read8(data,
969 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +0100970 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200971 data->fan[nr] = f71882fg_read16(data,
972 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100973 data->fan_target[nr] =
974 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
975 data->fan_full_speed[nr] =
976 f71882fg_read16(data,
977 F71882FG_REG_FAN_FULL_SPEED(nr));
978 data->pwm[nr] =
979 f71882fg_read8(data, F71882FG_REG_PWM(nr));
980 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200981
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100982 /* The f8000 can monitor 1 more fan, but has no pwm for it */
983 if (data->type == f8000)
984 data->fan[3] = f71882fg_read16(data,
985 F71882FG_REG_FAN(3));
Hans de Goede498be962009-01-07 16:37:28 +0100986 if (data->type == f71882fg)
987 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +0200988 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100989 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +0200990 data->in[nr] = f71882fg_read8(data,
991 F71882FG_REG_IN(nr));
992
993 data->last_updated = jiffies;
994 data->valid = 1;
995 }
996
997 mutex_unlock(&data->update_lock);
998
999 return data;
1000}
1001
1002/* Sysfs Interface */
1003static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1004 char *buf)
1005{
1006 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001007 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001008 int speed = fan_from_reg(data->fan[nr]);
1009
1010 if (speed == FAN_MIN_DETECT)
1011 speed = 0;
1012
1013 return sprintf(buf, "%d\n", speed);
1014}
1015
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001016static ssize_t show_fan_full_speed(struct device *dev,
1017 struct device_attribute *devattr, char *buf)
1018{
1019 struct f71882fg_data *data = f71882fg_update_device(dev);
1020 int nr = to_sensor_dev_attr_2(devattr)->index;
1021 int speed = fan_from_reg(data->fan_full_speed[nr]);
1022 return sprintf(buf, "%d\n", speed);
1023}
1024
1025static ssize_t store_fan_full_speed(struct device *dev,
1026 struct device_attribute *devattr,
1027 const char *buf, size_t count)
1028{
1029 struct f71882fg_data *data = dev_get_drvdata(dev);
1030 int nr = to_sensor_dev_attr_2(devattr)->index;
1031 long val = simple_strtol(buf, NULL, 10);
1032
1033 val = SENSORS_LIMIT(val, 23, 1500000);
1034 val = fan_to_reg(val);
1035
1036 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001037 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1038 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001039 mutex_unlock(&data->update_lock);
1040
1041 return count;
1042}
1043
Hans de Goede45fb3662007-07-13 14:34:19 +02001044static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1045 *devattr, char *buf)
1046{
1047 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001048 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001049
1050 if (data->fan_beep & (1 << nr))
1051 return sprintf(buf, "1\n");
1052 else
1053 return sprintf(buf, "0\n");
1054}
1055
1056static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1057 *devattr, const char *buf, size_t count)
1058{
1059 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001060 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001061 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001062
1063 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001064 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001065 if (val)
1066 data->fan_beep |= 1 << nr;
1067 else
1068 data->fan_beep &= ~(1 << nr);
1069
1070 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1071 mutex_unlock(&data->update_lock);
1072
1073 return count;
1074}
1075
1076static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1077 *devattr, char *buf)
1078{
1079 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001080 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001081
1082 if (data->fan_status & (1 << nr))
1083 return sprintf(buf, "1\n");
1084 else
1085 return sprintf(buf, "0\n");
1086}
1087
1088static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1089 char *buf)
1090{
1091 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001092 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001093
1094 return sprintf(buf, "%d\n", data->in[nr] * 8);
1095}
1096
1097static ssize_t show_in_max(struct device *dev, struct device_attribute
1098 *devattr, char *buf)
1099{
1100 struct f71882fg_data *data = f71882fg_update_device(dev);
1101
1102 return sprintf(buf, "%d\n", data->in1_max * 8);
1103}
1104
1105static ssize_t store_in_max(struct device *dev, struct device_attribute
1106 *devattr, const char *buf, size_t count)
1107{
1108 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001109 long val = simple_strtol(buf, NULL, 10) / 8;
1110 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001111
1112 mutex_lock(&data->update_lock);
1113 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1114 data->in1_max = val;
1115 mutex_unlock(&data->update_lock);
1116
1117 return count;
1118}
1119
1120static ssize_t show_in_beep(struct device *dev, struct device_attribute
1121 *devattr, char *buf)
1122{
1123 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001124 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001125
1126 if (data->in_beep & (1 << nr))
1127 return sprintf(buf, "1\n");
1128 else
1129 return sprintf(buf, "0\n");
1130}
1131
1132static ssize_t store_in_beep(struct device *dev, struct device_attribute
1133 *devattr, const char *buf, size_t count)
1134{
1135 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001136 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001137 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001138
1139 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001140 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001141 if (val)
1142 data->in_beep |= 1 << nr;
1143 else
1144 data->in_beep &= ~(1 << nr);
1145
1146 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1147 mutex_unlock(&data->update_lock);
1148
1149 return count;
1150}
1151
1152static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1153 *devattr, char *buf)
1154{
1155 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001156 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001157
1158 if (data->in_status & (1 << nr))
1159 return sprintf(buf, "1\n");
1160 else
1161 return sprintf(buf, "0\n");
1162}
1163
1164static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1165 char *buf)
1166{
1167 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001168 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001169
1170 return sprintf(buf, "%d\n", data->temp[nr] * 1000);
1171}
1172
1173static ssize_t show_temp_max(struct device *dev, struct device_attribute
1174 *devattr, char *buf)
1175{
1176 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001177 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001178
1179 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1180}
1181
1182static ssize_t store_temp_max(struct device *dev, struct device_attribute
1183 *devattr, const char *buf, size_t count)
1184{
1185 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001186 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001187 long val = simple_strtol(buf, NULL, 10) / 1000;
1188 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001189
1190 mutex_lock(&data->update_lock);
1191 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1192 data->temp_high[nr] = val;
1193 mutex_unlock(&data->update_lock);
1194
1195 return count;
1196}
1197
1198static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1199 *devattr, char *buf)
1200{
1201 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001202 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001203 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001204
Hans de Goedece0bfa52009-01-07 16:37:28 +01001205 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001206 if (nr & 1)
1207 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1208 else
1209 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1210 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001211 mutex_unlock(&data->update_lock);
1212
1213 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001214}
1215
1216static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1217 *devattr, const char *buf, size_t count)
1218{
1219 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001220 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001221 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001222 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001223 u8 reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001224
1225 mutex_lock(&data->update_lock);
1226
1227 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001228 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1229 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1230 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001231 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001232
1233 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001234 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1235 if (nr & 1)
1236 reg = (reg & 0x0f) | (val << 4);
1237 else
1238 reg = (reg & 0xf0) | val;
1239 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1240 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001241
Hans de Goede45fb3662007-07-13 14:34:19 +02001242 mutex_unlock(&data->update_lock);
1243 return ret;
1244}
1245
1246static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1247 *devattr, char *buf)
1248{
1249 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001250 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001251
1252 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1253}
1254
1255static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1256 *devattr, const char *buf, size_t count)
1257{
1258 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001259 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001260 long val = simple_strtol(buf, NULL, 10) / 1000;
1261 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001262
1263 mutex_lock(&data->update_lock);
1264 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1265 data->temp_ovt[nr] = val;
1266 mutex_unlock(&data->update_lock);
1267
1268 return count;
1269}
1270
1271static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1272 *devattr, char *buf)
1273{
1274 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001275 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001276 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001277
Hans de Goedece0bfa52009-01-07 16:37:28 +01001278 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001279 if (nr & 1)
1280 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1281 else
1282 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1283 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001284 mutex_unlock(&data->update_lock);
1285
1286 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001287}
1288
1289static ssize_t show_temp_type(struct device *dev, struct device_attribute
1290 *devattr, char *buf)
1291{
1292 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001293 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001294
1295 return sprintf(buf, "%d\n", data->temp_type[nr]);
1296}
1297
1298static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1299 *devattr, char *buf)
1300{
1301 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001302 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001303
Hans de Goede7567a042009-01-07 16:37:28 +01001304 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001305 return sprintf(buf, "1\n");
1306 else
1307 return sprintf(buf, "0\n");
1308}
1309
1310static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1311 *devattr, const char *buf, size_t count)
1312{
1313 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001314 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001315 unsigned long val = simple_strtoul(buf, NULL, 10);
Hans de Goede45fb3662007-07-13 14:34:19 +02001316
1317 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001318 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001319 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001320 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001321 else
Hans de Goede7567a042009-01-07 16:37:28 +01001322 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001323
1324 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1325 mutex_unlock(&data->update_lock);
1326
1327 return count;
1328}
1329
1330static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1331 *devattr, char *buf)
1332{
1333 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001334 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001335
Hans de Goede7567a042009-01-07 16:37:28 +01001336 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001337 return sprintf(buf, "1\n");
1338 else
1339 return sprintf(buf, "0\n");
1340}
1341
1342static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1343 *devattr, char *buf)
1344{
1345 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001346 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001347
Hans de Goede7567a042009-01-07 16:37:28 +01001348 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001349 return sprintf(buf, "1\n");
1350 else
1351 return sprintf(buf, "0\n");
1352}
1353
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001354static ssize_t show_pwm(struct device *dev,
1355 struct device_attribute *devattr, char *buf)
1356{
1357 struct f71882fg_data *data = f71882fg_update_device(dev);
1358 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001359 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001360 if (data->pwm_enable & (1 << (2 * nr)))
1361 /* PWM mode */
1362 val = data->pwm[nr];
1363 else {
1364 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001365 val = 255 * fan_from_reg(data->fan_target[nr])
1366 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001367 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001368 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001369 return sprintf(buf, "%d\n", val);
1370}
1371
1372static ssize_t store_pwm(struct device *dev,
1373 struct device_attribute *devattr, const char *buf,
1374 size_t count)
1375{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001376 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001377 int nr = to_sensor_dev_attr_2(devattr)->index;
1378 long val = simple_strtol(buf, NULL, 10);
1379 val = SENSORS_LIMIT(val, 0, 255);
1380
1381 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001382 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001383 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1384 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1385 count = -EROFS;
1386 goto leave;
1387 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001388 if (data->pwm_enable & (1 << (2 * nr))) {
1389 /* PWM mode */
1390 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1391 data->pwm[nr] = val;
1392 } else {
1393 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001394 int target, full_speed;
1395 full_speed = f71882fg_read16(data,
1396 F71882FG_REG_FAN_FULL_SPEED(nr));
1397 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1398 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1399 data->fan_target[nr] = target;
1400 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001401 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001402leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001403 mutex_unlock(&data->update_lock);
1404
1405 return count;
1406}
1407
1408static ssize_t show_pwm_enable(struct device *dev,
1409 struct device_attribute *devattr, char *buf)
1410{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001411 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001412 struct f71882fg_data *data = f71882fg_update_device(dev);
1413 int nr = to_sensor_dev_attr_2(devattr)->index;
1414
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001415 switch ((data->pwm_enable >> 2 * nr) & 3) {
1416 case 0:
1417 case 1:
1418 result = 2; /* Normal auto mode */
1419 break;
1420 case 2:
1421 result = 1; /* Manual mode */
1422 break;
1423 case 3:
1424 if (data->type == f8000)
1425 result = 3; /* Thermostat mode */
1426 else
1427 result = 1; /* Manual mode */
1428 break;
1429 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001430
1431 return sprintf(buf, "%d\n", result);
1432}
1433
1434static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1435 *devattr, const char *buf, size_t count)
1436{
1437 struct f71882fg_data *data = dev_get_drvdata(dev);
1438 int nr = to_sensor_dev_attr_2(devattr)->index;
1439 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001440
Hans de Goede3fc78382009-06-15 18:39:50 +02001441 /* Special case for F8000 pwm channel 3 which only does auto mode */
1442 if (data->type == f8000 && nr == 2 && val != 2)
1443 return -EINVAL;
1444
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001445 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001446 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001447 /* Special case for F8000 auto PWM mode / Thermostat mode */
1448 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1449 switch (val) {
1450 case 2:
1451 data->pwm_enable &= ~(2 << (2 * nr));
1452 break; /* Normal auto mode */
1453 case 3:
1454 data->pwm_enable |= 2 << (2 * nr);
1455 break; /* Thermostat mode */
1456 default:
1457 count = -EINVAL;
1458 goto leave;
1459 }
1460 } else {
1461 switch (val) {
1462 case 1:
1463 data->pwm_enable |= 2 << (2 * nr);
1464 break; /* Manual */
1465 case 2:
1466 data->pwm_enable &= ~(2 << (2 * nr));
1467 break; /* Normal auto mode */
1468 default:
1469 count = -EINVAL;
1470 goto leave;
1471 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001472 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001473 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001474leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001475 mutex_unlock(&data->update_lock);
1476
1477 return count;
1478}
1479
1480static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1481 struct device_attribute *devattr,
1482 char *buf)
1483{
1484 int result;
1485 struct f71882fg_data *data = f71882fg_update_device(dev);
1486 int pwm = to_sensor_dev_attr_2(devattr)->index;
1487 int point = to_sensor_dev_attr_2(devattr)->nr;
1488
Hans de Goedece0bfa52009-01-07 16:37:28 +01001489 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001490 if (data->pwm_enable & (1 << (2 * pwm))) {
1491 /* PWM mode */
1492 result = data->pwm_auto_point_pwm[pwm][point];
1493 } else {
1494 /* RPM mode */
1495 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1496 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001497 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001498
1499 return sprintf(buf, "%d\n", result);
1500}
1501
1502static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1503 struct device_attribute *devattr,
1504 const char *buf, size_t count)
1505{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001506 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001507 int pwm = to_sensor_dev_attr_2(devattr)->index;
1508 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001509 long val = simple_strtol(buf, NULL, 10);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001510 val = SENSORS_LIMIT(val, 0, 255);
1511
1512 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001513 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001514 if (data->pwm_enable & (1 << (2 * pwm))) {
1515 /* PWM mode */
1516 } else {
1517 /* RPM mode */
1518 if (val < 29) /* Prevent negative numbers */
1519 val = 255;
1520 else
1521 val = (255 - val) * 32 / val;
1522 }
1523 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1524 data->pwm_auto_point_pwm[pwm][point] = val;
1525 mutex_unlock(&data->update_lock);
1526
1527 return count;
1528}
1529
1530static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1531 struct device_attribute *devattr,
1532 char *buf)
1533{
1534 int result = 0;
1535 struct f71882fg_data *data = f71882fg_update_device(dev);
1536 int nr = to_sensor_dev_attr_2(devattr)->index;
1537 int point = to_sensor_dev_attr_2(devattr)->nr;
1538
1539 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001540 if (nr & 1)
1541 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1542 else
1543 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001544 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1545 mutex_unlock(&data->update_lock);
1546
1547 return sprintf(buf, "%d\n", result);
1548}
1549
1550static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1551 struct device_attribute *devattr,
1552 const char *buf, size_t count)
1553{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001554 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001555 int nr = to_sensor_dev_attr_2(devattr)->index;
1556 int point = to_sensor_dev_attr_2(devattr)->nr;
1557 long val = simple_strtol(buf, NULL, 10) / 1000;
Hans de Goedebc274902009-01-07 16:37:29 +01001558 u8 reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001559
1560 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001561 data->pwm_auto_point_temp[nr][point] =
1562 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001563 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1564 data->pwm_auto_point_temp[nr][point]);
1565 val = data->pwm_auto_point_temp[nr][point] - val;
1566
Hans de Goedebc274902009-01-07 16:37:29 +01001567 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1568 if (nr & 1)
1569 reg = (reg & 0x0f) | (val << 4);
1570 else
1571 reg = (reg & 0xf0) | val;
1572
1573 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1574 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001575 mutex_unlock(&data->update_lock);
1576
1577 return count;
1578}
1579
1580static ssize_t show_pwm_interpolate(struct device *dev,
1581 struct device_attribute *devattr, char *buf)
1582{
1583 int result;
1584 struct f71882fg_data *data = f71882fg_update_device(dev);
1585 int nr = to_sensor_dev_attr_2(devattr)->index;
1586
1587 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1588
1589 return sprintf(buf, "%d\n", result);
1590}
1591
1592static ssize_t store_pwm_interpolate(struct device *dev,
1593 struct device_attribute *devattr,
1594 const char *buf, size_t count)
1595{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001596 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001597 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001598 unsigned long val = simple_strtoul(buf, NULL, 10);
1599
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001600 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001601 data->pwm_auto_point_mapping[nr] =
1602 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001603 if (val)
1604 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1605 else
1606 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1607 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1608 data->pwm_auto_point_mapping[nr] = val;
1609 mutex_unlock(&data->update_lock);
1610
1611 return count;
1612}
1613
1614static ssize_t show_pwm_auto_point_channel(struct device *dev,
1615 struct device_attribute *devattr,
1616 char *buf)
1617{
1618 int result;
1619 struct f71882fg_data *data = f71882fg_update_device(dev);
1620 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001621 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001622
Hans de Goede30453012009-01-07 16:37:30 +01001623 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001624
1625 return sprintf(buf, "%d\n", result);
1626}
1627
1628static ssize_t store_pwm_auto_point_channel(struct device *dev,
1629 struct device_attribute *devattr,
1630 const char *buf, size_t count)
1631{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001632 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001633 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede30453012009-01-07 16:37:30 +01001634 int temp_start = (data->type == f8000) ? 0 : 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001635 long val = simple_strtol(buf, NULL, 10);
Hans de Goede30453012009-01-07 16:37:30 +01001636
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001637 switch (val) {
1638 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001639 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001640 break;
1641 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001642 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001643 break;
1644 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001645 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001646 break;
1647 default:
1648 return -EINVAL;
1649 }
Hans de Goede30453012009-01-07 16:37:30 +01001650 val += temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001651 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001652 data->pwm_auto_point_mapping[nr] =
1653 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001654 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1655 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1656 data->pwm_auto_point_mapping[nr] = val;
1657 mutex_unlock(&data->update_lock);
1658
1659 return count;
1660}
1661
1662static ssize_t show_pwm_auto_point_temp(struct device *dev,
1663 struct device_attribute *devattr,
1664 char *buf)
1665{
1666 int result;
1667 struct f71882fg_data *data = f71882fg_update_device(dev);
1668 int pwm = to_sensor_dev_attr_2(devattr)->index;
1669 int point = to_sensor_dev_attr_2(devattr)->nr;
1670
1671 result = data->pwm_auto_point_temp[pwm][point];
1672 return sprintf(buf, "%d\n", 1000 * result);
1673}
1674
1675static ssize_t store_pwm_auto_point_temp(struct device *dev,
1676 struct device_attribute *devattr,
1677 const char *buf, size_t count)
1678{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001679 struct f71882fg_data *data = dev_get_drvdata(dev);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001680 int pwm = to_sensor_dev_attr_2(devattr)->index;
1681 int point = to_sensor_dev_attr_2(devattr)->nr;
1682 long val = simple_strtol(buf, NULL, 10) / 1000;
1683 val = SENSORS_LIMIT(val, 0, 255);
1684
1685 mutex_lock(&data->update_lock);
1686 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1687 data->pwm_auto_point_temp[pwm][point] = val;
1688 mutex_unlock(&data->update_lock);
1689
1690 return count;
1691}
1692
Hans de Goede45fb3662007-07-13 14:34:19 +02001693static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1694 char *buf)
1695{
Hans de Goede498be962009-01-07 16:37:28 +01001696 struct f71882fg_data *data = dev_get_drvdata(dev);
1697 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001698}
1699
Hans de Goedec13548c2009-01-07 16:37:27 +01001700static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1701 struct sensor_device_attribute_2 *attr, int count)
1702{
1703 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001704
Hans de Goedec13548c2009-01-07 16:37:27 +01001705 for (i = 0; i < count; i++) {
1706 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1707 if (err)
1708 return err;
1709 }
1710 return 0;
1711}
1712
1713static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001714{
1715 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001716 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001717 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001718 u8 start_reg;
1719
Hans de Goedec13548c2009-01-07 16:37:27 +01001720 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1721 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001722 return -ENOMEM;
1723
1724 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001725 data->type = sio_data->type;
Hans de Goede45fb3662007-07-13 14:34:19 +02001726 mutex_init(&data->update_lock);
1727 platform_set_drvdata(pdev, data);
1728
Hans de Goede3cc74752009-01-07 16:37:28 +01001729 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001730 if (start_reg & 0x04) {
1731 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1732 err = -ENODEV;
1733 goto exit_free;
1734 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001735 if (!(start_reg & 0x03)) {
1736 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1737 err = -ENODEV;
1738 goto exit_free;
1739 }
1740
Hans de Goede45fb3662007-07-13 14:34:19 +02001741 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001742 err = device_create_file(&pdev->dev, &dev_attr_name);
1743 if (err)
1744 goto exit_unregister_sysfs;
1745
Hans de Goedec13548c2009-01-07 16:37:27 +01001746 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001747 switch (data->type) {
1748 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001749 err = f71882fg_create_sysfs_files(pdev,
1750 f71882fg_in_temp_attr,
1751 ARRAY_SIZE(f71882fg_in_temp_attr));
1752 if (err)
1753 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001754 /* fall through! */
1755 case f71862fg:
1756 err = f71882fg_create_sysfs_files(pdev,
1757 f718x2fg_in_temp_attr,
1758 ARRAY_SIZE(f718x2fg_in_temp_attr));
1759 break;
1760 case f8000:
1761 err = f71882fg_create_sysfs_files(pdev,
1762 f8000_in_temp_attr,
1763 ARRAY_SIZE(f8000_in_temp_attr));
1764 break;
Hans de Goede498be962009-01-07 16:37:28 +01001765 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001766 if (err)
1767 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001768 }
1769
Hans de Goede45fb3662007-07-13 14:34:19 +02001770 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001771 data->pwm_enable =
1772 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1773
1774 /* Sanity check the pwm settings */
1775 switch (data->type) {
1776 case f71862fg:
1777 err = (data->pwm_enable & 0x15) != 0x15;
1778 break;
1779 case f71882fg:
1780 err = 0;
1781 break;
1782 case f8000:
1783 err = data->pwm_enable & 0x20;
1784 break;
1785 }
1786 if (err) {
1787 dev_err(&pdev->dev,
1788 "Invalid (reserved) pwm settings: 0x%02x\n",
1789 (unsigned int)data->pwm_enable);
1790 err = -ENODEV;
1791 goto exit_unregister_sysfs;
1792 }
1793
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001794 err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
1795 ARRAY_SIZE(fxxxx_fan_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001796 if (err)
1797 goto exit_unregister_sysfs;
1798
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001799 switch (data->type) {
1800 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001801 err = f71882fg_create_sysfs_files(pdev,
1802 f71862fg_fan_attr,
1803 ARRAY_SIZE(f71862fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001804 break;
1805 case f71882fg:
Hans de Goede498be962009-01-07 16:37:28 +01001806 err = f71882fg_create_sysfs_files(pdev,
1807 f71882fg_fan_attr,
Hans de Goedec13548c2009-01-07 16:37:27 +01001808 ARRAY_SIZE(f71882fg_fan_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001809 break;
1810 case f8000:
1811 err = f71882fg_create_sysfs_files(pdev,
1812 f8000_fan_attr,
1813 ARRAY_SIZE(f8000_fan_attr));
1814 break;
Hans de Goede498be962009-01-07 16:37:28 +01001815 }
Hans de Goedec13548c2009-01-07 16:37:27 +01001816 if (err)
1817 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01001818
1819 for (i = 0; i < nr_fans; i++)
1820 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
1821 (data->pwm_enable & (1 << 2 * i)) ?
1822 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02001823 }
1824
Tony Jones1beeffe2007-08-20 13:46:20 -07001825 data->hwmon_dev = hwmon_device_register(&pdev->dev);
1826 if (IS_ERR(data->hwmon_dev)) {
1827 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01001828 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02001829 goto exit_unregister_sysfs;
1830 }
1831
1832 return 0;
1833
1834exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01001835 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01001836 return err; /* f71882fg_remove() also frees our data */
1837exit_free:
1838 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02001839 return err;
1840}
1841
Hans de Goedec13548c2009-01-07 16:37:27 +01001842static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001843{
1844 int i;
1845 struct f71882fg_data *data = platform_get_drvdata(pdev);
1846
1847 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01001848 if (data->hwmon_dev)
1849 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02001850
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001851 /* Note we are not looping over all attr arrays we have as the ones
1852 below are supersets of the ones skipped. */
Hans de Goedec13548c2009-01-07 16:37:27 +01001853 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02001854
Hans de Goede498be962009-01-07 16:37:28 +01001855 for (i = 0; i < ARRAY_SIZE(f718x2fg_in_temp_attr); i++)
1856 device_remove_file(&pdev->dev,
1857 &f718x2fg_in_temp_attr[i].dev_attr);
1858
Hans de Goede45fb3662007-07-13 14:34:19 +02001859 for (i = 0; i < ARRAY_SIZE(f71882fg_in_temp_attr); i++)
1860 device_remove_file(&pdev->dev,
1861 &f71882fg_in_temp_attr[i].dev_attr);
1862
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001863 for (i = 0; i < ARRAY_SIZE(fxxxx_fan_attr); i++)
1864 device_remove_file(&pdev->dev, &fxxxx_fan_attr[i].dev_attr);
Hans de Goede498be962009-01-07 16:37:28 +01001865
Hans de Goede45fb3662007-07-13 14:34:19 +02001866 for (i = 0; i < ARRAY_SIZE(f71882fg_fan_attr); i++)
1867 device_remove_file(&pdev->dev, &f71882fg_fan_attr[i].dev_attr);
1868
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001869 for (i = 0; i < ARRAY_SIZE(f8000_fan_attr); i++)
1870 device_remove_file(&pdev->dev, &f8000_fan_attr[i].dev_attr);
1871
Hans de Goede45fb3662007-07-13 14:34:19 +02001872 kfree(data);
1873
1874 return 0;
1875}
1876
Hans de Goede498be962009-01-07 16:37:28 +01001877static int __init f71882fg_find(int sioaddr, unsigned short *address,
1878 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001879{
1880 int err = -ENODEV;
1881 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02001882
1883 superio_enter(sioaddr);
1884
1885 devid = superio_inw(sioaddr, SIO_REG_MANID);
1886 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01001887 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02001888 goto exit;
1889 }
1890
Jean Delvare67b671b2007-12-06 23:13:42 +01001891 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01001892 switch (devid) {
1893 case SIO_F71862_ID:
1894 sio_data->type = f71862fg;
1895 break;
1896 case SIO_F71882_ID:
1897 sio_data->type = f71882fg;
1898 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001899 case SIO_F8000_ID:
1900 sio_data->type = f8000;
1901 break;
Hans de Goede498be962009-01-07 16:37:28 +01001902 default:
Hans de Goede45fb3662007-07-13 14:34:19 +02001903 printk(KERN_INFO DRVNAME ": Unsupported Fintek device\n");
1904 goto exit;
1905 }
1906
1907 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001908 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001909 printk(KERN_WARNING DRVNAME ": Device not activated\n");
1910 goto exit;
1911 }
1912
1913 *address = superio_inw(sioaddr, SIO_REG_ADDR);
1914 if (*address == 0)
1915 {
1916 printk(KERN_WARNING DRVNAME ": Base address not set\n");
1917 goto exit;
1918 }
1919 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
1920
Hans de Goede45fb3662007-07-13 14:34:19 +02001921 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01001922 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
1923 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02001924 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
1925exit:
1926 superio_exit(sioaddr);
1927 return err;
1928}
1929
Hans de Goede498be962009-01-07 16:37:28 +01001930static int __init f71882fg_device_add(unsigned short address,
1931 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001932{
1933 struct resource res = {
1934 .start = address,
1935 .end = address + REGION_LENGTH - 1,
1936 .flags = IORESOURCE_IO,
1937 };
1938 int err;
1939
1940 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001941 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001942 return -ENOMEM;
1943
1944 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01001945 err = acpi_check_resource_conflict(&res);
1946 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01001947 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01001948
Hans de Goede45fb3662007-07-13 14:34:19 +02001949 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
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 resource addition failed\n");
1952 goto exit_device_put;
1953 }
1954
Hans de Goede498be962009-01-07 16:37:28 +01001955 err = platform_device_add_data(f71882fg_pdev, sio_data,
1956 sizeof(struct f71882fg_sio_data));
1957 if (err) {
1958 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
1959 goto exit_device_put;
1960 }
1961
Hans de Goede45fb3662007-07-13 14:34:19 +02001962 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001963 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001964 printk(KERN_ERR DRVNAME ": Device addition failed\n");
1965 goto exit_device_put;
1966 }
1967
1968 return 0;
1969
1970exit_device_put:
1971 platform_device_put(f71882fg_pdev);
1972
1973 return err;
1974}
1975
1976static int __init f71882fg_init(void)
1977{
1978 int err = -ENODEV;
1979 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01001980 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02001981
Hans de Goede498be962009-01-07 16:37:28 +01001982 memset(&sio_data, 0, sizeof(sio_data));
1983
1984 if (f71882fg_find(0x2e, &address, &sio_data) &&
1985 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02001986 goto exit;
1987
Hans de Goedec13548c2009-01-07 16:37:27 +01001988 err = platform_driver_register(&f71882fg_driver);
1989 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001990 goto exit;
1991
Hans de Goede498be962009-01-07 16:37:28 +01001992 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01001993 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02001994 goto exit_driver;
1995
1996 return 0;
1997
1998exit_driver:
1999 platform_driver_unregister(&f71882fg_driver);
2000exit:
2001 return err;
2002}
2003
2004static void __exit f71882fg_exit(void)
2005{
2006 platform_device_unregister(f71882fg_pdev);
2007 platform_driver_unregister(&f71882fg_driver);
2008}
2009
2010MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002011MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002012MODULE_LICENSE("GPL");
2013
2014module_init(f71882fg_init);
2015module_exit(f71882fg_exit);