blob: 29879046fe53e2f76d81cc08579ae2728ff6f3bd [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",
Jean Delvare5d7f77b2011-03-26 10:45:02 +0100117 "f71889fg", /* f81801u too, same id */
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
Jean Delvaref27def02011-03-26 10:45:01 +0100155static const char f71882fg_nr_fans[] = {
156 [f71808e] = 3,
157 [f71858fg] = 3,
158 [f71862fg] = 3,
159 [f71869] = 3,
160 [f71882fg] = 4,
161 [f71889fg] = 3,
162 [f71889ed] = 3,
163 [f8000] = 3,
164};
165
166static const char f71882fg_nr_temps[] = {
167 [f71808e] = 2,
168 [f71858fg] = 3,
169 [f71862fg] = 3,
170 [f71869] = 3,
171 [f71882fg] = 3,
172 [f71889fg] = 3,
173 [f71889ed] = 3,
174 [f8000] = 3,
175};
176
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100177static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200178
179/* Super-I/O Function prototypes */
180static inline int superio_inb(int base, int reg);
181static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400182static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200183static inline void superio_select(int base, int ld);
184static inline void superio_exit(int base);
185
Hans de Goede498be962009-01-07 16:37:28 +0100186struct f71882fg_sio_data {
187 enum chips type;
188};
189
Hans de Goede45fb3662007-07-13 14:34:19 +0200190struct f71882fg_data {
191 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100192 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700193 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200194
195 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200196 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200197 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100198 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200199 unsigned long last_updated; /* In jiffies */
200 unsigned long last_limits; /* In jiffies */
201
202 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100203 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200204 u8 in1_max;
205 u8 in_status;
206 u8 in_beep;
207 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100208 u16 fan_target[4];
209 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200210 u8 fan_status;
211 u8 fan_beep;
Hans de Goedee5e713c2011-03-10 08:54:02 +0100212 /* Note: all models have max 3 temperature channels, but on some
Hans de Goede7567a042009-01-07 16:37:28 +0100213 they are addressed as 0-2 and on others as 1-3, so for coding
214 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200215 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100216 u8 temp_ovt[4];
217 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100218 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100219 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200220 u8 temp_status;
221 u8 temp_beep;
222 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200223 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100224 u8 pwm[4];
225 u8 pwm_enable;
226 u8 pwm_auto_point_hyst[2];
227 u8 pwm_auto_point_mapping[4];
228 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100229 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200230};
231
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100232/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200233static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
234 char *buf);
235static ssize_t show_in_max(struct device *dev, struct device_attribute
236 *devattr, char *buf);
237static ssize_t store_in_max(struct device *dev, struct device_attribute
238 *devattr, const char *buf, size_t count);
239static ssize_t show_in_beep(struct device *dev, struct device_attribute
240 *devattr, char *buf);
241static ssize_t store_in_beep(struct device *dev, struct device_attribute
242 *devattr, const char *buf, size_t count);
243static ssize_t show_in_alarm(struct device *dev, struct device_attribute
244 *devattr, char *buf);
245/* Sysfs Fan */
246static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
247 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100248static ssize_t show_fan_full_speed(struct device *dev,
249 struct device_attribute *devattr, char *buf);
250static ssize_t store_fan_full_speed(struct device *dev,
251 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200252static ssize_t show_fan_beep(struct device *dev, struct device_attribute
253 *devattr, char *buf);
254static ssize_t store_fan_beep(struct device *dev, struct device_attribute
255 *devattr, const char *buf, size_t count);
256static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
257 *devattr, char *buf);
258/* Sysfs Temp */
259static ssize_t show_temp(struct device *dev, struct device_attribute
260 *devattr, char *buf);
261static ssize_t show_temp_max(struct device *dev, struct device_attribute
262 *devattr, char *buf);
263static ssize_t store_temp_max(struct device *dev, struct device_attribute
264 *devattr, const char *buf, size_t count);
265static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
266 *devattr, char *buf);
267static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
268 *devattr, const char *buf, size_t count);
269static ssize_t show_temp_crit(struct device *dev, struct device_attribute
270 *devattr, char *buf);
271static ssize_t store_temp_crit(struct device *dev, struct device_attribute
272 *devattr, const char *buf, size_t count);
273static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
274 *devattr, char *buf);
275static ssize_t show_temp_type(struct device *dev, struct device_attribute
276 *devattr, char *buf);
277static ssize_t show_temp_beep(struct device *dev, struct device_attribute
278 *devattr, char *buf);
279static ssize_t store_temp_beep(struct device *dev, struct device_attribute
280 *devattr, const char *buf, size_t count);
281static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
282 *devattr, char *buf);
283static ssize_t show_temp_fault(struct device *dev, struct device_attribute
284 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100285/* PWM and Auto point control */
286static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
287 char *buf);
288static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
289 const char *buf, size_t count);
290static ssize_t show_pwm_enable(struct device *dev,
291 struct device_attribute *devattr, char *buf);
292static ssize_t store_pwm_enable(struct device *dev,
293 struct device_attribute *devattr, const char *buf, size_t count);
294static ssize_t show_pwm_interpolate(struct device *dev,
295 struct device_attribute *devattr, char *buf);
296static ssize_t store_pwm_interpolate(struct device *dev,
297 struct device_attribute *devattr, const char *buf, size_t count);
298static ssize_t show_pwm_auto_point_channel(struct device *dev,
299 struct device_attribute *devattr, char *buf);
300static ssize_t store_pwm_auto_point_channel(struct device *dev,
301 struct device_attribute *devattr, const char *buf, size_t count);
302static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
303 struct device_attribute *devattr, char *buf);
304static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
305 struct device_attribute *devattr, const char *buf, size_t count);
306static ssize_t show_pwm_auto_point_pwm(struct device *dev,
307 struct device_attribute *devattr, char *buf);
308static ssize_t store_pwm_auto_point_pwm(struct device *dev,
309 struct device_attribute *devattr, const char *buf, size_t count);
310static ssize_t show_pwm_auto_point_temp(struct device *dev,
311 struct device_attribute *devattr, char *buf);
312static ssize_t store_pwm_auto_point_temp(struct device *dev,
313 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200314/* Sysfs misc */
315static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
316 char *buf);
317
318static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100319static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200320
321static struct platform_driver f71882fg_driver = {
322 .driver = {
323 .owner = THIS_MODULE,
324 .name = DRVNAME,
325 },
326 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200327 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200328};
329
Hans de Goedec13548c2009-01-07 16:37:27 +0100330static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200331
Hans de Goede0bae6402011-03-09 20:57:10 +0100332/* Temp attr for the f71858fg, the f71858fg is special as it has its
333 temperature indexes start at 0 (the others start at 1) */
334static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200335 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
336 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
337 store_temp_max, 0, 0),
338 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
339 store_temp_max_hyst, 0, 0),
340 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
341 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
342 store_temp_crit, 0, 0),
343 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
344 0, 0),
345 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
346 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
347 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
348 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
349 store_temp_max, 0, 1),
350 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
351 store_temp_max_hyst, 0, 1),
352 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
353 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
354 store_temp_crit, 0, 1),
355 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
356 0, 1),
357 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200358 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
359 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
360 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
361 store_temp_max, 0, 2),
362 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
363 store_temp_max_hyst, 0, 2),
364 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
365 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
366 store_temp_crit, 0, 2),
367 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
368 0, 2),
369 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
370 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
371};
372
Hans de Goede0bae6402011-03-09 20:57:10 +0100373/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100374static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100376 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100377 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100378 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100379 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100380 /* Should really be temp1_max_alarm, but older versions did not handle
381 the max and crit alarms separately and lm_sensors v2 depends on the
382 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
383 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100384 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100385 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100386 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100387 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100388 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100389 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100390 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100391}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100392 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
393 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100394 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100395 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100396 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100397 /* Should be temp2_max_alarm, see temp1_alarm note */
398 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100399 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100400 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100401 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100402 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100403 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100404 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100405 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100406}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100407 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
408 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
409 store_temp_max, 0, 3),
410 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
411 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100412 /* Should be temp3_max_alarm, see temp1_alarm note */
413 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100414 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
415 store_temp_crit, 0, 3),
416 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
417 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100418 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100419 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100420 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100421} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200422
Hans de Goede78aa4f72011-03-09 20:57:12 +0100423/* Temp attr for models which can beep on temp alarm */
424static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
425 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
426 store_temp_beep, 0, 1),
427 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
428 store_temp_beep, 0, 5),
429}, {
430 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
431 store_temp_beep, 0, 2),
432 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
433 store_temp_beep, 0, 6),
434}, {
435 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
436 store_temp_beep, 0, 3),
437 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
438 store_temp_beep, 0, 7),
439} };
440
Hans de Goede0bae6402011-03-09 20:57:10 +0100441/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100442 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
443 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100444 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100445 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100446static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100447 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
448 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
449 store_temp_crit, 0, 0),
450 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
451 store_temp_max, 0, 0),
452 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200453 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100454 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
455 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
456 store_temp_crit, 0, 1),
457 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
458 store_temp_max, 0, 1),
459 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200460 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100461 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
462 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
463 store_temp_crit, 0, 2),
464 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
465 store_temp_max, 0, 2),
466 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200467 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100468};
469
Hans de Goede0bae6402011-03-09 20:57:10 +0100470/* in attr for all models */
471static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
472 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
473 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
474 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
475 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
476 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
477 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
478 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
479 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
480 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
481};
482
483/* For models with in1 alarm capability */
484static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
485 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
486 0, 1),
487 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
488 0, 1),
489 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
490};
491
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100492/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100493static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100494 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100495 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
496 show_fan_full_speed,
497 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100498 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100499 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
500 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
501 store_pwm_enable, 0, 0),
502 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
503 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100504}, {
505 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
506 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
507 show_fan_full_speed,
508 store_fan_full_speed, 0, 1),
509 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100510 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
511 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
512 store_pwm_enable, 0, 1),
513 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
514 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100515}, {
516 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
517 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
518 show_fan_full_speed,
519 store_fan_full_speed, 0, 2),
520 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200521 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
522 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
523 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100524 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
525 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100526}, {
527 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
528 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
529 show_fan_full_speed,
530 store_fan_full_speed, 0, 3),
531 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
532 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
533 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
534 store_pwm_enable, 0, 3),
535 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
536 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
537} };
Hans de Goede498be962009-01-07 16:37:28 +0100538
Hans de Goede66344aa2009-12-09 20:35:59 +0100539/* Attr for models which can beep on Fan alarm */
540static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100541 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
542 store_fan_beep, 0, 0),
543 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
544 store_fan_beep, 0, 1),
545 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
546 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100547 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
548 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100549};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100550
Hans de Goede66344aa2009-12-09 20:35:59 +0100551/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100552 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100553static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
554 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_channel,
556 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100557 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
559 1, 0),
560 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
562 4, 0),
563 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
565 0, 0),
566 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
567 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
568 3, 0),
569 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_temp_hyst,
571 store_pwm_auto_point_temp_hyst,
572 0, 0),
573 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
574 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
575
Hans de Goede66344aa2009-12-09 20:35:59 +0100576 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_channel,
578 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100579 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
581 1, 1),
582 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
584 4, 1),
585 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
587 0, 1),
588 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
589 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
590 3, 1),
591 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
592 show_pwm_auto_point_temp_hyst,
593 store_pwm_auto_point_temp_hyst,
594 0, 1),
595 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
596 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100597
Hans de Goede66344aa2009-12-09 20:35:59 +0100598 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
599 show_pwm_auto_point_channel,
600 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100601 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
602 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
603 1, 2),
604 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
605 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
606 4, 2),
607 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
609 0, 2),
610 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
612 3, 2),
613 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_temp_hyst,
615 store_pwm_auto_point_temp_hyst,
616 0, 2),
617 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
618 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100619};
620
Hans de Goedee5e713c2011-03-10 08:54:02 +0100621/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
Hans de Goedec11bb992011-03-09 20:57:15 +0100622 pwm setting when the temperature is above the pwmX_auto_point1_temp can be
623 programmed instead of being hardcoded to 0xff */
624static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
625 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_channel,
627 store_pwm_auto_point_channel, 0, 0),
628 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 0, 0),
631 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
633 1, 0),
634 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 4, 0),
637 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
639 0, 0),
640 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 3, 0),
643 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp_hyst,
645 store_pwm_auto_point_temp_hyst,
646 0, 0),
647 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
648 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
649
650 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
651 show_pwm_auto_point_channel,
652 store_pwm_auto_point_channel, 0, 1),
653 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
654 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
655 0, 1),
656 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
658 1, 1),
659 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
661 4, 1),
662 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
664 0, 1),
665 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
667 3, 1),
668 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_temp_hyst,
670 store_pwm_auto_point_temp_hyst,
671 0, 1),
672 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
673 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
674
675 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_channel,
677 store_pwm_auto_point_channel, 0, 2),
678 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 0, 2),
681 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 1, 2),
684 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 4, 2),
687 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
689 0, 2),
690 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
692 3, 2),
693 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp_hyst,
695 store_pwm_auto_point_temp_hyst,
696 0, 2),
697 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
698 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
699};
700
Hans de Goede3cad4022011-03-09 20:57:14 +0100701/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100702static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100703 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_channel,
705 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100706 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
708 0, 0),
709 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
710 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
711 1, 0),
712 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
713 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
714 2, 0),
715 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
716 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
717 3, 0),
718 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
719 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
720 4, 0),
721 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
722 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
723 0, 0),
724 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
725 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
726 1, 0),
727 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
728 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
729 2, 0),
730 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
731 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
732 3, 0),
733 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
734 show_pwm_auto_point_temp_hyst,
735 store_pwm_auto_point_temp_hyst,
736 0, 0),
737 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
738 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
739 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
740 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
741 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
742 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100743}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100744 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_channel,
746 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100747 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
749 0, 1),
750 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
752 1, 1),
753 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
755 2, 1),
756 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
758 3, 1),
759 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
761 4, 1),
762 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
764 0, 1),
765 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
766 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
767 1, 1),
768 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
770 2, 1),
771 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
773 3, 1),
774 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_temp_hyst,
776 store_pwm_auto_point_temp_hyst,
777 0, 1),
778 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
779 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
780 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
781 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
782 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
783 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100784}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100785 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_channel,
787 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100788 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
790 0, 2),
791 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
793 1, 2),
794 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
796 2, 2),
797 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
799 3, 2),
800 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
802 4, 2),
803 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
804 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
805 0, 2),
806 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
807 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
808 1, 2),
809 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
811 2, 2),
812 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
814 3, 2),
815 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_temp_hyst,
817 store_pwm_auto_point_temp_hyst,
818 0, 2),
819 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
820 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
821 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
822 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
823 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
824 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100825}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100826 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_channel,
828 store_pwm_auto_point_channel, 0, 3),
829 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
831 0, 3),
832 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
834 1, 3),
835 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
837 2, 3),
838 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
840 3, 3),
841 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
843 4, 3),
844 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
845 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
846 0, 3),
847 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
848 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
849 1, 3),
850 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
851 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
852 2, 3),
853 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
854 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
855 3, 3),
856 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
857 show_pwm_auto_point_temp_hyst,
858 store_pwm_auto_point_temp_hyst,
859 0, 3),
860 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
861 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
862 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
863 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
864 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
865 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100866} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200867
Hans de Goede66344aa2009-12-09 20:35:59 +0100868/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100869static struct sensor_device_attribute_2 f8000_fan_attr[] = {
870 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100871};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100872
Hans de Goede66344aa2009-12-09 20:35:59 +0100873/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
874 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
875 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
876static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
877 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
878 show_pwm_auto_point_channel,
879 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100880 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
881 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
882 0, 2),
883 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
884 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
885 1, 2),
886 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
887 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
888 2, 2),
889 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
890 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
891 3, 2),
892 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
893 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
894 4, 2),
895 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
896 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
897 0, 2),
898 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
899 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
900 1, 2),
901 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
902 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
903 2, 2),
904 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
905 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
906 3, 2),
907 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
908 show_pwm_auto_point_temp_hyst,
909 store_pwm_auto_point_temp_hyst,
910 0, 2),
911 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
912 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
913 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
914 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
915 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
916 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
917
Hans de Goede66344aa2009-12-09 20:35:59 +0100918 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
919 show_pwm_auto_point_channel,
920 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100921 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
922 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
923 0, 0),
924 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
925 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
926 1, 0),
927 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
928 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
929 2, 0),
930 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
931 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
932 3, 0),
933 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
934 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
935 4, 0),
936 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
937 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
938 0, 0),
939 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
940 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
941 1, 0),
942 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
943 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
944 2, 0),
945 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
946 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
947 3, 0),
948 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
949 show_pwm_auto_point_temp_hyst,
950 store_pwm_auto_point_temp_hyst,
951 0, 0),
952 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
953 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
954 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
955 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
956 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
957 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
958
Hans de Goede66344aa2009-12-09 20:35:59 +0100959 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
960 show_pwm_auto_point_channel,
961 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100962 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
963 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
964 0, 1),
965 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
966 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
967 1, 1),
968 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
969 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
970 2, 1),
971 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
972 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
973 3, 1),
974 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
975 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
976 4, 1),
977 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
978 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
979 0, 1),
980 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
981 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
982 1, 1),
983 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
984 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
985 2, 1),
986 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
987 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
988 3, 1),
989 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
990 show_pwm_auto_point_temp_hyst,
991 store_pwm_auto_point_temp_hyst,
992 0, 1),
993 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
994 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
995 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
996 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
997 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
998 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
999};
Hans de Goede45fb3662007-07-13 14:34:19 +02001000
1001/* Super I/O functions */
1002static inline int superio_inb(int base, int reg)
1003{
1004 outb(reg, base);
1005 return inb(base + 1);
1006}
1007
1008static int superio_inw(int base, int reg)
1009{
1010 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001011 val = superio_inb(base, reg) << 8;
1012 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001013 return val;
1014}
1015
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001016static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +02001017{
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001018 /* Don't step on other drivers' I/O space by accident */
1019 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +00001020 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001021 return -EBUSY;
1022 }
1023
Hans de Goede45fb3662007-07-13 14:34:19 +02001024 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001025 outb(SIO_UNLOCK_KEY, base);
1026 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001027
1028 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001029}
1030
Giel van Schijndel162bb592010-05-27 19:58:40 +02001031static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001032{
1033 outb(SIO_REG_LDSEL, base);
1034 outb(ld, base + 1);
1035}
1036
1037static inline void superio_exit(int base)
1038{
1039 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001040 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001041}
1042
Hans de Goede2f650632009-01-07 16:37:31 +01001043static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001044{
1045 return reg ? (1500000 / reg) : 0;
1046}
1047
Hans de Goede2f650632009-01-07 16:37:31 +01001048static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001049{
1050 return fan ? (1500000 / fan) : 0;
1051}
1052
Hans de Goede45fb3662007-07-13 14:34:19 +02001053static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1054{
1055 u8 val;
1056
1057 outb(reg, data->addr + ADDR_REG_OFFSET);
1058 val = inb(data->addr + DATA_REG_OFFSET);
1059
1060 return val;
1061}
1062
1063static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1064{
1065 u16 val;
1066
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001067 val = f71882fg_read8(data, reg) << 8;
1068 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001069
1070 return val;
1071}
1072
1073static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1074{
1075 outb(reg, data->addr + ADDR_REG_OFFSET);
1076 outb(val, data->addr + DATA_REG_OFFSET);
1077}
1078
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001079static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1080{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001081 f71882fg_write8(data, reg, val >> 8);
1082 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001083}
1084
Hans de Goede09475d32009-06-15 18:39:52 +02001085static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1086{
1087 if (data->type == f71858fg)
1088 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1089 else
1090 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1091}
1092
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001093static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001094{
1095 struct f71882fg_data *data = dev_get_drvdata(dev);
Jean Delvaref27def02011-03-26 10:45:01 +01001096 int nr_fans = f71882fg_nr_fans[data->type];
1097 int nr_temps = f71882fg_nr_temps[data->type];
Hans de Goedee5e713c2011-03-10 08:54:02 +01001098 int nr, reg, point;
Hans de Goede45fb3662007-07-13 14:34:19 +02001099
1100 mutex_lock(&data->update_lock);
1101
1102 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001103 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001104 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001105 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001106 data->in1_max =
1107 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1108 data->in_beep =
1109 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1110 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001111
1112 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001113 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1114 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001115 data->temp_ovt[nr] = f71882fg_read8(data,
1116 F71882FG_REG_TEMP_OVT(nr));
1117 data->temp_high[nr] = f71882fg_read8(data,
1118 F71882FG_REG_TEMP_HIGH(nr));
1119 }
1120
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001121 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001122 data->temp_hyst[0] = f71882fg_read8(data,
1123 F71882FG_REG_TEMP_HYST(0));
1124 data->temp_hyst[1] = f71882fg_read8(data,
1125 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001126 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001127 /* All but the f71858fg / f8000 have this register */
1128 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001129 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001130 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001131 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1132 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1133 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001134
Hans de Goede78aa4f72011-03-09 20:57:12 +01001135 if (f71882fg_has_beep[data->type]) {
1136 data->fan_beep = f71882fg_read8(data,
1137 F71882FG_REG_FAN_BEEP);
1138 data->temp_beep = f71882fg_read8(data,
1139 F71882FG_REG_TEMP_BEEP);
1140 }
1141
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001142 data->pwm_enable = f71882fg_read8(data,
1143 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001144 data->pwm_auto_point_hyst[0] =
1145 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1146 data->pwm_auto_point_hyst[1] =
1147 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1148
Hans de Goede498be962009-01-07 16:37:28 +01001149 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001150 data->pwm_auto_point_mapping[nr] =
1151 f71882fg_read8(data,
1152 F71882FG_REG_POINT_MAPPING(nr));
1153
Hans de Goedee5e713c2011-03-10 08:54:02 +01001154 switch (data->type) {
1155 default:
Hans de Goede498be962009-01-07 16:37:28 +01001156 for (point = 0; point < 5; point++) {
1157 data->pwm_auto_point_pwm[nr][point] =
1158 f71882fg_read8(data,
1159 F71882FG_REG_POINT_PWM
1160 (nr, point));
1161 }
1162 for (point = 0; point < 4; point++) {
1163 data->pwm_auto_point_temp[nr][point] =
1164 f71882fg_read8(data,
1165 F71882FG_REG_POINT_TEMP
1166 (nr, point));
1167 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001168 break;
1169 case f71808e:
1170 case f71869:
1171 data->pwm_auto_point_pwm[nr][0] =
1172 f71882fg_read8(data,
1173 F71882FG_REG_POINT_PWM(nr, 0));
1174 /* Fall through */
1175 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001176 data->pwm_auto_point_pwm[nr][1] =
1177 f71882fg_read8(data,
1178 F71882FG_REG_POINT_PWM
1179 (nr, 1));
1180 data->pwm_auto_point_pwm[nr][4] =
1181 f71882fg_read8(data,
1182 F71882FG_REG_POINT_PWM
1183 (nr, 4));
1184 data->pwm_auto_point_temp[nr][0] =
1185 f71882fg_read8(data,
1186 F71882FG_REG_POINT_TEMP
1187 (nr, 0));
1188 data->pwm_auto_point_temp[nr][3] =
1189 f71882fg_read8(data,
1190 F71882FG_REG_POINT_TEMP
1191 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001192 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001193 }
1194 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001195 data->last_limits = jiffies;
1196 }
1197
1198 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001199 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001200 data->temp_status = f71882fg_read8(data,
1201 F71882FG_REG_TEMP_STATUS);
1202 data->temp_diode_open = f71882fg_read8(data,
1203 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001204 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1205 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001206 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001207
1208 data->fan_status = f71882fg_read8(data,
1209 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001210 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001211 data->fan[nr] = f71882fg_read16(data,
1212 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001213 data->fan_target[nr] =
1214 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1215 data->fan_full_speed[nr] =
1216 f71882fg_read16(data,
1217 F71882FG_REG_FAN_FULL_SPEED(nr));
1218 data->pwm[nr] =
1219 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1220 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001221 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1222 if (data->type == f8000)
1223 data->fan[3] = f71882fg_read16(data,
1224 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001225
1226 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001227 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001228 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001229 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1230 if (f71882fg_has_in[data->type][nr])
1231 data->in[nr] = f71882fg_read8(data,
1232 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001233
1234 data->last_updated = jiffies;
1235 data->valid = 1;
1236 }
1237
1238 mutex_unlock(&data->update_lock);
1239
1240 return data;
1241}
1242
1243/* Sysfs Interface */
1244static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1245 char *buf)
1246{
1247 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001248 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001249 int speed = fan_from_reg(data->fan[nr]);
1250
1251 if (speed == FAN_MIN_DETECT)
1252 speed = 0;
1253
1254 return sprintf(buf, "%d\n", speed);
1255}
1256
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001257static ssize_t show_fan_full_speed(struct device *dev,
1258 struct device_attribute *devattr, char *buf)
1259{
1260 struct f71882fg_data *data = f71882fg_update_device(dev);
1261 int nr = to_sensor_dev_attr_2(devattr)->index;
1262 int speed = fan_from_reg(data->fan_full_speed[nr]);
1263 return sprintf(buf, "%d\n", speed);
1264}
1265
1266static ssize_t store_fan_full_speed(struct device *dev,
1267 struct device_attribute *devattr,
1268 const char *buf, size_t count)
1269{
1270 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001271 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1272 long val;
1273
1274 err = strict_strtol(buf, 10, &val);
1275 if (err)
1276 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001277
1278 val = SENSORS_LIMIT(val, 23, 1500000);
1279 val = fan_to_reg(val);
1280
1281 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001282 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1283 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001284 mutex_unlock(&data->update_lock);
1285
1286 return count;
1287}
1288
Hans de Goede45fb3662007-07-13 14:34:19 +02001289static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1290 *devattr, char *buf)
1291{
1292 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001293 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001294
1295 if (data->fan_beep & (1 << nr))
1296 return sprintf(buf, "1\n");
1297 else
1298 return sprintf(buf, "0\n");
1299}
1300
1301static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1302 *devattr, const char *buf, size_t count)
1303{
1304 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001305 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1306 unsigned long val;
1307
1308 err = strict_strtoul(buf, 10, &val);
1309 if (err)
1310 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001311
1312 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001313 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001314 if (val)
1315 data->fan_beep |= 1 << nr;
1316 else
1317 data->fan_beep &= ~(1 << nr);
1318
1319 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1320 mutex_unlock(&data->update_lock);
1321
1322 return count;
1323}
1324
1325static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1326 *devattr, char *buf)
1327{
1328 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001329 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001330
1331 if (data->fan_status & (1 << nr))
1332 return sprintf(buf, "1\n");
1333 else
1334 return sprintf(buf, "0\n");
1335}
1336
1337static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1338 char *buf)
1339{
1340 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001341 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001342
1343 return sprintf(buf, "%d\n", data->in[nr] * 8);
1344}
1345
1346static ssize_t show_in_max(struct device *dev, struct device_attribute
1347 *devattr, char *buf)
1348{
1349 struct f71882fg_data *data = f71882fg_update_device(dev);
1350
1351 return sprintf(buf, "%d\n", data->in1_max * 8);
1352}
1353
1354static ssize_t store_in_max(struct device *dev, struct device_attribute
1355 *devattr, const char *buf, size_t count)
1356{
1357 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001358 int err;
1359 long val;
1360
1361 err = strict_strtol(buf, 10, &val);
1362 if (err)
1363 return err;
1364
1365 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001366 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001367
1368 mutex_lock(&data->update_lock);
1369 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1370 data->in1_max = val;
1371 mutex_unlock(&data->update_lock);
1372
1373 return count;
1374}
1375
1376static ssize_t show_in_beep(struct device *dev, struct device_attribute
1377 *devattr, char *buf)
1378{
1379 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001380 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001381
1382 if (data->in_beep & (1 << nr))
1383 return sprintf(buf, "1\n");
1384 else
1385 return sprintf(buf, "0\n");
1386}
1387
1388static ssize_t store_in_beep(struct device *dev, struct device_attribute
1389 *devattr, const char *buf, size_t count)
1390{
1391 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001392 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1393 unsigned long val;
1394
1395 err = strict_strtoul(buf, 10, &val);
1396 if (err)
1397 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001398
1399 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001400 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001401 if (val)
1402 data->in_beep |= 1 << nr;
1403 else
1404 data->in_beep &= ~(1 << nr);
1405
1406 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1407 mutex_unlock(&data->update_lock);
1408
1409 return count;
1410}
1411
1412static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1413 *devattr, char *buf)
1414{
1415 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001416 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001417
1418 if (data->in_status & (1 << nr))
1419 return sprintf(buf, "1\n");
1420 else
1421 return sprintf(buf, "0\n");
1422}
1423
1424static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1425 char *buf)
1426{
1427 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001428 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001429 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001430
Hans de Goede09475d32009-06-15 18:39:52 +02001431 if (data->type == f71858fg) {
1432 /* TEMP_TABLE_SEL 1 or 3 ? */
1433 if (data->temp_config & 1) {
1434 sign = data->temp[nr] & 0x0001;
1435 temp = (data->temp[nr] >> 5) & 0x7ff;
1436 } else {
1437 sign = data->temp[nr] & 0x8000;
1438 temp = (data->temp[nr] >> 5) & 0x3ff;
1439 }
1440 temp *= 125;
1441 if (sign)
1442 temp -= 128000;
1443 } else
1444 temp = data->temp[nr] * 1000;
1445
1446 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001447}
1448
1449static ssize_t show_temp_max(struct device *dev, struct device_attribute
1450 *devattr, char *buf)
1451{
1452 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001453 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001454
1455 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1456}
1457
1458static ssize_t store_temp_max(struct device *dev, struct device_attribute
1459 *devattr, const char *buf, size_t count)
1460{
1461 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001462 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1463 long val;
1464
1465 err = strict_strtol(buf, 10, &val);
1466 if (err)
1467 return err;
1468
1469 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001470 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001471
1472 mutex_lock(&data->update_lock);
1473 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1474 data->temp_high[nr] = val;
1475 mutex_unlock(&data->update_lock);
1476
1477 return count;
1478}
1479
1480static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1481 *devattr, char *buf)
1482{
1483 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001484 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001485 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001486
Hans de Goedece0bfa52009-01-07 16:37:28 +01001487 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001488 if (nr & 1)
1489 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1490 else
1491 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1492 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001493 mutex_unlock(&data->update_lock);
1494
1495 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001496}
1497
1498static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1499 *devattr, const char *buf, size_t count)
1500{
1501 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001502 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001503 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001504 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001505 long val;
1506
1507 err = strict_strtol(buf, 10, &val);
1508 if (err)
1509 return err;
1510
1511 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001512
1513 mutex_lock(&data->update_lock);
1514
1515 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001516 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1517 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1518 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001519 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001520
1521 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001522 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1523 if (nr & 1)
1524 reg = (reg & 0x0f) | (val << 4);
1525 else
1526 reg = (reg & 0xf0) | val;
1527 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1528 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001529
Hans de Goede45fb3662007-07-13 14:34:19 +02001530 mutex_unlock(&data->update_lock);
1531 return ret;
1532}
1533
1534static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1535 *devattr, char *buf)
1536{
1537 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001538 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001539
1540 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1541}
1542
1543static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1544 *devattr, const char *buf, size_t count)
1545{
1546 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001547 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1548 long val;
1549
1550 err = strict_strtol(buf, 10, &val);
1551 if (err)
1552 return err;
1553
1554 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001555 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001556
1557 mutex_lock(&data->update_lock);
1558 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1559 data->temp_ovt[nr] = val;
1560 mutex_unlock(&data->update_lock);
1561
1562 return count;
1563}
1564
1565static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1566 *devattr, char *buf)
1567{
1568 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001569 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001570 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001571
Hans de Goedece0bfa52009-01-07 16:37:28 +01001572 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001573 if (nr & 1)
1574 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1575 else
1576 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1577 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001578 mutex_unlock(&data->update_lock);
1579
1580 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001581}
1582
1583static ssize_t show_temp_type(struct device *dev, struct device_attribute
1584 *devattr, char *buf)
1585{
1586 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001587 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001588
1589 return sprintf(buf, "%d\n", data->temp_type[nr]);
1590}
1591
1592static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1593 *devattr, char *buf)
1594{
1595 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001596 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001597
Hans de Goede7567a042009-01-07 16:37:28 +01001598 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001599 return sprintf(buf, "1\n");
1600 else
1601 return sprintf(buf, "0\n");
1602}
1603
1604static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1605 *devattr, const char *buf, size_t count)
1606{
1607 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001608 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1609 unsigned long val;
1610
1611 err = strict_strtoul(buf, 10, &val);
1612 if (err)
1613 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001614
1615 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001616 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001617 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001618 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001619 else
Hans de Goede7567a042009-01-07 16:37:28 +01001620 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001621
1622 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1623 mutex_unlock(&data->update_lock);
1624
1625 return count;
1626}
1627
1628static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1629 *devattr, char *buf)
1630{
1631 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001632 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001633
Hans de Goede7567a042009-01-07 16:37:28 +01001634 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001635 return sprintf(buf, "1\n");
1636 else
1637 return sprintf(buf, "0\n");
1638}
1639
1640static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1641 *devattr, char *buf)
1642{
1643 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001644 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001645
Hans de Goede7567a042009-01-07 16:37:28 +01001646 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001647 return sprintf(buf, "1\n");
1648 else
1649 return sprintf(buf, "0\n");
1650}
1651
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001652static ssize_t show_pwm(struct device *dev,
1653 struct device_attribute *devattr, char *buf)
1654{
1655 struct f71882fg_data *data = f71882fg_update_device(dev);
1656 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001657 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001658 if (data->pwm_enable & (1 << (2 * nr)))
1659 /* PWM mode */
1660 val = data->pwm[nr];
1661 else {
1662 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001663 val = 255 * fan_from_reg(data->fan_target[nr])
1664 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001665 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001666 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001667 return sprintf(buf, "%d\n", val);
1668}
1669
1670static ssize_t store_pwm(struct device *dev,
1671 struct device_attribute *devattr, const char *buf,
1672 size_t count)
1673{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001674 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001675 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1676 long val;
1677
1678 err = strict_strtol(buf, 10, &val);
1679 if (err)
1680 return err;
1681
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001682 val = SENSORS_LIMIT(val, 0, 255);
1683
1684 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001685 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001686 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1687 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1688 count = -EROFS;
1689 goto leave;
1690 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001691 if (data->pwm_enable & (1 << (2 * nr))) {
1692 /* PWM mode */
1693 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1694 data->pwm[nr] = val;
1695 } else {
1696 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001697 int target, full_speed;
1698 full_speed = f71882fg_read16(data,
1699 F71882FG_REG_FAN_FULL_SPEED(nr));
1700 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1701 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1702 data->fan_target[nr] = target;
1703 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001704 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001705leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001706 mutex_unlock(&data->update_lock);
1707
1708 return count;
1709}
1710
1711static ssize_t show_pwm_enable(struct device *dev,
1712 struct device_attribute *devattr, char *buf)
1713{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001714 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001715 struct f71882fg_data *data = f71882fg_update_device(dev);
1716 int nr = to_sensor_dev_attr_2(devattr)->index;
1717
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001718 switch ((data->pwm_enable >> 2 * nr) & 3) {
1719 case 0:
1720 case 1:
1721 result = 2; /* Normal auto mode */
1722 break;
1723 case 2:
1724 result = 1; /* Manual mode */
1725 break;
1726 case 3:
1727 if (data->type == f8000)
1728 result = 3; /* Thermostat mode */
1729 else
1730 result = 1; /* Manual mode */
1731 break;
1732 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001733
1734 return sprintf(buf, "%d\n", result);
1735}
1736
1737static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1738 *devattr, const char *buf, size_t count)
1739{
1740 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001741 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1742 long val;
1743
1744 err = strict_strtol(buf, 10, &val);
1745 if (err)
1746 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001747
Hans de Goede3fc78382009-06-15 18:39:50 +02001748 /* Special case for F8000 pwm channel 3 which only does auto mode */
1749 if (data->type == f8000 && nr == 2 && val != 2)
1750 return -EINVAL;
1751
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001752 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001753 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001754 /* Special case for F8000 auto PWM mode / Thermostat mode */
1755 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1756 switch (val) {
1757 case 2:
1758 data->pwm_enable &= ~(2 << (2 * nr));
1759 break; /* Normal auto mode */
1760 case 3:
1761 data->pwm_enable |= 2 << (2 * nr);
1762 break; /* Thermostat mode */
1763 default:
1764 count = -EINVAL;
1765 goto leave;
1766 }
1767 } else {
1768 switch (val) {
1769 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001770 /* The f71858fg does not support manual RPM mode */
1771 if (data->type == f71858fg &&
1772 ((data->pwm_enable >> (2 * nr)) & 1)) {
1773 count = -EINVAL;
1774 goto leave;
1775 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001776 data->pwm_enable |= 2 << (2 * nr);
1777 break; /* Manual */
1778 case 2:
1779 data->pwm_enable &= ~(2 << (2 * nr));
1780 break; /* Normal auto mode */
1781 default:
1782 count = -EINVAL;
1783 goto leave;
1784 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001785 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001786 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001787leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001788 mutex_unlock(&data->update_lock);
1789
1790 return count;
1791}
1792
1793static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1794 struct device_attribute *devattr,
1795 char *buf)
1796{
1797 int result;
1798 struct f71882fg_data *data = f71882fg_update_device(dev);
1799 int pwm = to_sensor_dev_attr_2(devattr)->index;
1800 int point = to_sensor_dev_attr_2(devattr)->nr;
1801
Hans de Goedece0bfa52009-01-07 16:37:28 +01001802 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001803 if (data->pwm_enable & (1 << (2 * pwm))) {
1804 /* PWM mode */
1805 result = data->pwm_auto_point_pwm[pwm][point];
1806 } else {
1807 /* RPM mode */
1808 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1809 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001810 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001811
1812 return sprintf(buf, "%d\n", result);
1813}
1814
1815static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1816 struct device_attribute *devattr,
1817 const char *buf, size_t count)
1818{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001819 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001820 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001821 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001822 long val;
1823
1824 err = strict_strtol(buf, 10, &val);
1825 if (err)
1826 return err;
1827
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001828 val = SENSORS_LIMIT(val, 0, 255);
1829
1830 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001831 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001832 if (data->pwm_enable & (1 << (2 * pwm))) {
1833 /* PWM mode */
1834 } else {
1835 /* RPM mode */
1836 if (val < 29) /* Prevent negative numbers */
1837 val = 255;
1838 else
1839 val = (255 - val) * 32 / val;
1840 }
1841 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1842 data->pwm_auto_point_pwm[pwm][point] = val;
1843 mutex_unlock(&data->update_lock);
1844
1845 return count;
1846}
1847
1848static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1849 struct device_attribute *devattr,
1850 char *buf)
1851{
1852 int result = 0;
1853 struct f71882fg_data *data = f71882fg_update_device(dev);
1854 int nr = to_sensor_dev_attr_2(devattr)->index;
1855 int point = to_sensor_dev_attr_2(devattr)->nr;
1856
1857 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001858 if (nr & 1)
1859 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1860 else
1861 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001862 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1863 mutex_unlock(&data->update_lock);
1864
1865 return sprintf(buf, "%d\n", result);
1866}
1867
1868static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1869 struct device_attribute *devattr,
1870 const char *buf, size_t count)
1871{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001872 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001873 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001874 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001875 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001876 long val;
1877
1878 err = strict_strtol(buf, 10, &val);
1879 if (err)
1880 return err;
1881
1882 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001883
1884 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001885 data->pwm_auto_point_temp[nr][point] =
1886 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001887 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1888 data->pwm_auto_point_temp[nr][point]);
1889 val = data->pwm_auto_point_temp[nr][point] - val;
1890
Hans de Goedebc274902009-01-07 16:37:29 +01001891 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1892 if (nr & 1)
1893 reg = (reg & 0x0f) | (val << 4);
1894 else
1895 reg = (reg & 0xf0) | val;
1896
1897 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1898 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001899 mutex_unlock(&data->update_lock);
1900
1901 return count;
1902}
1903
1904static ssize_t show_pwm_interpolate(struct device *dev,
1905 struct device_attribute *devattr, char *buf)
1906{
1907 int result;
1908 struct f71882fg_data *data = f71882fg_update_device(dev);
1909 int nr = to_sensor_dev_attr_2(devattr)->index;
1910
1911 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1912
1913 return sprintf(buf, "%d\n", result);
1914}
1915
1916static ssize_t store_pwm_interpolate(struct device *dev,
1917 struct device_attribute *devattr,
1918 const char *buf, size_t count)
1919{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001920 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001921 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1922 unsigned long val;
1923
1924 err = strict_strtoul(buf, 10, &val);
1925 if (err)
1926 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001927
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001928 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001929 data->pwm_auto_point_mapping[nr] =
1930 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001931 if (val)
1932 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1933 else
1934 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1935 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1936 data->pwm_auto_point_mapping[nr] = val;
1937 mutex_unlock(&data->update_lock);
1938
1939 return count;
1940}
1941
1942static ssize_t show_pwm_auto_point_channel(struct device *dev,
1943 struct device_attribute *devattr,
1944 char *buf)
1945{
1946 int result;
1947 struct f71882fg_data *data = f71882fg_update_device(dev);
1948 int nr = to_sensor_dev_attr_2(devattr)->index;
1949
Hans de Goede09475d32009-06-15 18:39:52 +02001950 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1951 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001952
1953 return sprintf(buf, "%d\n", result);
1954}
1955
1956static ssize_t store_pwm_auto_point_channel(struct device *dev,
1957 struct device_attribute *devattr,
1958 const char *buf, size_t count)
1959{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001960 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001961 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1962 long val;
1963
1964 err = strict_strtol(buf, 10, &val);
1965 if (err)
1966 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001967
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001968 switch (val) {
1969 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001970 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001971 break;
1972 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001973 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001974 break;
1975 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001976 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001977 break;
1978 default:
1979 return -EINVAL;
1980 }
Hans de Goede09475d32009-06-15 18:39:52 +02001981 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001982 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001983 data->pwm_auto_point_mapping[nr] =
1984 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001985 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1986 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1987 data->pwm_auto_point_mapping[nr] = val;
1988 mutex_unlock(&data->update_lock);
1989
1990 return count;
1991}
1992
1993static ssize_t show_pwm_auto_point_temp(struct device *dev,
1994 struct device_attribute *devattr,
1995 char *buf)
1996{
1997 int result;
1998 struct f71882fg_data *data = f71882fg_update_device(dev);
1999 int pwm = to_sensor_dev_attr_2(devattr)->index;
2000 int point = to_sensor_dev_attr_2(devattr)->nr;
2001
2002 result = data->pwm_auto_point_temp[pwm][point];
2003 return sprintf(buf, "%d\n", 1000 * result);
2004}
2005
2006static ssize_t store_pwm_auto_point_temp(struct device *dev,
2007 struct device_attribute *devattr,
2008 const char *buf, size_t count)
2009{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002010 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002011 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002012 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002013 long val;
2014
2015 err = strict_strtol(buf, 10, &val);
2016 if (err)
2017 return err;
2018
2019 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01002020
Hans de Goede98f7ba12011-03-09 20:57:09 +01002021 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01002022 val = SENSORS_LIMIT(val, -128, 127);
2023 else
2024 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002025
2026 mutex_lock(&data->update_lock);
2027 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2028 data->pwm_auto_point_temp[pwm][point] = val;
2029 mutex_unlock(&data->update_lock);
2030
2031 return count;
2032}
2033
Hans de Goede45fb3662007-07-13 14:34:19 +02002034static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2035 char *buf)
2036{
Hans de Goede498be962009-01-07 16:37:28 +01002037 struct f71882fg_data *data = dev_get_drvdata(dev);
2038 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002039}
2040
Hans de Goedec13548c2009-01-07 16:37:27 +01002041static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
2042 struct sensor_device_attribute_2 *attr, int count)
2043{
2044 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002045
Hans de Goedec13548c2009-01-07 16:37:27 +01002046 for (i = 0; i < count; i++) {
2047 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2048 if (err)
2049 return err;
2050 }
2051 return 0;
2052}
2053
Hans de Goedefc16c562009-12-09 20:36:01 +01002054static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2055 struct sensor_device_attribute_2 *attr, int count)
2056{
2057 int i;
2058
2059 for (i = 0; i < count; i++)
2060 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2061}
2062
Hans de Goedec13548c2009-01-07 16:37:27 +01002063static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002064{
2065 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01002066 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Jean Delvaref27def02011-03-26 10:45:01 +01002067 int nr_fans = f71882fg_nr_fans[sio_data->type];
2068 int nr_temps = f71882fg_nr_temps[sio_data->type];
2069 int err, i;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002070 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002071
Hans de Goedec13548c2009-01-07 16:37:27 +01002072 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
2073 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002074 return -ENOMEM;
2075
2076 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002077 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002078 data->temp_start =
2079 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002080 mutex_init(&data->update_lock);
2081 platform_set_drvdata(pdev, data);
2082
Hans de Goede3cc74752009-01-07 16:37:28 +01002083 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002084 if (start_reg & 0x04) {
2085 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
2086 err = -ENODEV;
2087 goto exit_free;
2088 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002089 if (!(start_reg & 0x03)) {
2090 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
2091 err = -ENODEV;
2092 goto exit_free;
2093 }
2094
Hans de Goede45fb3662007-07-13 14:34:19 +02002095 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002096 err = device_create_file(&pdev->dev, &dev_attr_name);
2097 if (err)
2098 goto exit_unregister_sysfs;
2099
Hans de Goedec13548c2009-01-07 16:37:27 +01002100 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002101 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002102 case f71858fg:
2103 data->temp_config =
2104 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2105 if (data->temp_config & 0x10)
2106 /* The f71858fg temperature alarms behave as
2107 the f8000 alarms in this mode */
2108 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002109 f8000_temp_attr,
2110 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002111 else
2112 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002113 f71858fg_temp_attr,
2114 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002115 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002116 case f8000:
2117 err = f71882fg_create_sysfs_files(pdev,
2118 f8000_temp_attr,
2119 ARRAY_SIZE(f8000_temp_attr));
2120 break;
2121 default:
2122 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002123 &fxxxx_temp_attr[0][0],
2124 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002125 }
2126 if (err)
2127 goto exit_unregister_sysfs;
2128
Hans de Goede78aa4f72011-03-09 20:57:12 +01002129 if (f71882fg_has_beep[data->type]) {
2130 err = f71882fg_create_sysfs_files(pdev,
2131 &fxxxx_temp_beep_attr[0][0],
2132 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2133 * nr_temps);
2134 if (err)
2135 goto exit_unregister_sysfs;
2136 }
2137
Hans de Goede0bae6402011-03-09 20:57:10 +01002138 for (i = 0; i < F71882FG_MAX_INS; i++) {
2139 if (f71882fg_has_in[data->type][i]) {
2140 err = device_create_file(&pdev->dev,
2141 &fxxxx_in_attr[i].dev_attr);
2142 if (err)
2143 goto exit_unregister_sysfs;
2144 }
2145 }
2146 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002147 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002148 fxxxx_in1_alarm_attr,
2149 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002150 if (err)
2151 goto exit_unregister_sysfs;
2152 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002153 }
2154
Hans de Goede45fb3662007-07-13 14:34:19 +02002155 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002156 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002157 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002158 case f71869:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002159 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002160 data->auto_point_temp_signed = 1;
2161 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002162 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002163 case f71889ed:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002164 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2165 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2166 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002167 /* Ensure banked pwm registers point to right bank */
2168 reg &= ~F71882FG_FAN_PROG_SEL;
2169 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002170 break;
2171 default:
2172 break;
2173 }
2174
Hans de Goede996cadb2009-06-15 18:39:51 +02002175 data->pwm_enable =
2176 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2177
2178 /* Sanity check the pwm settings */
2179 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002180 case f71858fg:
2181 err = 0;
2182 for (i = 0; i < nr_fans; i++)
2183 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2184 err = 1;
2185 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002186 case f71862fg:
2187 err = (data->pwm_enable & 0x15) != 0x15;
2188 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002189 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002190 case f71869:
Hans de Goede996cadb2009-06-15 18:39:51 +02002191 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002192 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002193 case f71889ed:
Hans de Goede996cadb2009-06-15 18:39:51 +02002194 err = 0;
2195 break;
2196 case f8000:
2197 err = data->pwm_enable & 0x20;
2198 break;
2199 }
2200 if (err) {
2201 dev_err(&pdev->dev,
2202 "Invalid (reserved) pwm settings: 0x%02x\n",
2203 (unsigned int)data->pwm_enable);
2204 err = -ENODEV;
2205 goto exit_unregister_sysfs;
2206 }
2207
Hans de Goedeb69b0392009-12-09 20:36:00 +01002208 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2209 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002210 if (err)
2211 goto exit_unregister_sysfs;
2212
Hans de Goede78aa4f72011-03-09 20:57:12 +01002213 if (f71882fg_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002214 err = f71882fg_create_sysfs_files(pdev,
2215 fxxxx_fan_beep_attr, nr_fans);
2216 if (err)
2217 goto exit_unregister_sysfs;
2218 }
2219
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002220 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002221 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002222 case f71869:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002223 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002224 case f71889ed:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002225 for (i = 0; i < nr_fans; i++) {
2226 data->pwm_auto_point_mapping[i] =
2227 f71882fg_read8(data,
2228 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002229 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2230 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002231 break;
2232 }
2233 if (i != nr_fans) {
2234 dev_warn(&pdev->dev,
2235 "Auto pwm controlled by raw digital "
2236 "data, disabling pwm auto_point "
2237 "sysfs attributes\n");
2238 goto no_pwm_auto_point;
2239 }
2240 break;
2241 default:
2242 break;
2243 }
2244
2245 switch (data->type) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002246 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002247 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002248 f71862fg_auto_pwm_attr,
2249 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002250 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002251 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002252 case f71869:
2253 err = f71882fg_create_sysfs_files(pdev,
2254 f71869_auto_pwm_attr,
2255 ARRAY_SIZE(f71869_auto_pwm_attr));
2256 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002257 case f8000:
2258 err = f71882fg_create_sysfs_files(pdev,
2259 f8000_fan_attr,
2260 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002261 if (err)
2262 goto exit_unregister_sysfs;
2263 err = f71882fg_create_sysfs_files(pdev,
2264 f8000_auto_pwm_attr,
2265 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002266 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002267 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002268 err = f71882fg_create_sysfs_files(pdev,
2269 &fxxxx_auto_pwm_attr[0][0],
2270 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002271 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002272 if (err)
2273 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002274
Hans de Goedee48a7f12011-03-09 20:57:13 +01002275no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002276 for (i = 0; i < nr_fans; i++)
2277 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2278 (data->pwm_enable & (1 << 2 * i)) ?
2279 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002280 }
2281
Tony Jones1beeffe2007-08-20 13:46:20 -07002282 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2283 if (IS_ERR(data->hwmon_dev)) {
2284 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002285 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002286 goto exit_unregister_sysfs;
2287 }
2288
2289 return 0;
2290
2291exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002292 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002293 return err; /* f71882fg_remove() also frees our data */
2294exit_free:
2295 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002296 return err;
2297}
2298
Hans de Goedec13548c2009-01-07 16:37:27 +01002299static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002300{
Hans de Goede45fb3662007-07-13 14:34:19 +02002301 struct f71882fg_data *data = platform_get_drvdata(pdev);
Jean Delvaref27def02011-03-26 10:45:01 +01002302 int nr_fans = f71882fg_nr_fans[data->type];
2303 int nr_temps = f71882fg_nr_temps[data->type];
2304 int i;
Hans de Goedefc16c562009-12-09 20:36:01 +01002305 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002306
Hans de Goedec13548c2009-01-07 16:37:27 +01002307 if (data->hwmon_dev)
2308 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002309
Hans de Goedec13548c2009-01-07 16:37:27 +01002310 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002311
Hans de Goedefc16c562009-12-09 20:36:01 +01002312 if (start_reg & 0x01) {
2313 switch (data->type) {
2314 case f71858fg:
2315 if (data->temp_config & 0x10)
2316 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002317 f8000_temp_attr,
2318 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002319 else
2320 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002321 f71858fg_temp_attr,
2322 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002323 break;
2324 case f8000:
2325 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002326 f8000_temp_attr,
2327 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002328 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002329 default:
2330 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002331 &fxxxx_temp_attr[0][0],
2332 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002333 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002334 if (f71882fg_has_beep[data->type]) {
2335 f71882fg_remove_sysfs_files(pdev,
2336 &fxxxx_temp_beep_attr[0][0],
2337 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2338 }
2339
Hans de Goede0bae6402011-03-09 20:57:10 +01002340 for (i = 0; i < F71882FG_MAX_INS; i++) {
2341 if (f71882fg_has_in[data->type][i]) {
2342 device_remove_file(&pdev->dev,
2343 &fxxxx_in_attr[i].dev_attr);
2344 }
2345 }
2346 if (f71882fg_has_in1_alarm[data->type]) {
2347 f71882fg_remove_sysfs_files(pdev,
2348 fxxxx_in1_alarm_attr,
2349 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002350 }
2351 }
Hans de Goede498be962009-01-07 16:37:28 +01002352
Hans de Goedefc16c562009-12-09 20:36:01 +01002353 if (start_reg & 0x02) {
2354 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2355 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002356
Hans de Goede78aa4f72011-03-09 20:57:12 +01002357 if (f71882fg_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002358 f71882fg_remove_sysfs_files(pdev,
2359 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002360 }
Hans de Goede498be962009-01-07 16:37:28 +01002361
Hans de Goedefc16c562009-12-09 20:36:01 +01002362 switch (data->type) {
2363 case f71862fg:
2364 f71882fg_remove_sysfs_files(pdev,
2365 f71862fg_auto_pwm_attr,
2366 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2367 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002368 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002369 case f71869:
2370 f71882fg_remove_sysfs_files(pdev,
2371 f71869_auto_pwm_attr,
2372 ARRAY_SIZE(f71869_auto_pwm_attr));
2373 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002374 case f8000:
2375 f71882fg_remove_sysfs_files(pdev,
2376 f8000_fan_attr,
2377 ARRAY_SIZE(f8000_fan_attr));
2378 f71882fg_remove_sysfs_files(pdev,
2379 f8000_auto_pwm_attr,
2380 ARRAY_SIZE(f8000_auto_pwm_attr));
2381 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002382 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002383 f71882fg_remove_sysfs_files(pdev,
2384 &fxxxx_auto_pwm_attr[0][0],
2385 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2386 }
2387 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002388
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002389 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002390 kfree(data);
2391
2392 return 0;
2393}
2394
Hans de Goede498be962009-01-07 16:37:28 +01002395static int __init f71882fg_find(int sioaddr, unsigned short *address,
2396 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002397{
Hans de Goede45fb3662007-07-13 14:34:19 +02002398 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002399 int err = superio_enter(sioaddr);
2400 if (err)
2401 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002402
2403 devid = superio_inw(sioaddr, SIO_REG_MANID);
2404 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002405 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002406 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002407 goto exit;
2408 }
2409
Jean Delvare67b671b2007-12-06 23:13:42 +01002410 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002411 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002412 case SIO_F71808E_ID:
2413 sio_data->type = f71808e;
2414 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002415 case SIO_F71858_ID:
2416 sio_data->type = f71858fg;
2417 break;
Hans de Goede498be962009-01-07 16:37:28 +01002418 case SIO_F71862_ID:
2419 sio_data->type = f71862fg;
2420 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002421 case SIO_F71869_ID:
2422 sio_data->type = f71869;
2423 break;
Hans de Goede498be962009-01-07 16:37:28 +01002424 case SIO_F71882_ID:
2425 sio_data->type = f71882fg;
2426 break;
Hans de Goede76698962009-12-09 20:36:01 +01002427 case SIO_F71889_ID:
2428 sio_data->type = f71889fg;
2429 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002430 case SIO_F71889E_ID:
2431 sio_data->type = f71889ed;
2432 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002433 case SIO_F8000_ID:
2434 sio_data->type = f8000;
2435 break;
Hans de Goede498be962009-01-07 16:37:28 +01002436 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002437 pr_info("Unsupported Fintek device: %04x\n",
2438 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002439 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002440 goto exit;
2441 }
2442
Hans de Goede09475d32009-06-15 18:39:52 +02002443 if (sio_data->type == f71858fg)
2444 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2445 else
2446 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2447
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002448 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002449 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002450 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002451 goto exit;
2452 }
2453
2454 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002455 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002456 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002457 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002458 goto exit;
2459 }
2460 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2461
Hans de Goede45fb3662007-07-13 14:34:19 +02002462 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002463 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002464 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002465 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2466exit:
2467 superio_exit(sioaddr);
2468 return err;
2469}
2470
Hans de Goede498be962009-01-07 16:37:28 +01002471static int __init f71882fg_device_add(unsigned short address,
2472 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002473{
2474 struct resource res = {
2475 .start = address,
2476 .end = address + REGION_LENGTH - 1,
2477 .flags = IORESOURCE_IO,
2478 };
2479 int err;
2480
2481 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002482 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002483 return -ENOMEM;
2484
2485 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002486 err = acpi_check_resource_conflict(&res);
2487 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002488 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002489
Hans de Goede45fb3662007-07-13 14:34:19 +02002490 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002491 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002492 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002493 goto exit_device_put;
2494 }
2495
Hans de Goede498be962009-01-07 16:37:28 +01002496 err = platform_device_add_data(f71882fg_pdev, sio_data,
2497 sizeof(struct f71882fg_sio_data));
2498 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002499 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002500 goto exit_device_put;
2501 }
2502
Hans de Goede45fb3662007-07-13 14:34:19 +02002503 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002504 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002505 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002506 goto exit_device_put;
2507 }
2508
2509 return 0;
2510
2511exit_device_put:
2512 platform_device_put(f71882fg_pdev);
2513
2514 return err;
2515}
2516
2517static int __init f71882fg_init(void)
2518{
2519 int err = -ENODEV;
2520 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002521 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002522
Hans de Goede498be962009-01-07 16:37:28 +01002523 memset(&sio_data, 0, sizeof(sio_data));
2524
2525 if (f71882fg_find(0x2e, &address, &sio_data) &&
2526 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002527 goto exit;
2528
Hans de Goedec13548c2009-01-07 16:37:27 +01002529 err = platform_driver_register(&f71882fg_driver);
2530 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002531 goto exit;
2532
Hans de Goede498be962009-01-07 16:37:28 +01002533 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002534 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002535 goto exit_driver;
2536
2537 return 0;
2538
2539exit_driver:
2540 platform_driver_unregister(&f71882fg_driver);
2541exit:
2542 return err;
2543}
2544
2545static void __exit f71882fg_exit(void)
2546{
2547 platform_device_unregister(f71882fg_pdev);
2548 platform_driver_unregister(&f71882fg_driver);
2549}
2550
2551MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002552MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002553MODULE_LICENSE("GPL");
2554
2555module_init(f71882fg_init);
2556module_exit(f71882fg_exit);