blob: 67ac85870592dced84591ffff40dccceea831381 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010053#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010054#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020055
56#define REGION_LENGTH 8
57#define ADDR_REG_OFFSET 5
58#define DATA_REG_OFFSET 6
59
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
61#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010063#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010066#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
67#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_FAN_STATUS 0x92
69#define F71882FG_REG_FAN_BEEP 0x93
70
Hans de Goede7567a042009-01-07 16:37:28 +010071#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
72#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
73#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_STATUS 0x62
75#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020076#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010077#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020078#define F71882FG_REG_TEMP_TYPE 0x6B
79#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
80
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
82#define F71882FG_REG_PWM_TYPE 0x94
83#define F71882FG_REG_PWM_ENABLE 0x96
84
Hans de Goedebc274902009-01-07 16:37:29 +010085#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010086
Hans de Goede98f7ba12011-03-09 20:57:09 +010087#define F71882FG_REG_FAN_FAULT_T 0x9F
88#define F71882FG_FAN_NEG_TEMP_EN 0x20
89
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010090#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
91#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
92#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
93
Hans de Goede45fb3662007-07-13 14:34:19 +020094#define F71882FG_REG_START 0x01
95
96#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
97
Jean Delvare67b671b2007-12-06 23:13:42 +010098static unsigned short force_id;
99module_param(force_id, ushort, 0);
100MODULE_PARM_DESC(force_id, "Override the detected device ID");
101
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700102enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100103
104static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200105 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100106 "f71862fg",
107 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100108 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100109 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100110};
111
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100112static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200113
114/* Super-I/O Function prototypes */
115static inline int superio_inb(int base, int reg);
116static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400117static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200118static inline void superio_select(int base, int ld);
119static inline void superio_exit(int base);
120
Hans de Goede498be962009-01-07 16:37:28 +0100121struct f71882fg_sio_data {
122 enum chips type;
123};
124
Hans de Goede45fb3662007-07-13 14:34:19 +0200125struct f71882fg_data {
126 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100127 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700128 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200129
130 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200131 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200132 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100133 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200134 unsigned long last_updated; /* In jiffies */
135 unsigned long last_limits; /* In jiffies */
136
137 /* Register Values */
138 u8 in[9];
139 u8 in1_max;
140 u8 in_status;
141 u8 in_beep;
142 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100143 u16 fan_target[4];
144 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200145 u8 fan_status;
146 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100147 /* Note: all models have only 3 temperature channels, but on some
148 they are addressed as 0-2 and on others as 1-3, so for coding
149 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200150 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100151 u8 temp_ovt[4];
152 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100153 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100154 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200155 u8 temp_status;
156 u8 temp_beep;
157 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200158 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100159 u8 pwm[4];
160 u8 pwm_enable;
161 u8 pwm_auto_point_hyst[2];
162 u8 pwm_auto_point_mapping[4];
163 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100164 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200165};
166
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100167/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200168static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
169 char *buf);
170static ssize_t show_in_max(struct device *dev, struct device_attribute
171 *devattr, char *buf);
172static ssize_t store_in_max(struct device *dev, struct device_attribute
173 *devattr, const char *buf, size_t count);
174static ssize_t show_in_beep(struct device *dev, struct device_attribute
175 *devattr, char *buf);
176static ssize_t store_in_beep(struct device *dev, struct device_attribute
177 *devattr, const char *buf, size_t count);
178static ssize_t show_in_alarm(struct device *dev, struct device_attribute
179 *devattr, char *buf);
180/* Sysfs Fan */
181static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
182 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100183static ssize_t show_fan_full_speed(struct device *dev,
184 struct device_attribute *devattr, char *buf);
185static ssize_t store_fan_full_speed(struct device *dev,
186 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200187static ssize_t show_fan_beep(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189static ssize_t store_fan_beep(struct device *dev, struct device_attribute
190 *devattr, const char *buf, size_t count);
191static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
192 *devattr, char *buf);
193/* Sysfs Temp */
194static ssize_t show_temp(struct device *dev, struct device_attribute
195 *devattr, char *buf);
196static ssize_t show_temp_max(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t store_temp_max(struct device *dev, struct device_attribute
199 *devattr, const char *buf, size_t count);
200static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_temp_crit(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t store_temp_crit(struct device *dev, struct device_attribute
207 *devattr, const char *buf, size_t count);
208static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t show_temp_type(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212static ssize_t show_temp_beep(struct device *dev, struct device_attribute
213 *devattr, char *buf);
214static ssize_t store_temp_beep(struct device *dev, struct device_attribute
215 *devattr, const char *buf, size_t count);
216static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
217 *devattr, char *buf);
218static ssize_t show_temp_fault(struct device *dev, struct device_attribute
219 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100220/* PWM and Auto point control */
221static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
222 char *buf);
223static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
224 const char *buf, size_t count);
225static ssize_t show_pwm_enable(struct device *dev,
226 struct device_attribute *devattr, char *buf);
227static ssize_t store_pwm_enable(struct device *dev,
228 struct device_attribute *devattr, const char *buf, size_t count);
229static ssize_t show_pwm_interpolate(struct device *dev,
230 struct device_attribute *devattr, char *buf);
231static ssize_t store_pwm_interpolate(struct device *dev,
232 struct device_attribute *devattr, const char *buf, size_t count);
233static ssize_t show_pwm_auto_point_channel(struct device *dev,
234 struct device_attribute *devattr, char *buf);
235static ssize_t store_pwm_auto_point_channel(struct device *dev,
236 struct device_attribute *devattr, const char *buf, size_t count);
237static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
238 struct device_attribute *devattr, char *buf);
239static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
240 struct device_attribute *devattr, const char *buf, size_t count);
241static ssize_t show_pwm_auto_point_pwm(struct device *dev,
242 struct device_attribute *devattr, char *buf);
243static ssize_t store_pwm_auto_point_pwm(struct device *dev,
244 struct device_attribute *devattr, const char *buf, size_t count);
245static ssize_t show_pwm_auto_point_temp(struct device *dev,
246 struct device_attribute *devattr, char *buf);
247static ssize_t store_pwm_auto_point_temp(struct device *dev,
248 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200249/* Sysfs misc */
250static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
251 char *buf);
252
253static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100254static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200255
256static struct platform_driver f71882fg_driver = {
257 .driver = {
258 .owner = THIS_MODULE,
259 .name = DRVNAME,
260 },
261 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200262 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200263};
264
Hans de Goedec13548c2009-01-07 16:37:27 +0100265static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200266
Hans de Goede66344aa2009-12-09 20:35:59 +0100267/* Temp and in attr for the f71858fg, the f71858fg is special as it
268 has its temperature indexes start at 0 (the others start at 1) and
269 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200270static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
271 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
272 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
273 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
274 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
275 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
276 store_temp_max, 0, 0),
277 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
278 store_temp_max_hyst, 0, 0),
279 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
280 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
281 store_temp_crit, 0, 0),
282 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
283 0, 0),
284 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
285 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
286 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
287 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
288 store_temp_max, 0, 1),
289 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
290 store_temp_max_hyst, 0, 1),
291 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
292 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
293 store_temp_crit, 0, 1),
294 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
295 0, 1),
296 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
297 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
298 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
299 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
300 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
301 store_temp_max, 0, 2),
302 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
303 store_temp_max_hyst, 0, 2),
304 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
305 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
306 store_temp_crit, 0, 2),
307 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
308 0, 2),
309 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
310 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
311};
312
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700313/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
314static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100315 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
316 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100317 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
318 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
319 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
320 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
321 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
322 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
323 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100324 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100325 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100326 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100327 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100328 store_temp_max_hyst, 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100329 /* Should really be temp1_max_alarm, but older versions did not handle
330 the max and crit alarms separately and lm_sensors v2 depends on the
331 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
332 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
333 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
334 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100335 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100336 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100337 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100338 0, 1),
Hans de Goede754a5902009-01-07 16:37:29 +0100339 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
340 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
341 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100342 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100343 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
344 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
345 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100346 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100348 store_temp_max_hyst, 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100349 /* Should be temp2_max_alarm, see temp1_alarm note */
350 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
351 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
352 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100354 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100355 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100356 0, 2),
Hans de Goede754a5902009-01-07 16:37:29 +0100357 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
358 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
359 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100360 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100361 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
362 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
363 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
364 store_temp_max, 0, 3),
365 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
366 store_temp_max_hyst, 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100367 /* Should be temp3_max_alarm, see temp1_alarm note */
368 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
369 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
370 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100371 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
372 store_temp_crit, 0, 3),
373 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
374 0, 3),
Hans de Goede754a5902009-01-07 16:37:29 +0100375 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
376 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
377 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100378 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100379 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200380};
381
Hans de Goede66344aa2009-12-09 20:35:59 +0100382/* For models with in1 alarm capability */
383static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100384 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
385 0, 1),
386 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
387 0, 1),
388 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
389};
390
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100391/* Temp and in attr for the f8000
392 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
393 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100394 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100395 */
396static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
397 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
398 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
399 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
400 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
401 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
402 store_temp_crit, 0, 0),
403 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
404 store_temp_max, 0, 0),
405 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200406 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100407 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
408 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
409 store_temp_crit, 0, 1),
410 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
411 store_temp_max, 0, 1),
412 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
413 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200414 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100415 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
416 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
417 store_temp_crit, 0, 2),
418 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
419 store_temp_max, 0, 2),
420 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200421 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100422};
423
424/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100425static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100427 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
428 show_fan_full_speed,
429 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100430 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100431 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
432 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
433 store_pwm_enable, 0, 0),
434 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
435 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100436}, {
437 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
438 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
439 show_fan_full_speed,
440 store_fan_full_speed, 0, 1),
441 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100442 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
443 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
444 store_pwm_enable, 0, 1),
445 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
446 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100447}, {
448 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
449 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
450 show_fan_full_speed,
451 store_fan_full_speed, 0, 2),
452 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200453 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
454 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
455 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100456 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
457 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100458}, {
459 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
460 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
461 show_fan_full_speed,
462 store_fan_full_speed, 0, 3),
463 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
464 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
465 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
466 store_pwm_enable, 0, 3),
467 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
468 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
469} };
Hans de Goede498be962009-01-07 16:37:28 +0100470
Hans de Goede66344aa2009-12-09 20:35:59 +0100471/* Attr for models which can beep on Fan alarm */
472static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100473 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 0),
475 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
476 store_fan_beep, 0, 1),
477 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
478 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100479 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
480 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100481};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100482
Hans de Goede66344aa2009-12-09 20:35:59 +0100483/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
484 f71858fg / f71882fg / f71889fg */
485static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
486 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
487 show_pwm_auto_point_channel,
488 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100489 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
490 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
491 1, 0),
492 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
493 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
494 4, 0),
495 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
496 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
497 0, 0),
498 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
499 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
500 3, 0),
501 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
502 show_pwm_auto_point_temp_hyst,
503 store_pwm_auto_point_temp_hyst,
504 0, 0),
505 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
506 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
507
Hans de Goede66344aa2009-12-09 20:35:59 +0100508 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
509 show_pwm_auto_point_channel,
510 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100511 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
512 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
513 1, 1),
514 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
515 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
516 4, 1),
517 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
518 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
519 0, 1),
520 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
521 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
522 3, 1),
523 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
524 show_pwm_auto_point_temp_hyst,
525 store_pwm_auto_point_temp_hyst,
526 0, 1),
527 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
528 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100529
Hans de Goede66344aa2009-12-09 20:35:59 +0100530 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
531 show_pwm_auto_point_channel,
532 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100533 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
534 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
535 1, 2),
536 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
537 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
538 4, 2),
539 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
540 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
541 0, 2),
542 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
543 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
544 3, 2),
545 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
546 show_pwm_auto_point_temp_hyst,
547 store_pwm_auto_point_temp_hyst,
548 0, 2),
549 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
550 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100551};
552
Hans de Goede66344aa2009-12-09 20:35:59 +0100553/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100554static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100555 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
556 show_pwm_auto_point_channel,
557 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100558 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
559 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
560 0, 0),
561 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
562 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
563 1, 0),
564 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
565 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
566 2, 0),
567 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
568 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
569 3, 0),
570 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
571 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
572 4, 0),
573 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
575 0, 0),
576 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
578 1, 0),
579 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
581 2, 0),
582 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
584 3, 0),
585 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_temp_hyst,
587 store_pwm_auto_point_temp_hyst,
588 0, 0),
589 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
591 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
592 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
593 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
594 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100595}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100596 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_channel,
598 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100599 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
601 0, 1),
602 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
604 1, 1),
605 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
606 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
607 2, 1),
608 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
609 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
610 3, 1),
611 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
613 4, 1),
614 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
616 0, 1),
617 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
619 1, 1),
620 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
622 2, 1),
623 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
625 3, 1),
626 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_temp_hyst,
628 store_pwm_auto_point_temp_hyst,
629 0, 1),
630 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
631 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
632 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
633 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
634 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
635 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100636}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100637 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_channel,
639 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100640 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
642 0, 2),
643 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
645 1, 2),
646 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
648 2, 2),
649 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
651 3, 2),
652 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
653 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
654 4, 2),
655 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
657 0, 2),
658 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
659 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
660 1, 2),
661 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
662 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
663 2, 2),
664 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
665 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
666 3, 2),
667 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
668 show_pwm_auto_point_temp_hyst,
669 store_pwm_auto_point_temp_hyst,
670 0, 2),
671 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
672 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
673 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
674 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
675 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
676 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100677}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100678 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_channel,
680 store_pwm_auto_point_channel, 0, 3),
681 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 0, 3),
684 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 1, 3),
687 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
689 2, 3),
690 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
692 3, 3),
693 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
695 4, 3),
696 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
698 0, 3),
699 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
701 1, 3),
702 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
704 2, 3),
705 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
707 3, 3),
708 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_temp_hyst,
710 store_pwm_auto_point_temp_hyst,
711 0, 3),
712 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
714 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
715 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
716 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
717 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100718} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200719
Hans de Goede66344aa2009-12-09 20:35:59 +0100720/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100721static struct sensor_device_attribute_2 f8000_fan_attr[] = {
722 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100723};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100724
Hans de Goede66344aa2009-12-09 20:35:59 +0100725/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
726 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
727 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
728static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
729 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
730 show_pwm_auto_point_channel,
731 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100732 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
733 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
734 0, 2),
735 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
736 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
737 1, 2),
738 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
739 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
740 2, 2),
741 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
742 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
743 3, 2),
744 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
746 4, 2),
747 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
749 0, 2),
750 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
752 1, 2),
753 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
755 2, 2),
756 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
758 3, 2),
759 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_temp_hyst,
761 store_pwm_auto_point_temp_hyst,
762 0, 2),
763 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
765 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
766 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
767 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
768 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
769
Hans de Goede66344aa2009-12-09 20:35:59 +0100770 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_channel,
772 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100773 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
775 0, 0),
776 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
778 1, 0),
779 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
780 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
781 2, 0),
782 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
783 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
784 3, 0),
785 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
787 4, 0),
788 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
790 0, 0),
791 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
793 1, 0),
794 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
796 2, 0),
797 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
799 3, 0),
800 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_temp_hyst,
802 store_pwm_auto_point_temp_hyst,
803 0, 0),
804 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
806 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
807 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
808 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
809 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
810
Hans de Goede66344aa2009-12-09 20:35:59 +0100811 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_channel,
813 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100814 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 0, 1),
817 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
819 1, 1),
820 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
822 2, 1),
823 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
825 3, 1),
826 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
828 4, 1),
829 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
831 0, 1),
832 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
834 1, 1),
835 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
837 2, 1),
838 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
840 3, 1),
841 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_temp_hyst,
843 store_pwm_auto_point_temp_hyst,
844 0, 1),
845 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
847 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
848 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
849 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
850 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
851};
Hans de Goede45fb3662007-07-13 14:34:19 +0200852
853/* Super I/O functions */
854static inline int superio_inb(int base, int reg)
855{
856 outb(reg, base);
857 return inb(base + 1);
858}
859
860static int superio_inw(int base, int reg)
861{
862 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200863 val = superio_inb(base, reg) << 8;
864 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200865 return val;
866}
867
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400868static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200869{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400870 /* Don't step on other drivers' I/O space by accident */
871 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000872 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400873 return -EBUSY;
874 }
875
Hans de Goede45fb3662007-07-13 14:34:19 +0200876 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200877 outb(SIO_UNLOCK_KEY, base);
878 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400879
880 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200881}
882
Giel van Schijndel162bb592010-05-27 19:58:40 +0200883static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200884{
885 outb(SIO_REG_LDSEL, base);
886 outb(ld, base + 1);
887}
888
889static inline void superio_exit(int base)
890{
891 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400892 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200893}
894
Hans de Goede2f650632009-01-07 16:37:31 +0100895static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200896{
897 return reg ? (1500000 / reg) : 0;
898}
899
Hans de Goede2f650632009-01-07 16:37:31 +0100900static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100901{
902 return fan ? (1500000 / fan) : 0;
903}
904
Hans de Goede45fb3662007-07-13 14:34:19 +0200905static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
906{
907 u8 val;
908
909 outb(reg, data->addr + ADDR_REG_OFFSET);
910 val = inb(data->addr + DATA_REG_OFFSET);
911
912 return val;
913}
914
915static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
916{
917 u16 val;
918
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200919 val = f71882fg_read8(data, reg) << 8;
920 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200921
922 return val;
923}
924
925static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
926{
927 outb(reg, data->addr + ADDR_REG_OFFSET);
928 outb(val, data->addr + DATA_REG_OFFSET);
929}
930
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100931static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
932{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200933 f71882fg_write8(data, reg, val >> 8);
934 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100935}
936
Hans de Goede09475d32009-06-15 18:39:52 +0200937static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
938{
939 if (data->type == f71858fg)
940 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
941 else
942 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
943}
944
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100945static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200946{
947 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100948 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100949 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200950 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200951
952 mutex_lock(&data->update_lock);
953
954 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200955 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200956 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100957 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100958 data->in1_max =
959 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
960 data->in_beep =
961 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
962 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200963
964 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200965 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200966 data->temp_ovt[nr] = f71882fg_read8(data,
967 F71882FG_REG_TEMP_OVT(nr));
968 data->temp_high[nr] = f71882fg_read8(data,
969 F71882FG_REG_TEMP_HIGH(nr));
970 }
971
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100972 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100973 data->temp_hyst[0] = f71882fg_read8(data,
974 F71882FG_REG_TEMP_HYST(0));
975 data->temp_hyst[1] = f71882fg_read8(data,
976 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200977 }
978
Hans de Goede76698962009-12-09 20:36:01 +0100979 if (data->type == f71862fg || data->type == f71882fg ||
980 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200981 data->fan_beep = f71882fg_read8(data,
982 F71882FG_REG_FAN_BEEP);
983 data->temp_beep = f71882fg_read8(data,
984 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100985 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100986 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100987 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
988 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
989 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200990
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100991 data->pwm_enable = f71882fg_read8(data,
992 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +0100993 data->pwm_auto_point_hyst[0] =
994 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
995 data->pwm_auto_point_hyst[1] =
996 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
997
Hans de Goede498be962009-01-07 16:37:28 +0100998 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100999 data->pwm_auto_point_mapping[nr] =
1000 f71882fg_read8(data,
1001 F71882FG_REG_POINT_MAPPING(nr));
1002
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001003 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001004 int point;
1005 for (point = 0; point < 5; point++) {
1006 data->pwm_auto_point_pwm[nr][point] =
1007 f71882fg_read8(data,
1008 F71882FG_REG_POINT_PWM
1009 (nr, point));
1010 }
1011 for (point = 0; point < 4; point++) {
1012 data->pwm_auto_point_temp[nr][point] =
1013 f71882fg_read8(data,
1014 F71882FG_REG_POINT_TEMP
1015 (nr, point));
1016 }
1017 } else {
1018 data->pwm_auto_point_pwm[nr][1] =
1019 f71882fg_read8(data,
1020 F71882FG_REG_POINT_PWM
1021 (nr, 1));
1022 data->pwm_auto_point_pwm[nr][4] =
1023 f71882fg_read8(data,
1024 F71882FG_REG_POINT_PWM
1025 (nr, 4));
1026 data->pwm_auto_point_temp[nr][0] =
1027 f71882fg_read8(data,
1028 F71882FG_REG_POINT_TEMP
1029 (nr, 0));
1030 data->pwm_auto_point_temp[nr][3] =
1031 f71882fg_read8(data,
1032 F71882FG_REG_POINT_TEMP
1033 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001034 }
1035 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001036 data->last_limits = jiffies;
1037 }
1038
1039 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001040 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001041 data->temp_status = f71882fg_read8(data,
1042 F71882FG_REG_TEMP_STATUS);
1043 data->temp_diode_open = f71882fg_read8(data,
1044 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001045 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1046 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001047
1048 data->fan_status = f71882fg_read8(data,
1049 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001050 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001051 data->fan[nr] = f71882fg_read16(data,
1052 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001053 data->fan_target[nr] =
1054 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1055 data->fan_full_speed[nr] =
1056 f71882fg_read16(data,
1057 F71882FG_REG_FAN_FULL_SPEED(nr));
1058 data->pwm[nr] =
1059 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1060 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001061
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001062 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1063 if (data->type == f8000)
1064 data->fan[3] = f71882fg_read16(data,
1065 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001066 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001067 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001068 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001069 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001070 data->in[nr] = f71882fg_read8(data,
1071 F71882FG_REG_IN(nr));
1072
1073 data->last_updated = jiffies;
1074 data->valid = 1;
1075 }
1076
1077 mutex_unlock(&data->update_lock);
1078
1079 return data;
1080}
1081
1082/* Sysfs Interface */
1083static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1084 char *buf)
1085{
1086 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001087 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001088 int speed = fan_from_reg(data->fan[nr]);
1089
1090 if (speed == FAN_MIN_DETECT)
1091 speed = 0;
1092
1093 return sprintf(buf, "%d\n", speed);
1094}
1095
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001096static ssize_t show_fan_full_speed(struct device *dev,
1097 struct device_attribute *devattr, char *buf)
1098{
1099 struct f71882fg_data *data = f71882fg_update_device(dev);
1100 int nr = to_sensor_dev_attr_2(devattr)->index;
1101 int speed = fan_from_reg(data->fan_full_speed[nr]);
1102 return sprintf(buf, "%d\n", speed);
1103}
1104
1105static ssize_t store_fan_full_speed(struct device *dev,
1106 struct device_attribute *devattr,
1107 const char *buf, size_t count)
1108{
1109 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001110 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1111 long val;
1112
1113 err = strict_strtol(buf, 10, &val);
1114 if (err)
1115 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001116
1117 val = SENSORS_LIMIT(val, 23, 1500000);
1118 val = fan_to_reg(val);
1119
1120 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001121 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1122 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001123 mutex_unlock(&data->update_lock);
1124
1125 return count;
1126}
1127
Hans de Goede45fb3662007-07-13 14:34:19 +02001128static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1129 *devattr, char *buf)
1130{
1131 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001132 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001133
1134 if (data->fan_beep & (1 << nr))
1135 return sprintf(buf, "1\n");
1136 else
1137 return sprintf(buf, "0\n");
1138}
1139
1140static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1141 *devattr, const char *buf, size_t count)
1142{
1143 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001144 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1145 unsigned long val;
1146
1147 err = strict_strtoul(buf, 10, &val);
1148 if (err)
1149 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001150
1151 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001152 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001153 if (val)
1154 data->fan_beep |= 1 << nr;
1155 else
1156 data->fan_beep &= ~(1 << nr);
1157
1158 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1159 mutex_unlock(&data->update_lock);
1160
1161 return count;
1162}
1163
1164static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1165 *devattr, 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 if (data->fan_status & (1 << nr))
1171 return sprintf(buf, "1\n");
1172 else
1173 return sprintf(buf, "0\n");
1174}
1175
1176static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1177 char *buf)
1178{
1179 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001180 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001181
1182 return sprintf(buf, "%d\n", data->in[nr] * 8);
1183}
1184
1185static ssize_t show_in_max(struct device *dev, struct device_attribute
1186 *devattr, char *buf)
1187{
1188 struct f71882fg_data *data = f71882fg_update_device(dev);
1189
1190 return sprintf(buf, "%d\n", data->in1_max * 8);
1191}
1192
1193static ssize_t store_in_max(struct device *dev, struct device_attribute
1194 *devattr, const char *buf, size_t count)
1195{
1196 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001197 int err;
1198 long val;
1199
1200 err = strict_strtol(buf, 10, &val);
1201 if (err)
1202 return err;
1203
1204 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001205 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001206
1207 mutex_lock(&data->update_lock);
1208 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1209 data->in1_max = val;
1210 mutex_unlock(&data->update_lock);
1211
1212 return count;
1213}
1214
1215static ssize_t show_in_beep(struct device *dev, struct device_attribute
1216 *devattr, char *buf)
1217{
1218 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001219 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001220
1221 if (data->in_beep & (1 << nr))
1222 return sprintf(buf, "1\n");
1223 else
1224 return sprintf(buf, "0\n");
1225}
1226
1227static ssize_t store_in_beep(struct device *dev, struct device_attribute
1228 *devattr, const char *buf, size_t count)
1229{
1230 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001231 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1232 unsigned long val;
1233
1234 err = strict_strtoul(buf, 10, &val);
1235 if (err)
1236 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001237
1238 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001239 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001240 if (val)
1241 data->in_beep |= 1 << nr;
1242 else
1243 data->in_beep &= ~(1 << nr);
1244
1245 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1246 mutex_unlock(&data->update_lock);
1247
1248 return count;
1249}
1250
1251static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1252 *devattr, char *buf)
1253{
1254 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001255 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001256
1257 if (data->in_status & (1 << nr))
1258 return sprintf(buf, "1\n");
1259 else
1260 return sprintf(buf, "0\n");
1261}
1262
1263static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1264 char *buf)
1265{
1266 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001267 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001268 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001269
Hans de Goede09475d32009-06-15 18:39:52 +02001270 if (data->type == f71858fg) {
1271 /* TEMP_TABLE_SEL 1 or 3 ? */
1272 if (data->temp_config & 1) {
1273 sign = data->temp[nr] & 0x0001;
1274 temp = (data->temp[nr] >> 5) & 0x7ff;
1275 } else {
1276 sign = data->temp[nr] & 0x8000;
1277 temp = (data->temp[nr] >> 5) & 0x3ff;
1278 }
1279 temp *= 125;
1280 if (sign)
1281 temp -= 128000;
1282 } else
1283 temp = data->temp[nr] * 1000;
1284
1285 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001286}
1287
1288static ssize_t show_temp_max(struct device *dev, struct device_attribute
1289 *devattr, char *buf)
1290{
1291 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001292 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001293
1294 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1295}
1296
1297static ssize_t store_temp_max(struct device *dev, struct device_attribute
1298 *devattr, const char *buf, size_t count)
1299{
1300 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001301 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1302 long val;
1303
1304 err = strict_strtol(buf, 10, &val);
1305 if (err)
1306 return err;
1307
1308 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001309 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001310
1311 mutex_lock(&data->update_lock);
1312 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1313 data->temp_high[nr] = val;
1314 mutex_unlock(&data->update_lock);
1315
1316 return count;
1317}
1318
1319static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1320 *devattr, char *buf)
1321{
1322 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001323 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001324 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001325
Hans de Goedece0bfa52009-01-07 16:37:28 +01001326 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001327 if (nr & 1)
1328 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1329 else
1330 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1331 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001332 mutex_unlock(&data->update_lock);
1333
1334 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001335}
1336
1337static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1338 *devattr, const char *buf, size_t count)
1339{
1340 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001341 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001342 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001343 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001344 long val;
1345
1346 err = strict_strtol(buf, 10, &val);
1347 if (err)
1348 return err;
1349
1350 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001351
1352 mutex_lock(&data->update_lock);
1353
1354 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001355 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1356 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1357 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001358 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001359
1360 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001361 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1362 if (nr & 1)
1363 reg = (reg & 0x0f) | (val << 4);
1364 else
1365 reg = (reg & 0xf0) | val;
1366 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1367 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001368
Hans de Goede45fb3662007-07-13 14:34:19 +02001369 mutex_unlock(&data->update_lock);
1370 return ret;
1371}
1372
1373static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1374 *devattr, char *buf)
1375{
1376 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001377 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001378
1379 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1380}
1381
1382static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1383 *devattr, const char *buf, size_t count)
1384{
1385 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001386 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1387 long val;
1388
1389 err = strict_strtol(buf, 10, &val);
1390 if (err)
1391 return err;
1392
1393 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001394 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001395
1396 mutex_lock(&data->update_lock);
1397 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1398 data->temp_ovt[nr] = val;
1399 mutex_unlock(&data->update_lock);
1400
1401 return count;
1402}
1403
1404static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1405 *devattr, char *buf)
1406{
1407 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001408 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001409 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001410
Hans de Goedece0bfa52009-01-07 16:37:28 +01001411 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001412 if (nr & 1)
1413 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1414 else
1415 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1416 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001417 mutex_unlock(&data->update_lock);
1418
1419 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001420}
1421
1422static ssize_t show_temp_type(struct device *dev, struct device_attribute
1423 *devattr, char *buf)
1424{
1425 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001426 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001427
1428 return sprintf(buf, "%d\n", data->temp_type[nr]);
1429}
1430
1431static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1432 *devattr, char *buf)
1433{
1434 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001435 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001436
Hans de Goede7567a042009-01-07 16:37:28 +01001437 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001438 return sprintf(buf, "1\n");
1439 else
1440 return sprintf(buf, "0\n");
1441}
1442
1443static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1444 *devattr, const char *buf, size_t count)
1445{
1446 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001447 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1448 unsigned long val;
1449
1450 err = strict_strtoul(buf, 10, &val);
1451 if (err)
1452 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001453
1454 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001455 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001456 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001457 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001458 else
Hans de Goede7567a042009-01-07 16:37:28 +01001459 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001460
1461 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1462 mutex_unlock(&data->update_lock);
1463
1464 return count;
1465}
1466
1467static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1468 *devattr, char *buf)
1469{
1470 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001471 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001472
Hans de Goede7567a042009-01-07 16:37:28 +01001473 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001474 return sprintf(buf, "1\n");
1475 else
1476 return sprintf(buf, "0\n");
1477}
1478
1479static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1480 *devattr, char *buf)
1481{
1482 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001483 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001484
Hans de Goede7567a042009-01-07 16:37:28 +01001485 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001486 return sprintf(buf, "1\n");
1487 else
1488 return sprintf(buf, "0\n");
1489}
1490
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001491static ssize_t show_pwm(struct device *dev,
1492 struct device_attribute *devattr, char *buf)
1493{
1494 struct f71882fg_data *data = f71882fg_update_device(dev);
1495 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001496 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001497 if (data->pwm_enable & (1 << (2 * nr)))
1498 /* PWM mode */
1499 val = data->pwm[nr];
1500 else {
1501 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001502 val = 255 * fan_from_reg(data->fan_target[nr])
1503 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001504 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001505 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001506 return sprintf(buf, "%d\n", val);
1507}
1508
1509static ssize_t store_pwm(struct device *dev,
1510 struct device_attribute *devattr, const char *buf,
1511 size_t count)
1512{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001513 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001514 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1515 long val;
1516
1517 err = strict_strtol(buf, 10, &val);
1518 if (err)
1519 return err;
1520
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001521 val = SENSORS_LIMIT(val, 0, 255);
1522
1523 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001524 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001525 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1526 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1527 count = -EROFS;
1528 goto leave;
1529 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001530 if (data->pwm_enable & (1 << (2 * nr))) {
1531 /* PWM mode */
1532 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1533 data->pwm[nr] = val;
1534 } else {
1535 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001536 int target, full_speed;
1537 full_speed = f71882fg_read16(data,
1538 F71882FG_REG_FAN_FULL_SPEED(nr));
1539 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1540 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1541 data->fan_target[nr] = target;
1542 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001543 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001544leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001545 mutex_unlock(&data->update_lock);
1546
1547 return count;
1548}
1549
1550static ssize_t show_pwm_enable(struct device *dev,
1551 struct device_attribute *devattr, char *buf)
1552{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001553 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001554 struct f71882fg_data *data = f71882fg_update_device(dev);
1555 int nr = to_sensor_dev_attr_2(devattr)->index;
1556
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001557 switch ((data->pwm_enable >> 2 * nr) & 3) {
1558 case 0:
1559 case 1:
1560 result = 2; /* Normal auto mode */
1561 break;
1562 case 2:
1563 result = 1; /* Manual mode */
1564 break;
1565 case 3:
1566 if (data->type == f8000)
1567 result = 3; /* Thermostat mode */
1568 else
1569 result = 1; /* Manual mode */
1570 break;
1571 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001572
1573 return sprintf(buf, "%d\n", result);
1574}
1575
1576static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1577 *devattr, const char *buf, size_t count)
1578{
1579 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001580 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1581 long val;
1582
1583 err = strict_strtol(buf, 10, &val);
1584 if (err)
1585 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001586
Hans de Goede3fc78382009-06-15 18:39:50 +02001587 /* Special case for F8000 pwm channel 3 which only does auto mode */
1588 if (data->type == f8000 && nr == 2 && val != 2)
1589 return -EINVAL;
1590
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001591 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001592 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001593 /* Special case for F8000 auto PWM mode / Thermostat mode */
1594 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1595 switch (val) {
1596 case 2:
1597 data->pwm_enable &= ~(2 << (2 * nr));
1598 break; /* Normal auto mode */
1599 case 3:
1600 data->pwm_enable |= 2 << (2 * nr);
1601 break; /* Thermostat mode */
1602 default:
1603 count = -EINVAL;
1604 goto leave;
1605 }
1606 } else {
1607 switch (val) {
1608 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001609 /* The f71858fg does not support manual RPM mode */
1610 if (data->type == f71858fg &&
1611 ((data->pwm_enable >> (2 * nr)) & 1)) {
1612 count = -EINVAL;
1613 goto leave;
1614 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001615 data->pwm_enable |= 2 << (2 * nr);
1616 break; /* Manual */
1617 case 2:
1618 data->pwm_enable &= ~(2 << (2 * nr));
1619 break; /* Normal auto mode */
1620 default:
1621 count = -EINVAL;
1622 goto leave;
1623 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001624 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001625 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001626leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001627 mutex_unlock(&data->update_lock);
1628
1629 return count;
1630}
1631
1632static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1633 struct device_attribute *devattr,
1634 char *buf)
1635{
1636 int result;
1637 struct f71882fg_data *data = f71882fg_update_device(dev);
1638 int pwm = to_sensor_dev_attr_2(devattr)->index;
1639 int point = to_sensor_dev_attr_2(devattr)->nr;
1640
Hans de Goedece0bfa52009-01-07 16:37:28 +01001641 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001642 if (data->pwm_enable & (1 << (2 * pwm))) {
1643 /* PWM mode */
1644 result = data->pwm_auto_point_pwm[pwm][point];
1645 } else {
1646 /* RPM mode */
1647 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1648 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001649 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001650
1651 return sprintf(buf, "%d\n", result);
1652}
1653
1654static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1655 struct device_attribute *devattr,
1656 const char *buf, size_t count)
1657{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001658 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001659 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001660 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001661 long val;
1662
1663 err = strict_strtol(buf, 10, &val);
1664 if (err)
1665 return err;
1666
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001667 val = SENSORS_LIMIT(val, 0, 255);
1668
1669 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001670 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001671 if (data->pwm_enable & (1 << (2 * pwm))) {
1672 /* PWM mode */
1673 } else {
1674 /* RPM mode */
1675 if (val < 29) /* Prevent negative numbers */
1676 val = 255;
1677 else
1678 val = (255 - val) * 32 / val;
1679 }
1680 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1681 data->pwm_auto_point_pwm[pwm][point] = val;
1682 mutex_unlock(&data->update_lock);
1683
1684 return count;
1685}
1686
1687static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1688 struct device_attribute *devattr,
1689 char *buf)
1690{
1691 int result = 0;
1692 struct f71882fg_data *data = f71882fg_update_device(dev);
1693 int nr = to_sensor_dev_attr_2(devattr)->index;
1694 int point = to_sensor_dev_attr_2(devattr)->nr;
1695
1696 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001697 if (nr & 1)
1698 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1699 else
1700 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001701 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1702 mutex_unlock(&data->update_lock);
1703
1704 return sprintf(buf, "%d\n", result);
1705}
1706
1707static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1708 struct device_attribute *devattr,
1709 const char *buf, size_t count)
1710{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001711 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001712 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001713 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001714 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001715 long val;
1716
1717 err = strict_strtol(buf, 10, &val);
1718 if (err)
1719 return err;
1720
1721 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001722
1723 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001724 data->pwm_auto_point_temp[nr][point] =
1725 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001726 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1727 data->pwm_auto_point_temp[nr][point]);
1728 val = data->pwm_auto_point_temp[nr][point] - val;
1729
Hans de Goedebc274902009-01-07 16:37:29 +01001730 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1731 if (nr & 1)
1732 reg = (reg & 0x0f) | (val << 4);
1733 else
1734 reg = (reg & 0xf0) | val;
1735
1736 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1737 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001738 mutex_unlock(&data->update_lock);
1739
1740 return count;
1741}
1742
1743static ssize_t show_pwm_interpolate(struct device *dev,
1744 struct device_attribute *devattr, char *buf)
1745{
1746 int result;
1747 struct f71882fg_data *data = f71882fg_update_device(dev);
1748 int nr = to_sensor_dev_attr_2(devattr)->index;
1749
1750 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1751
1752 return sprintf(buf, "%d\n", result);
1753}
1754
1755static ssize_t store_pwm_interpolate(struct device *dev,
1756 struct device_attribute *devattr,
1757 const char *buf, size_t count)
1758{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001759 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001760 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1761 unsigned long val;
1762
1763 err = strict_strtoul(buf, 10, &val);
1764 if (err)
1765 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001766
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001767 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001768 data->pwm_auto_point_mapping[nr] =
1769 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001770 if (val)
1771 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1772 else
1773 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1774 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1775 data->pwm_auto_point_mapping[nr] = val;
1776 mutex_unlock(&data->update_lock);
1777
1778 return count;
1779}
1780
1781static ssize_t show_pwm_auto_point_channel(struct device *dev,
1782 struct device_attribute *devattr,
1783 char *buf)
1784{
1785 int result;
1786 struct f71882fg_data *data = f71882fg_update_device(dev);
1787 int nr = to_sensor_dev_attr_2(devattr)->index;
1788
Hans de Goede09475d32009-06-15 18:39:52 +02001789 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1790 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001791
1792 return sprintf(buf, "%d\n", result);
1793}
1794
1795static ssize_t store_pwm_auto_point_channel(struct device *dev,
1796 struct device_attribute *devattr,
1797 const char *buf, size_t count)
1798{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001799 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001800 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1801 long val;
1802
1803 err = strict_strtol(buf, 10, &val);
1804 if (err)
1805 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001806
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001807 switch (val) {
1808 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001809 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001810 break;
1811 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001812 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001813 break;
1814 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001815 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001816 break;
1817 default:
1818 return -EINVAL;
1819 }
Hans de Goede09475d32009-06-15 18:39:52 +02001820 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001821 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001822 data->pwm_auto_point_mapping[nr] =
1823 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001824 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1825 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1826 data->pwm_auto_point_mapping[nr] = val;
1827 mutex_unlock(&data->update_lock);
1828
1829 return count;
1830}
1831
1832static ssize_t show_pwm_auto_point_temp(struct device *dev,
1833 struct device_attribute *devattr,
1834 char *buf)
1835{
1836 int result;
1837 struct f71882fg_data *data = f71882fg_update_device(dev);
1838 int pwm = to_sensor_dev_attr_2(devattr)->index;
1839 int point = to_sensor_dev_attr_2(devattr)->nr;
1840
1841 result = data->pwm_auto_point_temp[pwm][point];
1842 return sprintf(buf, "%d\n", 1000 * result);
1843}
1844
1845static ssize_t store_pwm_auto_point_temp(struct device *dev,
1846 struct device_attribute *devattr,
1847 const char *buf, size_t count)
1848{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001849 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001850 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001851 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001852 long val;
1853
1854 err = strict_strtol(buf, 10, &val);
1855 if (err)
1856 return err;
1857
1858 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001859
Hans de Goede98f7ba12011-03-09 20:57:09 +01001860 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001861 val = SENSORS_LIMIT(val, -128, 127);
1862 else
1863 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001864
1865 mutex_lock(&data->update_lock);
1866 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1867 data->pwm_auto_point_temp[pwm][point] = val;
1868 mutex_unlock(&data->update_lock);
1869
1870 return count;
1871}
1872
Hans de Goede45fb3662007-07-13 14:34:19 +02001873static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1874 char *buf)
1875{
Hans de Goede498be962009-01-07 16:37:28 +01001876 struct f71882fg_data *data = dev_get_drvdata(dev);
1877 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001878}
1879
Hans de Goedec13548c2009-01-07 16:37:27 +01001880static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1881 struct sensor_device_attribute_2 *attr, int count)
1882{
1883 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001884
Hans de Goedec13548c2009-01-07 16:37:27 +01001885 for (i = 0; i < count; i++) {
1886 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1887 if (err)
1888 return err;
1889 }
1890 return 0;
1891}
1892
Hans de Goedefc16c562009-12-09 20:36:01 +01001893static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1894 struct sensor_device_attribute_2 *attr, int count)
1895{
1896 int i;
1897
1898 for (i = 0; i < count; i++)
1899 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1900}
1901
Hans de Goedec13548c2009-01-07 16:37:27 +01001902static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001903{
1904 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001905 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001906 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01001907 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001908
Hans de Goedec13548c2009-01-07 16:37:27 +01001909 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1910 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001911 return -ENOMEM;
1912
1913 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001914 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001915 data->temp_start =
1916 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001917 mutex_init(&data->update_lock);
1918 platform_set_drvdata(pdev, data);
1919
Hans de Goede3cc74752009-01-07 16:37:28 +01001920 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001921 if (start_reg & 0x04) {
1922 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1923 err = -ENODEV;
1924 goto exit_free;
1925 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001926 if (!(start_reg & 0x03)) {
1927 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1928 err = -ENODEV;
1929 goto exit_free;
1930 }
1931
Hans de Goede45fb3662007-07-13 14:34:19 +02001932 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001933 err = device_create_file(&pdev->dev, &dev_attr_name);
1934 if (err)
1935 goto exit_unregister_sysfs;
1936
Hans de Goedec13548c2009-01-07 16:37:27 +01001937 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001938 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001939 case f71858fg:
1940 data->temp_config =
1941 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1942 if (data->temp_config & 0x10)
1943 /* The f71858fg temperature alarms behave as
1944 the f8000 alarms in this mode */
1945 err = f71882fg_create_sysfs_files(pdev,
1946 f8000_in_temp_attr,
1947 ARRAY_SIZE(f8000_in_temp_attr));
1948 else
1949 err = f71882fg_create_sysfs_files(pdev,
1950 f71858fg_in_temp_attr,
1951 ARRAY_SIZE(f71858fg_in_temp_attr));
1952 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001953 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001954 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001955 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001956 fxxxx_in1_alarm_attr,
1957 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001958 if (err)
1959 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001960 /* fall through! */
1961 case f71862fg:
1962 err = f71882fg_create_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001963 fxxxx_in_temp_attr,
1964 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001965 break;
1966 case f8000:
1967 err = f71882fg_create_sysfs_files(pdev,
1968 f8000_in_temp_attr,
1969 ARRAY_SIZE(f8000_in_temp_attr));
1970 break;
Hans de Goede498be962009-01-07 16:37:28 +01001971 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001972 if (err)
1973 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001974 }
1975
Hans de Goede45fb3662007-07-13 14:34:19 +02001976 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01001977 switch (data->type) {
1978 case f71889fg:
1979 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
1980 if (reg & F71882FG_FAN_NEG_TEMP_EN)
1981 data->auto_point_temp_signed = 1;
1982 break;
1983 default:
1984 break;
1985 }
1986
Hans de Goede996cadb2009-06-15 18:39:51 +02001987 data->pwm_enable =
1988 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1989
1990 /* Sanity check the pwm settings */
1991 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001992 case f71858fg:
1993 err = 0;
1994 for (i = 0; i < nr_fans; i++)
1995 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
1996 err = 1;
1997 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02001998 case f71862fg:
1999 err = (data->pwm_enable & 0x15) != 0x15;
2000 break;
2001 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002002 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002003 err = 0;
2004 break;
2005 case f8000:
2006 err = data->pwm_enable & 0x20;
2007 break;
2008 }
2009 if (err) {
2010 dev_err(&pdev->dev,
2011 "Invalid (reserved) pwm settings: 0x%02x\n",
2012 (unsigned int)data->pwm_enable);
2013 err = -ENODEV;
2014 goto exit_unregister_sysfs;
2015 }
2016
Hans de Goedeb69b0392009-12-09 20:36:00 +01002017 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2018 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002019 if (err)
2020 goto exit_unregister_sysfs;
2021
Hans de Goede76698962009-12-09 20:36:01 +01002022 if (data->type == f71862fg || data->type == f71882fg ||
2023 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002024 err = f71882fg_create_sysfs_files(pdev,
2025 fxxxx_fan_beep_attr, nr_fans);
2026 if (err)
2027 goto exit_unregister_sysfs;
2028 }
2029
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002030 switch (data->type) {
2031 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002032 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002033 f71862fg_auto_pwm_attr,
2034 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002035 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002036 case f8000:
2037 err = f71882fg_create_sysfs_files(pdev,
2038 f8000_fan_attr,
2039 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002040 if (err)
2041 goto exit_unregister_sysfs;
2042 err = f71882fg_create_sysfs_files(pdev,
2043 f8000_auto_pwm_attr,
2044 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002045 break;
Hans de Goede76698962009-12-09 20:36:01 +01002046 case f71889fg:
2047 for (i = 0; i < nr_fans; i++) {
2048 data->pwm_auto_point_mapping[i] =
2049 f71882fg_read8(data,
2050 F71882FG_REG_POINT_MAPPING(i));
2051 if (data->pwm_auto_point_mapping[i] & 0x80)
2052 break;
2053 }
2054 if (i != nr_fans) {
2055 dev_warn(&pdev->dev,
2056 "Auto pwm controlled by raw digital "
2057 "data, disabling pwm auto_point "
2058 "sysfs attributes\n");
2059 break;
2060 }
2061 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002062 default: /* f71858fg / f71882fg */
2063 err = f71882fg_create_sysfs_files(pdev,
2064 &fxxxx_auto_pwm_attr[0][0],
2065 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002066 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002067 if (err)
2068 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002069
2070 for (i = 0; i < nr_fans; i++)
2071 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2072 (data->pwm_enable & (1 << 2 * i)) ?
2073 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002074 }
2075
Tony Jones1beeffe2007-08-20 13:46:20 -07002076 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2077 if (IS_ERR(data->hwmon_dev)) {
2078 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002079 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002080 goto exit_unregister_sysfs;
2081 }
2082
2083 return 0;
2084
2085exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002086 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002087 return err; /* f71882fg_remove() also frees our data */
2088exit_free:
2089 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002090 return err;
2091}
2092
Hans de Goedec13548c2009-01-07 16:37:27 +01002093static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002094{
Hans de Goede45fb3662007-07-13 14:34:19 +02002095 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002096 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2097 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002098
Hans de Goedec13548c2009-01-07 16:37:27 +01002099 if (data->hwmon_dev)
2100 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002101
Hans de Goedec13548c2009-01-07 16:37:27 +01002102 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002103
Hans de Goedefc16c562009-12-09 20:36:01 +01002104 if (start_reg & 0x01) {
2105 switch (data->type) {
2106 case f71858fg:
2107 if (data->temp_config & 0x10)
2108 f71882fg_remove_sysfs_files(pdev,
2109 f8000_in_temp_attr,
2110 ARRAY_SIZE(f8000_in_temp_attr));
2111 else
2112 f71882fg_remove_sysfs_files(pdev,
2113 f71858fg_in_temp_attr,
2114 ARRAY_SIZE(f71858fg_in_temp_attr));
2115 break;
2116 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002117 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002118 f71882fg_remove_sysfs_files(pdev,
2119 fxxxx_in1_alarm_attr,
2120 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2121 /* fall through! */
2122 case f71862fg:
2123 f71882fg_remove_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07002124 fxxxx_in_temp_attr,
2125 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002126 break;
2127 case f8000:
2128 f71882fg_remove_sysfs_files(pdev,
2129 f8000_in_temp_attr,
2130 ARRAY_SIZE(f8000_in_temp_attr));
2131 break;
2132 }
2133 }
Hans de Goede498be962009-01-07 16:37:28 +01002134
Hans de Goedefc16c562009-12-09 20:36:01 +01002135 if (start_reg & 0x02) {
2136 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2137 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002138
Hans de Goede76698962009-12-09 20:36:01 +01002139 if (data->type == f71862fg || data->type == f71882fg ||
2140 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002141 f71882fg_remove_sysfs_files(pdev,
2142 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002143
Hans de Goedefc16c562009-12-09 20:36:01 +01002144 switch (data->type) {
2145 case f71862fg:
2146 f71882fg_remove_sysfs_files(pdev,
2147 f71862fg_auto_pwm_attr,
2148 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2149 break;
2150 case f8000:
2151 f71882fg_remove_sysfs_files(pdev,
2152 f8000_fan_attr,
2153 ARRAY_SIZE(f8000_fan_attr));
2154 f71882fg_remove_sysfs_files(pdev,
2155 f8000_auto_pwm_attr,
2156 ARRAY_SIZE(f8000_auto_pwm_attr));
2157 break;
2158 default: /* f71858fg / f71882fg / f71889fg */
2159 f71882fg_remove_sysfs_files(pdev,
2160 &fxxxx_auto_pwm_attr[0][0],
2161 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2162 }
2163 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002164
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002165 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002166 kfree(data);
2167
2168 return 0;
2169}
2170
Hans de Goede498be962009-01-07 16:37:28 +01002171static int __init f71882fg_find(int sioaddr, unsigned short *address,
2172 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002173{
Hans de Goede45fb3662007-07-13 14:34:19 +02002174 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002175 int err = superio_enter(sioaddr);
2176 if (err)
2177 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002178
2179 devid = superio_inw(sioaddr, SIO_REG_MANID);
2180 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002181 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002182 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002183 goto exit;
2184 }
2185
Jean Delvare67b671b2007-12-06 23:13:42 +01002186 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002187 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002188 case SIO_F71858_ID:
2189 sio_data->type = f71858fg;
2190 break;
Hans de Goede498be962009-01-07 16:37:28 +01002191 case SIO_F71862_ID:
2192 sio_data->type = f71862fg;
2193 break;
2194 case SIO_F71882_ID:
2195 sio_data->type = f71882fg;
2196 break;
Hans de Goede76698962009-12-09 20:36:01 +01002197 case SIO_F71889_ID:
2198 sio_data->type = f71889fg;
2199 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002200 case SIO_F8000_ID:
2201 sio_data->type = f8000;
2202 break;
Hans de Goede498be962009-01-07 16:37:28 +01002203 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002204 pr_info("Unsupported Fintek device: %04x\n",
2205 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002206 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002207 goto exit;
2208 }
2209
Hans de Goede09475d32009-06-15 18:39:52 +02002210 if (sio_data->type == f71858fg)
2211 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2212 else
2213 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2214
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002215 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002216 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002217 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002218 goto exit;
2219 }
2220
2221 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002222 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002223 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002224 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002225 goto exit;
2226 }
2227 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2228
Hans de Goede45fb3662007-07-13 14:34:19 +02002229 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002230 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002231 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002232 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2233exit:
2234 superio_exit(sioaddr);
2235 return err;
2236}
2237
Hans de Goede498be962009-01-07 16:37:28 +01002238static int __init f71882fg_device_add(unsigned short address,
2239 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002240{
2241 struct resource res = {
2242 .start = address,
2243 .end = address + REGION_LENGTH - 1,
2244 .flags = IORESOURCE_IO,
2245 };
2246 int err;
2247
2248 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002249 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002250 return -ENOMEM;
2251
2252 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002253 err = acpi_check_resource_conflict(&res);
2254 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002255 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002256
Hans de Goede45fb3662007-07-13 14:34:19 +02002257 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002258 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002259 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002260 goto exit_device_put;
2261 }
2262
Hans de Goede498be962009-01-07 16:37:28 +01002263 err = platform_device_add_data(f71882fg_pdev, sio_data,
2264 sizeof(struct f71882fg_sio_data));
2265 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002266 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002267 goto exit_device_put;
2268 }
2269
Hans de Goede45fb3662007-07-13 14:34:19 +02002270 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002271 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002272 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002273 goto exit_device_put;
2274 }
2275
2276 return 0;
2277
2278exit_device_put:
2279 platform_device_put(f71882fg_pdev);
2280
2281 return err;
2282}
2283
2284static int __init f71882fg_init(void)
2285{
2286 int err = -ENODEV;
2287 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002288 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002289
Hans de Goede498be962009-01-07 16:37:28 +01002290 memset(&sio_data, 0, sizeof(sio_data));
2291
2292 if (f71882fg_find(0x2e, &address, &sio_data) &&
2293 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002294 goto exit;
2295
Hans de Goedec13548c2009-01-07 16:37:27 +01002296 err = platform_driver_register(&f71882fg_driver);
2297 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002298 goto exit;
2299
Hans de Goede498be962009-01-07 16:37:28 +01002300 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002301 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002302 goto exit_driver;
2303
2304 return 0;
2305
2306exit_driver:
2307 platform_driver_unregister(&f71882fg_driver);
2308exit:
2309 return err;
2310}
2311
2312static void __exit f71882fg_exit(void)
2313{
2314 platform_device_unregister(f71882fg_pdev);
2315 platform_driver_unregister(&f71882fg_driver);
2316}
2317
2318MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002319MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002320MODULE_LICENSE("GPL");
2321
2322module_init(f71882fg_init);
2323module_exit(f71882fg_exit);