blob: 0f60b058ff9d53980554bd4120d9babbe6711704 [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 Goedee5e713c2011-03-10 08:54:02 +010050#define SIO_F71808E_ID 0x0901 /* Chipset ID */
Hans de Goede09475d32009-06-15 18:39:52 +020051#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010052#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goedec11bb992011-03-09 20:57:15 +010053#define SIO_F71869_ID 0x0814 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020054#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010055#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010056#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010057#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020058
59#define REGION_LENGTH 8
60#define ADDR_REG_OFFSET 5
61#define DATA_REG_OFFSET 6
62
Hans de Goede3cad4022011-03-09 20:57:14 +010063#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
64#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020065#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010066#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020067
68#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010069#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
70#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020071#define F71882FG_REG_FAN_STATUS 0x92
72#define F71882FG_REG_FAN_BEEP 0x93
73
Hans de Goede7567a042009-01-07 16:37:28 +010074#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
75#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
76#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020077#define F71882FG_REG_TEMP_STATUS 0x62
78#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020079#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010080#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020081#define F71882FG_REG_TEMP_TYPE 0x6B
82#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
83
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010084#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
85#define F71882FG_REG_PWM_TYPE 0x94
86#define F71882FG_REG_PWM_ENABLE 0x96
87
Hans de Goedebc274902009-01-07 16:37:29 +010088#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010089
Hans de Goede98f7ba12011-03-09 20:57:09 +010090#define F71882FG_REG_FAN_FAULT_T 0x9F
91#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010092#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010093
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010094#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
95#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
96#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
97
Hans de Goede45fb3662007-07-13 14:34:19 +020098#define F71882FG_REG_START 0x01
99
Hans de Goede0bae6402011-03-09 20:57:10 +0100100#define F71882FG_MAX_INS 9
101
Hans de Goede45fb3662007-07-13 14:34:19 +0200102#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
103
Jean Delvare67b671b2007-12-06 23:13:42 +0100104static unsigned short force_id;
105module_param(force_id, ushort, 0);
106MODULE_PARM_DESC(force_id, "Override the detected device ID");
107
Hans de Goedee5e713c2011-03-10 08:54:02 +0100108enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
109 f71889ed, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100110
111static const char *f71882fg_names[] = {
Hans de Goedee5e713c2011-03-10 08:54:02 +0100112 "f71808e",
Hans de Goede09475d32009-06-15 18:39:52 +0200113 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100114 "f71862fg",
Hans de Goedec11bb992011-03-09 20:57:15 +0100115 "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
Hans de Goede498be962009-01-07 16:37:28 +0100116 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100117 "f71889fg",
Hans de Goede3cad4022011-03-09 20:57:14 +0100118 "f71889ed",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100119 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100120};
121
Jean Delvare2740c602011-03-26 10:45:01 +0100122static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
123 [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
124 [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
125 [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
126 [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
127 [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
128 [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
129 [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
130 [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
Hans de Goede0bae6402011-03-09 20:57:10 +0100131};
132
Jean Delvare2740c602011-03-26 10:45:01 +0100133static const char f71882fg_has_in1_alarm[] = {
134 [f71808e] = 0,
135 [f71858fg] = 0,
136 [f71862fg] = 0,
137 [f71869] = 0,
138 [f71882fg] = 1,
139 [f71889fg] = 1,
140 [f71889ed] = 1,
141 [f8000] = 0,
Hans de Goede0bae6402011-03-09 20:57:10 +0100142};
143
Jean Delvare2740c602011-03-26 10:45:01 +0100144static const char f71882fg_has_beep[] = {
145 [f71808e] = 0,
146 [f71858fg] = 0,
147 [f71862fg] = 1,
148 [f71869] = 1,
149 [f71882fg] = 1,
150 [f71889fg] = 1,
151 [f71889ed] = 1,
152 [f8000] = 0,
Hans de Goede78aa4f72011-03-09 20:57:12 +0100153};
154
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100155static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200156
157/* Super-I/O Function prototypes */
158static inline int superio_inb(int base, int reg);
159static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400160static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200161static inline void superio_select(int base, int ld);
162static inline void superio_exit(int base);
163
Hans de Goede498be962009-01-07 16:37:28 +0100164struct f71882fg_sio_data {
165 enum chips type;
166};
167
Hans de Goede45fb3662007-07-13 14:34:19 +0200168struct f71882fg_data {
169 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100170 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700171 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200172
173 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200174 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200175 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100176 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200177 unsigned long last_updated; /* In jiffies */
178 unsigned long last_limits; /* In jiffies */
179
180 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100181 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200182 u8 in1_max;
183 u8 in_status;
184 u8 in_beep;
185 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100186 u16 fan_target[4];
187 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200188 u8 fan_status;
189 u8 fan_beep;
Hans de Goedee5e713c2011-03-10 08:54:02 +0100190 /* Note: all models have max 3 temperature channels, but on some
Hans de Goede7567a042009-01-07 16:37:28 +0100191 they are addressed as 0-2 and on others as 1-3, so for coding
192 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200193 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100194 u8 temp_ovt[4];
195 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100196 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100197 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200198 u8 temp_status;
199 u8 temp_beep;
200 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200201 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100202 u8 pwm[4];
203 u8 pwm_enable;
204 u8 pwm_auto_point_hyst[2];
205 u8 pwm_auto_point_mapping[4];
206 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100207 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200208};
209
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100210/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200211static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
212 char *buf);
213static ssize_t show_in_max(struct device *dev, struct device_attribute
214 *devattr, char *buf);
215static ssize_t store_in_max(struct device *dev, struct device_attribute
216 *devattr, const char *buf, size_t count);
217static ssize_t show_in_beep(struct device *dev, struct device_attribute
218 *devattr, char *buf);
219static ssize_t store_in_beep(struct device *dev, struct device_attribute
220 *devattr, const char *buf, size_t count);
221static ssize_t show_in_alarm(struct device *dev, struct device_attribute
222 *devattr, char *buf);
223/* Sysfs Fan */
224static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
225 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100226static ssize_t show_fan_full_speed(struct device *dev,
227 struct device_attribute *devattr, char *buf);
228static ssize_t store_fan_full_speed(struct device *dev,
229 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200230static ssize_t show_fan_beep(struct device *dev, struct device_attribute
231 *devattr, char *buf);
232static ssize_t store_fan_beep(struct device *dev, struct device_attribute
233 *devattr, const char *buf, size_t count);
234static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
235 *devattr, char *buf);
236/* Sysfs Temp */
237static ssize_t show_temp(struct device *dev, struct device_attribute
238 *devattr, char *buf);
239static ssize_t show_temp_max(struct device *dev, struct device_attribute
240 *devattr, char *buf);
241static ssize_t store_temp_max(struct device *dev, struct device_attribute
242 *devattr, const char *buf, size_t count);
243static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
244 *devattr, char *buf);
245static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
246 *devattr, const char *buf, size_t count);
247static ssize_t show_temp_crit(struct device *dev, struct device_attribute
248 *devattr, char *buf);
249static ssize_t store_temp_crit(struct device *dev, struct device_attribute
250 *devattr, const char *buf, size_t count);
251static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
252 *devattr, char *buf);
253static ssize_t show_temp_type(struct device *dev, struct device_attribute
254 *devattr, char *buf);
255static ssize_t show_temp_beep(struct device *dev, struct device_attribute
256 *devattr, char *buf);
257static ssize_t store_temp_beep(struct device *dev, struct device_attribute
258 *devattr, const char *buf, size_t count);
259static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
260 *devattr, char *buf);
261static ssize_t show_temp_fault(struct device *dev, struct device_attribute
262 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100263/* PWM and Auto point control */
264static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
265 char *buf);
266static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
267 const char *buf, size_t count);
268static ssize_t show_pwm_enable(struct device *dev,
269 struct device_attribute *devattr, char *buf);
270static ssize_t store_pwm_enable(struct device *dev,
271 struct device_attribute *devattr, const char *buf, size_t count);
272static ssize_t show_pwm_interpolate(struct device *dev,
273 struct device_attribute *devattr, char *buf);
274static ssize_t store_pwm_interpolate(struct device *dev,
275 struct device_attribute *devattr, const char *buf, size_t count);
276static ssize_t show_pwm_auto_point_channel(struct device *dev,
277 struct device_attribute *devattr, char *buf);
278static ssize_t store_pwm_auto_point_channel(struct device *dev,
279 struct device_attribute *devattr, const char *buf, size_t count);
280static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
281 struct device_attribute *devattr, char *buf);
282static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
283 struct device_attribute *devattr, const char *buf, size_t count);
284static ssize_t show_pwm_auto_point_pwm(struct device *dev,
285 struct device_attribute *devattr, char *buf);
286static ssize_t store_pwm_auto_point_pwm(struct device *dev,
287 struct device_attribute *devattr, const char *buf, size_t count);
288static ssize_t show_pwm_auto_point_temp(struct device *dev,
289 struct device_attribute *devattr, char *buf);
290static ssize_t store_pwm_auto_point_temp(struct device *dev,
291 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200292/* Sysfs misc */
293static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
294 char *buf);
295
296static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100297static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200298
299static struct platform_driver f71882fg_driver = {
300 .driver = {
301 .owner = THIS_MODULE,
302 .name = DRVNAME,
303 },
304 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200305 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200306};
307
Hans de Goedec13548c2009-01-07 16:37:27 +0100308static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200309
Hans de Goede0bae6402011-03-09 20:57:10 +0100310/* Temp attr for the f71858fg, the f71858fg is special as it has its
311 temperature indexes start at 0 (the others start at 1) */
312static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200313 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
314 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
315 store_temp_max, 0, 0),
316 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
317 store_temp_max_hyst, 0, 0),
318 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
319 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
320 store_temp_crit, 0, 0),
321 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
322 0, 0),
323 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
324 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
325 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
326 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
327 store_temp_max, 0, 1),
328 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
329 store_temp_max_hyst, 0, 1),
330 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
331 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
332 store_temp_crit, 0, 1),
333 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
334 0, 1),
335 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200336 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
337 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
338 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
339 store_temp_max, 0, 2),
340 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
341 store_temp_max_hyst, 0, 2),
342 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
343 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
344 store_temp_crit, 0, 2),
345 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
346 0, 2),
347 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
348 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
349};
350
Hans de Goede0bae6402011-03-09 20:57:10 +0100351/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100352static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100354 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100355 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100357 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100358 /* Should really be temp1_max_alarm, but older versions did not handle
359 the max and crit alarms separately and lm_sensors v2 depends on the
360 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
361 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100362 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100363 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100364 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100365 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100366 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100368 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100369}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100370 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
371 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100372 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100373 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100374 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100375 /* Should be temp2_max_alarm, see temp1_alarm note */
376 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100377 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100378 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100379 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100380 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100381 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100382 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100383 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100384}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100385 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
386 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
387 store_temp_max, 0, 3),
388 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
389 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100390 /* Should be temp3_max_alarm, see temp1_alarm note */
391 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100392 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
393 store_temp_crit, 0, 3),
394 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
395 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100396 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100397 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100398 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100399} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200400
Hans de Goede78aa4f72011-03-09 20:57:12 +0100401/* Temp attr for models which can beep on temp alarm */
402static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
403 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
404 store_temp_beep, 0, 1),
405 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
406 store_temp_beep, 0, 5),
407}, {
408 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
409 store_temp_beep, 0, 2),
410 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
411 store_temp_beep, 0, 6),
412}, {
413 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
414 store_temp_beep, 0, 3),
415 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
416 store_temp_beep, 0, 7),
417} };
418
Hans de Goede0bae6402011-03-09 20:57:10 +0100419/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100420 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
421 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100422 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100423 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100424static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100425 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
426 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
427 store_temp_crit, 0, 0),
428 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
429 store_temp_max, 0, 0),
430 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200431 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100432 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
433 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
434 store_temp_crit, 0, 1),
435 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
436 store_temp_max, 0, 1),
437 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200438 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100439 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
440 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
441 store_temp_crit, 0, 2),
442 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
443 store_temp_max, 0, 2),
444 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200445 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100446};
447
Hans de Goede0bae6402011-03-09 20:57:10 +0100448/* in attr for all models */
449static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
450 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
451 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
452 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
453 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
454 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
455 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
456 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
457 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
458 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
459};
460
461/* For models with in1 alarm capability */
462static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
463 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
464 0, 1),
465 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
466 0, 1),
467 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
468};
469
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100470/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100471static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100472 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100473 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
474 show_fan_full_speed,
475 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100476 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100477 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
478 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
479 store_pwm_enable, 0, 0),
480 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
481 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100482}, {
483 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
484 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
485 show_fan_full_speed,
486 store_fan_full_speed, 0, 1),
487 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100488 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
489 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
490 store_pwm_enable, 0, 1),
491 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
492 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100493}, {
494 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
495 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
496 show_fan_full_speed,
497 store_fan_full_speed, 0, 2),
498 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200499 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
500 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
501 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100502 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
503 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100504}, {
505 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
506 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
507 show_fan_full_speed,
508 store_fan_full_speed, 0, 3),
509 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
510 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
511 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
512 store_pwm_enable, 0, 3),
513 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
514 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
515} };
Hans de Goede498be962009-01-07 16:37:28 +0100516
Hans de Goede66344aa2009-12-09 20:35:59 +0100517/* Attr for models which can beep on Fan alarm */
518static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100519 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
520 store_fan_beep, 0, 0),
521 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
522 store_fan_beep, 0, 1),
523 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
524 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100525 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
526 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100527};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100528
Hans de Goede66344aa2009-12-09 20:35:59 +0100529/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100530 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100531static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
532 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_channel,
534 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100535 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
537 1, 0),
538 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
540 4, 0),
541 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
543 0, 0),
544 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
545 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
546 3, 0),
547 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
548 show_pwm_auto_point_temp_hyst,
549 store_pwm_auto_point_temp_hyst,
550 0, 0),
551 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
552 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
553
Hans de Goede66344aa2009-12-09 20:35:59 +0100554 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_channel,
556 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100557 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
559 1, 1),
560 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
562 4, 1),
563 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
565 0, 1),
566 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
567 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
568 3, 1),
569 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_temp_hyst,
571 store_pwm_auto_point_temp_hyst,
572 0, 1),
573 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
574 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100575
Hans de Goede66344aa2009-12-09 20:35:59 +0100576 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_channel,
578 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100579 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
581 1, 2),
582 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
584 4, 2),
585 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
587 0, 2),
588 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
589 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
590 3, 2),
591 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
592 show_pwm_auto_point_temp_hyst,
593 store_pwm_auto_point_temp_hyst,
594 0, 2),
595 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
596 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100597};
598
Hans de Goedee5e713c2011-03-10 08:54:02 +0100599/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
Hans de Goedec11bb992011-03-09 20:57:15 +0100600 pwm setting when the temperature is above the pwmX_auto_point1_temp can be
601 programmed instead of being hardcoded to 0xff */
602static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
603 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
604 show_pwm_auto_point_channel,
605 store_pwm_auto_point_channel, 0, 0),
606 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
607 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
608 0, 0),
609 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
610 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
611 1, 0),
612 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
613 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
614 4, 0),
615 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
616 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
617 0, 0),
618 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
619 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
620 3, 0),
621 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
622 show_pwm_auto_point_temp_hyst,
623 store_pwm_auto_point_temp_hyst,
624 0, 0),
625 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
626 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
627
628 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_channel,
630 store_pwm_auto_point_channel, 0, 1),
631 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
633 0, 1),
634 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 1, 1),
637 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 4, 1),
640 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 0, 1),
643 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
645 3, 1),
646 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_temp_hyst,
648 store_pwm_auto_point_temp_hyst,
649 0, 1),
650 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
651 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
652
653 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
654 show_pwm_auto_point_channel,
655 store_pwm_auto_point_channel, 0, 2),
656 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
658 0, 2),
659 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
661 1, 2),
662 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
664 4, 2),
665 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
667 0, 2),
668 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
670 3, 2),
671 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
672 show_pwm_auto_point_temp_hyst,
673 store_pwm_auto_point_temp_hyst,
674 0, 2),
675 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
676 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
677};
678
Hans de Goede3cad4022011-03-09 20:57:14 +0100679/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100680static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100681 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_channel,
683 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100684 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 0, 0),
687 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
689 1, 0),
690 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
692 2, 0),
693 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
695 3, 0),
696 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
698 4, 0),
699 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
701 0, 0),
702 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
704 1, 0),
705 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
707 2, 0),
708 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
710 3, 0),
711 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
712 show_pwm_auto_point_temp_hyst,
713 store_pwm_auto_point_temp_hyst,
714 0, 0),
715 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
716 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
717 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
718 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
719 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
720 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100721}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100722 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_channel,
724 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100725 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
727 0, 1),
728 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 1, 1),
731 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 2, 1),
734 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
736 3, 1),
737 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
739 4, 1),
740 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
742 0, 1),
743 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
745 1, 1),
746 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
748 2, 1),
749 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
751 3, 1),
752 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_temp_hyst,
754 store_pwm_auto_point_temp_hyst,
755 0, 1),
756 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
757 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
758 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
759 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
760 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
761 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100762}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100763 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
764 show_pwm_auto_point_channel,
765 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100766 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
768 0, 2),
769 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
771 1, 2),
772 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
774 2, 2),
775 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
777 3, 2),
778 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
780 4, 2),
781 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
783 0, 2),
784 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
785 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
786 1, 2),
787 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
789 2, 2),
790 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
791 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
792 3, 2),
793 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
794 show_pwm_auto_point_temp_hyst,
795 store_pwm_auto_point_temp_hyst,
796 0, 2),
797 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
798 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
799 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
800 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
801 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
802 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100803}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100804 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
805 show_pwm_auto_point_channel,
806 store_pwm_auto_point_channel, 0, 3),
807 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
809 0, 3),
810 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
812 1, 3),
813 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
815 2, 3),
816 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
818 3, 3),
819 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
821 4, 3),
822 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
823 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
824 0, 3),
825 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
826 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
827 1, 3),
828 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
830 2, 3),
831 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
832 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
833 3, 3),
834 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
835 show_pwm_auto_point_temp_hyst,
836 store_pwm_auto_point_temp_hyst,
837 0, 3),
838 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
839 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
840 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
841 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
842 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
843 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100844} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200845
Hans de Goede66344aa2009-12-09 20:35:59 +0100846/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100847static struct sensor_device_attribute_2 f8000_fan_attr[] = {
848 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100849};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100850
Hans de Goede66344aa2009-12-09 20:35:59 +0100851/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
852 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
853 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
854static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
855 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_channel,
857 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100858 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
860 0, 2),
861 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
863 1, 2),
864 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
866 2, 2),
867 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
869 3, 2),
870 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
872 4, 2),
873 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
875 0, 2),
876 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
877 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
878 1, 2),
879 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
880 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
881 2, 2),
882 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
883 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
884 3, 2),
885 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
886 show_pwm_auto_point_temp_hyst,
887 store_pwm_auto_point_temp_hyst,
888 0, 2),
889 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
890 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
891 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
892 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
893 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
894 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
895
Hans de Goede66344aa2009-12-09 20:35:59 +0100896 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
897 show_pwm_auto_point_channel,
898 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100899 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
900 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
901 0, 0),
902 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
903 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
904 1, 0),
905 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
906 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
907 2, 0),
908 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
909 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
910 3, 0),
911 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
912 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
913 4, 0),
914 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
915 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
916 0, 0),
917 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
918 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
919 1, 0),
920 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
921 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
922 2, 0),
923 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
924 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
925 3, 0),
926 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
927 show_pwm_auto_point_temp_hyst,
928 store_pwm_auto_point_temp_hyst,
929 0, 0),
930 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
931 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
932 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
933 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
934 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
935 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
936
Hans de Goede66344aa2009-12-09 20:35:59 +0100937 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
938 show_pwm_auto_point_channel,
939 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100940 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
941 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
942 0, 1),
943 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
944 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
945 1, 1),
946 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
947 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
948 2, 1),
949 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
950 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
951 3, 1),
952 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
953 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
954 4, 1),
955 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
956 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
957 0, 1),
958 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
959 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
960 1, 1),
961 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
962 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
963 2, 1),
964 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
965 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
966 3, 1),
967 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
968 show_pwm_auto_point_temp_hyst,
969 store_pwm_auto_point_temp_hyst,
970 0, 1),
971 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
972 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
973 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
974 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
975 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
976 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
977};
Hans de Goede45fb3662007-07-13 14:34:19 +0200978
979/* Super I/O functions */
980static inline int superio_inb(int base, int reg)
981{
982 outb(reg, base);
983 return inb(base + 1);
984}
985
986static int superio_inw(int base, int reg)
987{
988 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200989 val = superio_inb(base, reg) << 8;
990 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200991 return val;
992}
993
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400994static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200995{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400996 /* Don't step on other drivers' I/O space by accident */
997 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000998 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400999 return -EBUSY;
1000 }
1001
Hans de Goede45fb3662007-07-13 14:34:19 +02001002 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001003 outb(SIO_UNLOCK_KEY, base);
1004 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001005
1006 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001007}
1008
Giel van Schijndel162bb592010-05-27 19:58:40 +02001009static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001010{
1011 outb(SIO_REG_LDSEL, base);
1012 outb(ld, base + 1);
1013}
1014
1015static inline void superio_exit(int base)
1016{
1017 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001018 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001019}
1020
Hans de Goede2f650632009-01-07 16:37:31 +01001021static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001022{
1023 return reg ? (1500000 / reg) : 0;
1024}
1025
Hans de Goede2f650632009-01-07 16:37:31 +01001026static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001027{
1028 return fan ? (1500000 / fan) : 0;
1029}
1030
Hans de Goede45fb3662007-07-13 14:34:19 +02001031static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1032{
1033 u8 val;
1034
1035 outb(reg, data->addr + ADDR_REG_OFFSET);
1036 val = inb(data->addr + DATA_REG_OFFSET);
1037
1038 return val;
1039}
1040
1041static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1042{
1043 u16 val;
1044
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001045 val = f71882fg_read8(data, reg) << 8;
1046 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001047
1048 return val;
1049}
1050
1051static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1052{
1053 outb(reg, data->addr + ADDR_REG_OFFSET);
1054 outb(val, data->addr + DATA_REG_OFFSET);
1055}
1056
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001057static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1058{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001059 f71882fg_write8(data, reg, val >> 8);
1060 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001061}
1062
Hans de Goede09475d32009-06-15 18:39:52 +02001063static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1064{
1065 if (data->type == f71858fg)
1066 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1067 else
1068 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1069}
1070
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001071static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001072{
1073 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001074 int nr, reg, point;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001075 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goedee5e713c2011-03-10 08:54:02 +01001076 int nr_temps = (data->type == f71808e) ? 2 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001077
1078 mutex_lock(&data->update_lock);
1079
1080 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001081 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001082 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001083 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001084 data->in1_max =
1085 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1086 data->in_beep =
1087 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1088 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001089
1090 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001091 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1092 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001093 data->temp_ovt[nr] = f71882fg_read8(data,
1094 F71882FG_REG_TEMP_OVT(nr));
1095 data->temp_high[nr] = f71882fg_read8(data,
1096 F71882FG_REG_TEMP_HIGH(nr));
1097 }
1098
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001099 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001100 data->temp_hyst[0] = f71882fg_read8(data,
1101 F71882FG_REG_TEMP_HYST(0));
1102 data->temp_hyst[1] = f71882fg_read8(data,
1103 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001104 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001105 /* All but the f71858fg / f8000 have this register */
1106 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001107 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001108 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001109 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1110 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1111 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001112
Hans de Goede78aa4f72011-03-09 20:57:12 +01001113 if (f71882fg_has_beep[data->type]) {
1114 data->fan_beep = f71882fg_read8(data,
1115 F71882FG_REG_FAN_BEEP);
1116 data->temp_beep = f71882fg_read8(data,
1117 F71882FG_REG_TEMP_BEEP);
1118 }
1119
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001120 data->pwm_enable = f71882fg_read8(data,
1121 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001122 data->pwm_auto_point_hyst[0] =
1123 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1124 data->pwm_auto_point_hyst[1] =
1125 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1126
Hans de Goede498be962009-01-07 16:37:28 +01001127 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001128 data->pwm_auto_point_mapping[nr] =
1129 f71882fg_read8(data,
1130 F71882FG_REG_POINT_MAPPING(nr));
1131
Hans de Goedee5e713c2011-03-10 08:54:02 +01001132 switch (data->type) {
1133 default:
Hans de Goede498be962009-01-07 16:37:28 +01001134 for (point = 0; point < 5; point++) {
1135 data->pwm_auto_point_pwm[nr][point] =
1136 f71882fg_read8(data,
1137 F71882FG_REG_POINT_PWM
1138 (nr, point));
1139 }
1140 for (point = 0; point < 4; point++) {
1141 data->pwm_auto_point_temp[nr][point] =
1142 f71882fg_read8(data,
1143 F71882FG_REG_POINT_TEMP
1144 (nr, point));
1145 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001146 break;
1147 case f71808e:
1148 case f71869:
1149 data->pwm_auto_point_pwm[nr][0] =
1150 f71882fg_read8(data,
1151 F71882FG_REG_POINT_PWM(nr, 0));
1152 /* Fall through */
1153 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001154 data->pwm_auto_point_pwm[nr][1] =
1155 f71882fg_read8(data,
1156 F71882FG_REG_POINT_PWM
1157 (nr, 1));
1158 data->pwm_auto_point_pwm[nr][4] =
1159 f71882fg_read8(data,
1160 F71882FG_REG_POINT_PWM
1161 (nr, 4));
1162 data->pwm_auto_point_temp[nr][0] =
1163 f71882fg_read8(data,
1164 F71882FG_REG_POINT_TEMP
1165 (nr, 0));
1166 data->pwm_auto_point_temp[nr][3] =
1167 f71882fg_read8(data,
1168 F71882FG_REG_POINT_TEMP
1169 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001170 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001171 }
1172 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001173 data->last_limits = jiffies;
1174 }
1175
1176 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001177 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001178 data->temp_status = f71882fg_read8(data,
1179 F71882FG_REG_TEMP_STATUS);
1180 data->temp_diode_open = f71882fg_read8(data,
1181 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001182 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1183 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001184 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001185
1186 data->fan_status = f71882fg_read8(data,
1187 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001188 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001189 data->fan[nr] = f71882fg_read16(data,
1190 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001191 data->fan_target[nr] =
1192 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1193 data->fan_full_speed[nr] =
1194 f71882fg_read16(data,
1195 F71882FG_REG_FAN_FULL_SPEED(nr));
1196 data->pwm[nr] =
1197 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1198 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001199 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1200 if (data->type == f8000)
1201 data->fan[3] = f71882fg_read16(data,
1202 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001203
1204 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001205 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001206 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001207 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1208 if (f71882fg_has_in[data->type][nr])
1209 data->in[nr] = f71882fg_read8(data,
1210 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001211
1212 data->last_updated = jiffies;
1213 data->valid = 1;
1214 }
1215
1216 mutex_unlock(&data->update_lock);
1217
1218 return data;
1219}
1220
1221/* Sysfs Interface */
1222static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1223 char *buf)
1224{
1225 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001226 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001227 int speed = fan_from_reg(data->fan[nr]);
1228
1229 if (speed == FAN_MIN_DETECT)
1230 speed = 0;
1231
1232 return sprintf(buf, "%d\n", speed);
1233}
1234
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001235static ssize_t show_fan_full_speed(struct device *dev,
1236 struct device_attribute *devattr, char *buf)
1237{
1238 struct f71882fg_data *data = f71882fg_update_device(dev);
1239 int nr = to_sensor_dev_attr_2(devattr)->index;
1240 int speed = fan_from_reg(data->fan_full_speed[nr]);
1241 return sprintf(buf, "%d\n", speed);
1242}
1243
1244static ssize_t store_fan_full_speed(struct device *dev,
1245 struct device_attribute *devattr,
1246 const char *buf, size_t count)
1247{
1248 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001249 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1250 long val;
1251
1252 err = strict_strtol(buf, 10, &val);
1253 if (err)
1254 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001255
1256 val = SENSORS_LIMIT(val, 23, 1500000);
1257 val = fan_to_reg(val);
1258
1259 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001260 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1261 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001262 mutex_unlock(&data->update_lock);
1263
1264 return count;
1265}
1266
Hans de Goede45fb3662007-07-13 14:34:19 +02001267static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1268 *devattr, char *buf)
1269{
1270 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001271 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001272
1273 if (data->fan_beep & (1 << nr))
1274 return sprintf(buf, "1\n");
1275 else
1276 return sprintf(buf, "0\n");
1277}
1278
1279static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1280 *devattr, const char *buf, size_t count)
1281{
1282 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001283 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1284 unsigned long val;
1285
1286 err = strict_strtoul(buf, 10, &val);
1287 if (err)
1288 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001289
1290 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001291 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001292 if (val)
1293 data->fan_beep |= 1 << nr;
1294 else
1295 data->fan_beep &= ~(1 << nr);
1296
1297 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1298 mutex_unlock(&data->update_lock);
1299
1300 return count;
1301}
1302
1303static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1304 *devattr, char *buf)
1305{
1306 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001307 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001308
1309 if (data->fan_status & (1 << nr))
1310 return sprintf(buf, "1\n");
1311 else
1312 return sprintf(buf, "0\n");
1313}
1314
1315static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1316 char *buf)
1317{
1318 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001319 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001320
1321 return sprintf(buf, "%d\n", data->in[nr] * 8);
1322}
1323
1324static ssize_t show_in_max(struct device *dev, struct device_attribute
1325 *devattr, char *buf)
1326{
1327 struct f71882fg_data *data = f71882fg_update_device(dev);
1328
1329 return sprintf(buf, "%d\n", data->in1_max * 8);
1330}
1331
1332static ssize_t store_in_max(struct device *dev, struct device_attribute
1333 *devattr, const char *buf, size_t count)
1334{
1335 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001336 int err;
1337 long val;
1338
1339 err = strict_strtol(buf, 10, &val);
1340 if (err)
1341 return err;
1342
1343 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001344 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001345
1346 mutex_lock(&data->update_lock);
1347 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1348 data->in1_max = val;
1349 mutex_unlock(&data->update_lock);
1350
1351 return count;
1352}
1353
1354static ssize_t show_in_beep(struct device *dev, struct device_attribute
1355 *devattr, char *buf)
1356{
1357 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001358 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001359
1360 if (data->in_beep & (1 << nr))
1361 return sprintf(buf, "1\n");
1362 else
1363 return sprintf(buf, "0\n");
1364}
1365
1366static ssize_t store_in_beep(struct device *dev, struct device_attribute
1367 *devattr, const char *buf, size_t count)
1368{
1369 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001370 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1371 unsigned long val;
1372
1373 err = strict_strtoul(buf, 10, &val);
1374 if (err)
1375 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001376
1377 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001378 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001379 if (val)
1380 data->in_beep |= 1 << nr;
1381 else
1382 data->in_beep &= ~(1 << nr);
1383
1384 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1385 mutex_unlock(&data->update_lock);
1386
1387 return count;
1388}
1389
1390static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1391 *devattr, char *buf)
1392{
1393 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001394 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001395
1396 if (data->in_status & (1 << nr))
1397 return sprintf(buf, "1\n");
1398 else
1399 return sprintf(buf, "0\n");
1400}
1401
1402static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1403 char *buf)
1404{
1405 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001406 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001407 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001408
Hans de Goede09475d32009-06-15 18:39:52 +02001409 if (data->type == f71858fg) {
1410 /* TEMP_TABLE_SEL 1 or 3 ? */
1411 if (data->temp_config & 1) {
1412 sign = data->temp[nr] & 0x0001;
1413 temp = (data->temp[nr] >> 5) & 0x7ff;
1414 } else {
1415 sign = data->temp[nr] & 0x8000;
1416 temp = (data->temp[nr] >> 5) & 0x3ff;
1417 }
1418 temp *= 125;
1419 if (sign)
1420 temp -= 128000;
1421 } else
1422 temp = data->temp[nr] * 1000;
1423
1424 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001425}
1426
1427static ssize_t show_temp_max(struct device *dev, struct device_attribute
1428 *devattr, char *buf)
1429{
1430 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001431 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001432
1433 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1434}
1435
1436static ssize_t store_temp_max(struct device *dev, struct device_attribute
1437 *devattr, const char *buf, size_t count)
1438{
1439 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001440 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1441 long val;
1442
1443 err = strict_strtol(buf, 10, &val);
1444 if (err)
1445 return err;
1446
1447 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001448 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001449
1450 mutex_lock(&data->update_lock);
1451 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1452 data->temp_high[nr] = val;
1453 mutex_unlock(&data->update_lock);
1454
1455 return count;
1456}
1457
1458static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1459 *devattr, char *buf)
1460{
1461 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001462 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001463 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001464
Hans de Goedece0bfa52009-01-07 16:37:28 +01001465 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001466 if (nr & 1)
1467 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1468 else
1469 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1470 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001471 mutex_unlock(&data->update_lock);
1472
1473 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001474}
1475
1476static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1477 *devattr, const char *buf, size_t count)
1478{
1479 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001480 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001481 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001482 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001483 long val;
1484
1485 err = strict_strtol(buf, 10, &val);
1486 if (err)
1487 return err;
1488
1489 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001490
1491 mutex_lock(&data->update_lock);
1492
1493 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001494 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1495 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1496 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001497 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001498
1499 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001500 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1501 if (nr & 1)
1502 reg = (reg & 0x0f) | (val << 4);
1503 else
1504 reg = (reg & 0xf0) | val;
1505 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1506 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001507
Hans de Goede45fb3662007-07-13 14:34:19 +02001508 mutex_unlock(&data->update_lock);
1509 return ret;
1510}
1511
1512static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1513 *devattr, char *buf)
1514{
1515 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001516 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001517
1518 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1519}
1520
1521static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1522 *devattr, const char *buf, size_t count)
1523{
1524 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001525 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1526 long val;
1527
1528 err = strict_strtol(buf, 10, &val);
1529 if (err)
1530 return err;
1531
1532 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001533 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001534
1535 mutex_lock(&data->update_lock);
1536 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1537 data->temp_ovt[nr] = val;
1538 mutex_unlock(&data->update_lock);
1539
1540 return count;
1541}
1542
1543static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1544 *devattr, char *buf)
1545{
1546 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001547 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001548 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001549
Hans de Goedece0bfa52009-01-07 16:37:28 +01001550 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001551 if (nr & 1)
1552 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1553 else
1554 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1555 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001556 mutex_unlock(&data->update_lock);
1557
1558 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001559}
1560
1561static ssize_t show_temp_type(struct device *dev, struct device_attribute
1562 *devattr, char *buf)
1563{
1564 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001565 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001566
1567 return sprintf(buf, "%d\n", data->temp_type[nr]);
1568}
1569
1570static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1571 *devattr, char *buf)
1572{
1573 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001574 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001575
Hans de Goede7567a042009-01-07 16:37:28 +01001576 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001577 return sprintf(buf, "1\n");
1578 else
1579 return sprintf(buf, "0\n");
1580}
1581
1582static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1583 *devattr, const char *buf, size_t count)
1584{
1585 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001586 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1587 unsigned long val;
1588
1589 err = strict_strtoul(buf, 10, &val);
1590 if (err)
1591 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001592
1593 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001594 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001595 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001596 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001597 else
Hans de Goede7567a042009-01-07 16:37:28 +01001598 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001599
1600 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1601 mutex_unlock(&data->update_lock);
1602
1603 return count;
1604}
1605
1606static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1607 *devattr, char *buf)
1608{
1609 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001610 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001611
Hans de Goede7567a042009-01-07 16:37:28 +01001612 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001613 return sprintf(buf, "1\n");
1614 else
1615 return sprintf(buf, "0\n");
1616}
1617
1618static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1619 *devattr, char *buf)
1620{
1621 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001622 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001623
Hans de Goede7567a042009-01-07 16:37:28 +01001624 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001625 return sprintf(buf, "1\n");
1626 else
1627 return sprintf(buf, "0\n");
1628}
1629
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001630static ssize_t show_pwm(struct device *dev,
1631 struct device_attribute *devattr, char *buf)
1632{
1633 struct f71882fg_data *data = f71882fg_update_device(dev);
1634 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001635 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001636 if (data->pwm_enable & (1 << (2 * nr)))
1637 /* PWM mode */
1638 val = data->pwm[nr];
1639 else {
1640 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001641 val = 255 * fan_from_reg(data->fan_target[nr])
1642 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001643 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001644 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001645 return sprintf(buf, "%d\n", val);
1646}
1647
1648static ssize_t store_pwm(struct device *dev,
1649 struct device_attribute *devattr, const char *buf,
1650 size_t count)
1651{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001652 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001653 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1654 long val;
1655
1656 err = strict_strtol(buf, 10, &val);
1657 if (err)
1658 return err;
1659
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001660 val = SENSORS_LIMIT(val, 0, 255);
1661
1662 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001663 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001664 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1665 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1666 count = -EROFS;
1667 goto leave;
1668 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001669 if (data->pwm_enable & (1 << (2 * nr))) {
1670 /* PWM mode */
1671 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1672 data->pwm[nr] = val;
1673 } else {
1674 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001675 int target, full_speed;
1676 full_speed = f71882fg_read16(data,
1677 F71882FG_REG_FAN_FULL_SPEED(nr));
1678 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1679 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1680 data->fan_target[nr] = target;
1681 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001682 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001683leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001684 mutex_unlock(&data->update_lock);
1685
1686 return count;
1687}
1688
1689static ssize_t show_pwm_enable(struct device *dev,
1690 struct device_attribute *devattr, char *buf)
1691{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001692 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001693 struct f71882fg_data *data = f71882fg_update_device(dev);
1694 int nr = to_sensor_dev_attr_2(devattr)->index;
1695
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001696 switch ((data->pwm_enable >> 2 * nr) & 3) {
1697 case 0:
1698 case 1:
1699 result = 2; /* Normal auto mode */
1700 break;
1701 case 2:
1702 result = 1; /* Manual mode */
1703 break;
1704 case 3:
1705 if (data->type == f8000)
1706 result = 3; /* Thermostat mode */
1707 else
1708 result = 1; /* Manual mode */
1709 break;
1710 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001711
1712 return sprintf(buf, "%d\n", result);
1713}
1714
1715static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1716 *devattr, const char *buf, size_t count)
1717{
1718 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001719 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1720 long val;
1721
1722 err = strict_strtol(buf, 10, &val);
1723 if (err)
1724 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001725
Hans de Goede3fc78382009-06-15 18:39:50 +02001726 /* Special case for F8000 pwm channel 3 which only does auto mode */
1727 if (data->type == f8000 && nr == 2 && val != 2)
1728 return -EINVAL;
1729
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001730 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001731 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001732 /* Special case for F8000 auto PWM mode / Thermostat mode */
1733 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1734 switch (val) {
1735 case 2:
1736 data->pwm_enable &= ~(2 << (2 * nr));
1737 break; /* Normal auto mode */
1738 case 3:
1739 data->pwm_enable |= 2 << (2 * nr);
1740 break; /* Thermostat mode */
1741 default:
1742 count = -EINVAL;
1743 goto leave;
1744 }
1745 } else {
1746 switch (val) {
1747 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001748 /* The f71858fg does not support manual RPM mode */
1749 if (data->type == f71858fg &&
1750 ((data->pwm_enable >> (2 * nr)) & 1)) {
1751 count = -EINVAL;
1752 goto leave;
1753 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001754 data->pwm_enable |= 2 << (2 * nr);
1755 break; /* Manual */
1756 case 2:
1757 data->pwm_enable &= ~(2 << (2 * nr));
1758 break; /* Normal auto mode */
1759 default:
1760 count = -EINVAL;
1761 goto leave;
1762 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001763 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001764 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001765leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001766 mutex_unlock(&data->update_lock);
1767
1768 return count;
1769}
1770
1771static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1772 struct device_attribute *devattr,
1773 char *buf)
1774{
1775 int result;
1776 struct f71882fg_data *data = f71882fg_update_device(dev);
1777 int pwm = to_sensor_dev_attr_2(devattr)->index;
1778 int point = to_sensor_dev_attr_2(devattr)->nr;
1779
Hans de Goedece0bfa52009-01-07 16:37:28 +01001780 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001781 if (data->pwm_enable & (1 << (2 * pwm))) {
1782 /* PWM mode */
1783 result = data->pwm_auto_point_pwm[pwm][point];
1784 } else {
1785 /* RPM mode */
1786 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1787 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001788 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001789
1790 return sprintf(buf, "%d\n", result);
1791}
1792
1793static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1794 struct device_attribute *devattr,
1795 const char *buf, size_t count)
1796{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001797 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001798 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001799 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001800 long val;
1801
1802 err = strict_strtol(buf, 10, &val);
1803 if (err)
1804 return err;
1805
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001806 val = SENSORS_LIMIT(val, 0, 255);
1807
1808 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001809 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001810 if (data->pwm_enable & (1 << (2 * pwm))) {
1811 /* PWM mode */
1812 } else {
1813 /* RPM mode */
1814 if (val < 29) /* Prevent negative numbers */
1815 val = 255;
1816 else
1817 val = (255 - val) * 32 / val;
1818 }
1819 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1820 data->pwm_auto_point_pwm[pwm][point] = val;
1821 mutex_unlock(&data->update_lock);
1822
1823 return count;
1824}
1825
1826static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1827 struct device_attribute *devattr,
1828 char *buf)
1829{
1830 int result = 0;
1831 struct f71882fg_data *data = f71882fg_update_device(dev);
1832 int nr = to_sensor_dev_attr_2(devattr)->index;
1833 int point = to_sensor_dev_attr_2(devattr)->nr;
1834
1835 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001836 if (nr & 1)
1837 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1838 else
1839 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001840 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1841 mutex_unlock(&data->update_lock);
1842
1843 return sprintf(buf, "%d\n", result);
1844}
1845
1846static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1847 struct device_attribute *devattr,
1848 const char *buf, size_t count)
1849{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001850 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001851 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001852 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001853 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001854 long val;
1855
1856 err = strict_strtol(buf, 10, &val);
1857 if (err)
1858 return err;
1859
1860 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001861
1862 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001863 data->pwm_auto_point_temp[nr][point] =
1864 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001865 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1866 data->pwm_auto_point_temp[nr][point]);
1867 val = data->pwm_auto_point_temp[nr][point] - val;
1868
Hans de Goedebc274902009-01-07 16:37:29 +01001869 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1870 if (nr & 1)
1871 reg = (reg & 0x0f) | (val << 4);
1872 else
1873 reg = (reg & 0xf0) | val;
1874
1875 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1876 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001877 mutex_unlock(&data->update_lock);
1878
1879 return count;
1880}
1881
1882static ssize_t show_pwm_interpolate(struct device *dev,
1883 struct device_attribute *devattr, char *buf)
1884{
1885 int result;
1886 struct f71882fg_data *data = f71882fg_update_device(dev);
1887 int nr = to_sensor_dev_attr_2(devattr)->index;
1888
1889 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1890
1891 return sprintf(buf, "%d\n", result);
1892}
1893
1894static ssize_t store_pwm_interpolate(struct device *dev,
1895 struct device_attribute *devattr,
1896 const char *buf, size_t count)
1897{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001898 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001899 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1900 unsigned long val;
1901
1902 err = strict_strtoul(buf, 10, &val);
1903 if (err)
1904 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001905
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001906 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001907 data->pwm_auto_point_mapping[nr] =
1908 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001909 if (val)
1910 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1911 else
1912 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1913 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1914 data->pwm_auto_point_mapping[nr] = val;
1915 mutex_unlock(&data->update_lock);
1916
1917 return count;
1918}
1919
1920static ssize_t show_pwm_auto_point_channel(struct device *dev,
1921 struct device_attribute *devattr,
1922 char *buf)
1923{
1924 int result;
1925 struct f71882fg_data *data = f71882fg_update_device(dev);
1926 int nr = to_sensor_dev_attr_2(devattr)->index;
1927
Hans de Goede09475d32009-06-15 18:39:52 +02001928 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1929 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001930
1931 return sprintf(buf, "%d\n", result);
1932}
1933
1934static ssize_t store_pwm_auto_point_channel(struct device *dev,
1935 struct device_attribute *devattr,
1936 const char *buf, size_t count)
1937{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001938 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001939 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1940 long val;
1941
1942 err = strict_strtol(buf, 10, &val);
1943 if (err)
1944 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001945
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001946 switch (val) {
1947 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001948 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001949 break;
1950 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001951 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001952 break;
1953 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001954 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001955 break;
1956 default:
1957 return -EINVAL;
1958 }
Hans de Goede09475d32009-06-15 18:39:52 +02001959 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001960 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001961 data->pwm_auto_point_mapping[nr] =
1962 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001963 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1964 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1965 data->pwm_auto_point_mapping[nr] = val;
1966 mutex_unlock(&data->update_lock);
1967
1968 return count;
1969}
1970
1971static ssize_t show_pwm_auto_point_temp(struct device *dev,
1972 struct device_attribute *devattr,
1973 char *buf)
1974{
1975 int result;
1976 struct f71882fg_data *data = f71882fg_update_device(dev);
1977 int pwm = to_sensor_dev_attr_2(devattr)->index;
1978 int point = to_sensor_dev_attr_2(devattr)->nr;
1979
1980 result = data->pwm_auto_point_temp[pwm][point];
1981 return sprintf(buf, "%d\n", 1000 * result);
1982}
1983
1984static ssize_t store_pwm_auto_point_temp(struct device *dev,
1985 struct device_attribute *devattr,
1986 const char *buf, size_t count)
1987{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001988 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001989 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001990 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001991 long val;
1992
1993 err = strict_strtol(buf, 10, &val);
1994 if (err)
1995 return err;
1996
1997 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001998
Hans de Goede98f7ba12011-03-09 20:57:09 +01001999 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01002000 val = SENSORS_LIMIT(val, -128, 127);
2001 else
2002 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002003
2004 mutex_lock(&data->update_lock);
2005 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2006 data->pwm_auto_point_temp[pwm][point] = val;
2007 mutex_unlock(&data->update_lock);
2008
2009 return count;
2010}
2011
Hans de Goede45fb3662007-07-13 14:34:19 +02002012static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2013 char *buf)
2014{
Hans de Goede498be962009-01-07 16:37:28 +01002015 struct f71882fg_data *data = dev_get_drvdata(dev);
2016 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002017}
2018
Hans de Goedec13548c2009-01-07 16:37:27 +01002019static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
2020 struct sensor_device_attribute_2 *attr, int count)
2021{
2022 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002023
Hans de Goedec13548c2009-01-07 16:37:27 +01002024 for (i = 0; i < count; i++) {
2025 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2026 if (err)
2027 return err;
2028 }
2029 return 0;
2030}
2031
Hans de Goedefc16c562009-12-09 20:36:01 +01002032static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2033 struct sensor_device_attribute_2 *attr, int count)
2034{
2035 int i;
2036
2037 for (i = 0; i < count; i++)
2038 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2039}
2040
Hans de Goedec13548c2009-01-07 16:37:27 +01002041static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002042{
2043 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01002044 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01002045 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002046 int nr_temps = (sio_data->type == f71808e) ? 2 : 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002047 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002048
Hans de Goedec13548c2009-01-07 16:37:27 +01002049 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
2050 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002051 return -ENOMEM;
2052
2053 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002054 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002055 data->temp_start =
2056 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002057 mutex_init(&data->update_lock);
2058 platform_set_drvdata(pdev, data);
2059
Hans de Goede3cc74752009-01-07 16:37:28 +01002060 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002061 if (start_reg & 0x04) {
2062 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
2063 err = -ENODEV;
2064 goto exit_free;
2065 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002066 if (!(start_reg & 0x03)) {
2067 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
2068 err = -ENODEV;
2069 goto exit_free;
2070 }
2071
Hans de Goede45fb3662007-07-13 14:34:19 +02002072 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002073 err = device_create_file(&pdev->dev, &dev_attr_name);
2074 if (err)
2075 goto exit_unregister_sysfs;
2076
Hans de Goedec13548c2009-01-07 16:37:27 +01002077 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002078 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002079 case f71858fg:
2080 data->temp_config =
2081 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2082 if (data->temp_config & 0x10)
2083 /* The f71858fg temperature alarms behave as
2084 the f8000 alarms in this mode */
2085 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002086 f8000_temp_attr,
2087 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002088 else
2089 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002090 f71858fg_temp_attr,
2091 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002092 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002093 case f8000:
2094 err = f71882fg_create_sysfs_files(pdev,
2095 f8000_temp_attr,
2096 ARRAY_SIZE(f8000_temp_attr));
2097 break;
2098 default:
2099 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002100 &fxxxx_temp_attr[0][0],
2101 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002102 }
2103 if (err)
2104 goto exit_unregister_sysfs;
2105
Hans de Goede78aa4f72011-03-09 20:57:12 +01002106 if (f71882fg_has_beep[data->type]) {
2107 err = f71882fg_create_sysfs_files(pdev,
2108 &fxxxx_temp_beep_attr[0][0],
2109 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2110 * nr_temps);
2111 if (err)
2112 goto exit_unregister_sysfs;
2113 }
2114
Hans de Goede0bae6402011-03-09 20:57:10 +01002115 for (i = 0; i < F71882FG_MAX_INS; i++) {
2116 if (f71882fg_has_in[data->type][i]) {
2117 err = device_create_file(&pdev->dev,
2118 &fxxxx_in_attr[i].dev_attr);
2119 if (err)
2120 goto exit_unregister_sysfs;
2121 }
2122 }
2123 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002124 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002125 fxxxx_in1_alarm_attr,
2126 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002127 if (err)
2128 goto exit_unregister_sysfs;
2129 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002130 }
2131
Hans de Goede45fb3662007-07-13 14:34:19 +02002132 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002133 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002134 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002135 case f71869:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002136 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002137 data->auto_point_temp_signed = 1;
2138 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002139 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002140 case f71889ed:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002141 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2142 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2143 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002144 /* Ensure banked pwm registers point to right bank */
2145 reg &= ~F71882FG_FAN_PROG_SEL;
2146 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002147 break;
2148 default:
2149 break;
2150 }
2151
Hans de Goede996cadb2009-06-15 18:39:51 +02002152 data->pwm_enable =
2153 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2154
2155 /* Sanity check the pwm settings */
2156 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002157 case f71858fg:
2158 err = 0;
2159 for (i = 0; i < nr_fans; i++)
2160 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2161 err = 1;
2162 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002163 case f71862fg:
2164 err = (data->pwm_enable & 0x15) != 0x15;
2165 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002166 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002167 case f71869:
Hans de Goede996cadb2009-06-15 18:39:51 +02002168 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002169 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002170 case f71889ed:
Hans de Goede996cadb2009-06-15 18:39:51 +02002171 err = 0;
2172 break;
2173 case f8000:
2174 err = data->pwm_enable & 0x20;
2175 break;
2176 }
2177 if (err) {
2178 dev_err(&pdev->dev,
2179 "Invalid (reserved) pwm settings: 0x%02x\n",
2180 (unsigned int)data->pwm_enable);
2181 err = -ENODEV;
2182 goto exit_unregister_sysfs;
2183 }
2184
Hans de Goedeb69b0392009-12-09 20:36:00 +01002185 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2186 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002187 if (err)
2188 goto exit_unregister_sysfs;
2189
Hans de Goede78aa4f72011-03-09 20:57:12 +01002190 if (f71882fg_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002191 err = f71882fg_create_sysfs_files(pdev,
2192 fxxxx_fan_beep_attr, nr_fans);
2193 if (err)
2194 goto exit_unregister_sysfs;
2195 }
2196
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002197 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002198 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002199 case f71869:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002200 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002201 case f71889ed:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002202 for (i = 0; i < nr_fans; i++) {
2203 data->pwm_auto_point_mapping[i] =
2204 f71882fg_read8(data,
2205 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002206 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2207 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002208 break;
2209 }
2210 if (i != nr_fans) {
2211 dev_warn(&pdev->dev,
2212 "Auto pwm controlled by raw digital "
2213 "data, disabling pwm auto_point "
2214 "sysfs attributes\n");
2215 goto no_pwm_auto_point;
2216 }
2217 break;
2218 default:
2219 break;
2220 }
2221
2222 switch (data->type) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002223 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002224 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002225 f71862fg_auto_pwm_attr,
2226 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002227 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002228 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002229 case f71869:
2230 err = f71882fg_create_sysfs_files(pdev,
2231 f71869_auto_pwm_attr,
2232 ARRAY_SIZE(f71869_auto_pwm_attr));
2233 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002234 case f8000:
2235 err = f71882fg_create_sysfs_files(pdev,
2236 f8000_fan_attr,
2237 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002238 if (err)
2239 goto exit_unregister_sysfs;
2240 err = f71882fg_create_sysfs_files(pdev,
2241 f8000_auto_pwm_attr,
2242 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002243 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002244 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002245 err = f71882fg_create_sysfs_files(pdev,
2246 &fxxxx_auto_pwm_attr[0][0],
2247 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002248 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002249 if (err)
2250 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002251
Hans de Goedee48a7f12011-03-09 20:57:13 +01002252no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002253 for (i = 0; i < nr_fans; i++)
2254 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2255 (data->pwm_enable & (1 << 2 * i)) ?
2256 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002257 }
2258
Tony Jones1beeffe2007-08-20 13:46:20 -07002259 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2260 if (IS_ERR(data->hwmon_dev)) {
2261 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002262 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002263 goto exit_unregister_sysfs;
2264 }
2265
2266 return 0;
2267
2268exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002269 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002270 return err; /* f71882fg_remove() also frees our data */
2271exit_free:
2272 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002273 return err;
2274}
2275
Hans de Goedec13548c2009-01-07 16:37:27 +01002276static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002277{
Hans de Goede45fb3662007-07-13 14:34:19 +02002278 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002279 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002280 int nr_temps = (data->type == f71808e) ? 2 : 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002281 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002282
Hans de Goedec13548c2009-01-07 16:37:27 +01002283 if (data->hwmon_dev)
2284 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002285
Hans de Goedec13548c2009-01-07 16:37:27 +01002286 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002287
Hans de Goedefc16c562009-12-09 20:36:01 +01002288 if (start_reg & 0x01) {
2289 switch (data->type) {
2290 case f71858fg:
2291 if (data->temp_config & 0x10)
2292 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002293 f8000_temp_attr,
2294 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002295 else
2296 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002297 f71858fg_temp_attr,
2298 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002299 break;
2300 case f8000:
2301 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002302 f8000_temp_attr,
2303 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002304 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002305 default:
2306 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002307 &fxxxx_temp_attr[0][0],
2308 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002309 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002310 if (f71882fg_has_beep[data->type]) {
2311 f71882fg_remove_sysfs_files(pdev,
2312 &fxxxx_temp_beep_attr[0][0],
2313 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2314 }
2315
Hans de Goede0bae6402011-03-09 20:57:10 +01002316 for (i = 0; i < F71882FG_MAX_INS; i++) {
2317 if (f71882fg_has_in[data->type][i]) {
2318 device_remove_file(&pdev->dev,
2319 &fxxxx_in_attr[i].dev_attr);
2320 }
2321 }
2322 if (f71882fg_has_in1_alarm[data->type]) {
2323 f71882fg_remove_sysfs_files(pdev,
2324 fxxxx_in1_alarm_attr,
2325 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002326 }
2327 }
Hans de Goede498be962009-01-07 16:37:28 +01002328
Hans de Goedefc16c562009-12-09 20:36:01 +01002329 if (start_reg & 0x02) {
2330 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2331 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002332
Hans de Goede78aa4f72011-03-09 20:57:12 +01002333 if (f71882fg_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002334 f71882fg_remove_sysfs_files(pdev,
2335 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002336 }
Hans de Goede498be962009-01-07 16:37:28 +01002337
Hans de Goedefc16c562009-12-09 20:36:01 +01002338 switch (data->type) {
2339 case f71862fg:
2340 f71882fg_remove_sysfs_files(pdev,
2341 f71862fg_auto_pwm_attr,
2342 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2343 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002344 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002345 case f71869:
2346 f71882fg_remove_sysfs_files(pdev,
2347 f71869_auto_pwm_attr,
2348 ARRAY_SIZE(f71869_auto_pwm_attr));
2349 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002350 case f8000:
2351 f71882fg_remove_sysfs_files(pdev,
2352 f8000_fan_attr,
2353 ARRAY_SIZE(f8000_fan_attr));
2354 f71882fg_remove_sysfs_files(pdev,
2355 f8000_auto_pwm_attr,
2356 ARRAY_SIZE(f8000_auto_pwm_attr));
2357 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002358 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002359 f71882fg_remove_sysfs_files(pdev,
2360 &fxxxx_auto_pwm_attr[0][0],
2361 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2362 }
2363 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002364
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002365 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002366 kfree(data);
2367
2368 return 0;
2369}
2370
Hans de Goede498be962009-01-07 16:37:28 +01002371static int __init f71882fg_find(int sioaddr, unsigned short *address,
2372 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002373{
Hans de Goede45fb3662007-07-13 14:34:19 +02002374 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002375 int err = superio_enter(sioaddr);
2376 if (err)
2377 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002378
2379 devid = superio_inw(sioaddr, SIO_REG_MANID);
2380 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002381 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002382 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002383 goto exit;
2384 }
2385
Jean Delvare67b671b2007-12-06 23:13:42 +01002386 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002387 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002388 case SIO_F71808E_ID:
2389 sio_data->type = f71808e;
2390 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002391 case SIO_F71858_ID:
2392 sio_data->type = f71858fg;
2393 break;
Hans de Goede498be962009-01-07 16:37:28 +01002394 case SIO_F71862_ID:
2395 sio_data->type = f71862fg;
2396 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002397 case SIO_F71869_ID:
2398 sio_data->type = f71869;
2399 break;
Hans de Goede498be962009-01-07 16:37:28 +01002400 case SIO_F71882_ID:
2401 sio_data->type = f71882fg;
2402 break;
Hans de Goede76698962009-12-09 20:36:01 +01002403 case SIO_F71889_ID:
2404 sio_data->type = f71889fg;
2405 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002406 case SIO_F71889E_ID:
2407 sio_data->type = f71889ed;
2408 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002409 case SIO_F8000_ID:
2410 sio_data->type = f8000;
2411 break;
Hans de Goede498be962009-01-07 16:37:28 +01002412 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002413 pr_info("Unsupported Fintek device: %04x\n",
2414 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002415 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002416 goto exit;
2417 }
2418
Hans de Goede09475d32009-06-15 18:39:52 +02002419 if (sio_data->type == f71858fg)
2420 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2421 else
2422 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2423
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002424 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002425 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002426 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002427 goto exit;
2428 }
2429
2430 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002431 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002432 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002433 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002434 goto exit;
2435 }
2436 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2437
Hans de Goede45fb3662007-07-13 14:34:19 +02002438 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002439 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002440 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002441 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2442exit:
2443 superio_exit(sioaddr);
2444 return err;
2445}
2446
Hans de Goede498be962009-01-07 16:37:28 +01002447static int __init f71882fg_device_add(unsigned short address,
2448 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002449{
2450 struct resource res = {
2451 .start = address,
2452 .end = address + REGION_LENGTH - 1,
2453 .flags = IORESOURCE_IO,
2454 };
2455 int err;
2456
2457 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002458 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002459 return -ENOMEM;
2460
2461 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002462 err = acpi_check_resource_conflict(&res);
2463 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002464 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002465
Hans de Goede45fb3662007-07-13 14:34:19 +02002466 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002467 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002468 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002469 goto exit_device_put;
2470 }
2471
Hans de Goede498be962009-01-07 16:37:28 +01002472 err = platform_device_add_data(f71882fg_pdev, sio_data,
2473 sizeof(struct f71882fg_sio_data));
2474 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002475 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002476 goto exit_device_put;
2477 }
2478
Hans de Goede45fb3662007-07-13 14:34:19 +02002479 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002480 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002481 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002482 goto exit_device_put;
2483 }
2484
2485 return 0;
2486
2487exit_device_put:
2488 platform_device_put(f71882fg_pdev);
2489
2490 return err;
2491}
2492
2493static int __init f71882fg_init(void)
2494{
2495 int err = -ENODEV;
2496 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002497 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002498
Hans de Goede498be962009-01-07 16:37:28 +01002499 memset(&sio_data, 0, sizeof(sio_data));
2500
2501 if (f71882fg_find(0x2e, &address, &sio_data) &&
2502 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002503 goto exit;
2504
Hans de Goedec13548c2009-01-07 16:37:27 +01002505 err = platform_driver_register(&f71882fg_driver);
2506 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002507 goto exit;
2508
Hans de Goede498be962009-01-07 16:37:28 +01002509 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002510 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002511 goto exit_driver;
2512
2513 return 0;
2514
2515exit_driver:
2516 platform_driver_unregister(&f71882fg_driver);
2517exit:
2518 return err;
2519}
2520
2521static void __exit f71882fg_exit(void)
2522{
2523 platform_device_unregister(f71882fg_pdev);
2524 platform_driver_unregister(&f71882fg_driver);
2525}
2526
2527MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002528MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002529MODULE_LICENSE("GPL");
2530
2531module_init(f71882fg_init);
2532module_exit(f71882fg_exit);