blob: eea697757891c6dbb303c2d674c13d2311415e40 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goedec11bb992011-03-09 20:57:15 +010052#define SIO_F71869_ID 0x0814 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020053#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010054#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010055#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010056#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020057
58#define REGION_LENGTH 8
59#define ADDR_REG_OFFSET 5
60#define DATA_REG_OFFSET 6
61
Hans de Goede3cad4022011-03-09 20:57:14 +010062#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
63#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010065#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020066
67#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010068#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
69#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020070#define F71882FG_REG_FAN_STATUS 0x92
71#define F71882FG_REG_FAN_BEEP 0x93
72
Hans de Goede7567a042009-01-07 16:37:28 +010073#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
74#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
75#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020076#define F71882FG_REG_TEMP_STATUS 0x62
77#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020078#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010079#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020080#define F71882FG_REG_TEMP_TYPE 0x6B
81#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
82
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010083#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
84#define F71882FG_REG_PWM_TYPE 0x94
85#define F71882FG_REG_PWM_ENABLE 0x96
86
Hans de Goedebc274902009-01-07 16:37:29 +010087#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010088
Hans de Goede98f7ba12011-03-09 20:57:09 +010089#define F71882FG_REG_FAN_FAULT_T 0x9F
90#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010091#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010092
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010093#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
94#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
95#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
96
Hans de Goede45fb3662007-07-13 14:34:19 +020097#define F71882FG_REG_START 0x01
98
Hans de Goede0bae6402011-03-09 20:57:10 +010099#define F71882FG_MAX_INS 9
100
Hans de Goede45fb3662007-07-13 14:34:19 +0200101#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
102
Jean Delvare67b671b2007-12-06 23:13:42 +0100103static unsigned short force_id;
104module_param(force_id, ushort, 0);
105MODULE_PARM_DESC(force_id, "Override the detected device ID");
106
Hans de Goedec11bb992011-03-09 20:57:15 +0100107enum chips { f71858fg, f71862fg, f71869, f71882fg, f71889fg, f71889ed, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100108
109static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200110 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100111 "f71862fg",
Hans de Goedec11bb992011-03-09 20:57:15 +0100112 "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
Hans de Goede498be962009-01-07 16:37:28 +0100113 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100114 "f71889fg",
Hans de Goede3cad4022011-03-09 20:57:14 +0100115 "f71889ed",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100116 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100117};
118
Hans de Goedec11bb992011-03-09 20:57:15 +0100119static const char f71882fg_has_in[7][F71882FG_MAX_INS] = {
Hans de Goede0bae6402011-03-09 20:57:10 +0100120 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */
121 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */
Hans de Goedec11bb992011-03-09 20:57:15 +0100122 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71869 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100123 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */
124 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100125 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889ed */
Hans de Goede0bae6402011-03-09 20:57:10 +0100126 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */
127};
128
Hans de Goedec11bb992011-03-09 20:57:15 +0100129static const char f71882fg_has_in1_alarm[7] = {
Hans de Goede0bae6402011-03-09 20:57:10 +0100130 0, /* f71858fg */
131 0, /* f71862fg */
Hans de Goedec11bb992011-03-09 20:57:15 +0100132 0, /* f71869 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100133 1, /* f71882fg */
134 1, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100135 1, /* f71889ed */
Hans de Goede0bae6402011-03-09 20:57:10 +0100136 0, /* f8000 */
137};
138
Hans de Goedec11bb992011-03-09 20:57:15 +0100139static const char f71882fg_has_beep[7] = {
Hans de Goede78aa4f72011-03-09 20:57:12 +0100140 0, /* f71858fg */
141 1, /* f71862fg */
Hans de Goedec11bb992011-03-09 20:57:15 +0100142 1, /* f71869 */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100143 1, /* f71882fg */
144 1, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100145 1, /* f71889ed */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100146 0, /* f8000 */
147};
148
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100149static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200150
151/* Super-I/O Function prototypes */
152static inline int superio_inb(int base, int reg);
153static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400154static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200155static inline void superio_select(int base, int ld);
156static inline void superio_exit(int base);
157
Hans de Goede498be962009-01-07 16:37:28 +0100158struct f71882fg_sio_data {
159 enum chips type;
160};
161
Hans de Goede45fb3662007-07-13 14:34:19 +0200162struct f71882fg_data {
163 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100164 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700165 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200166
167 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200168 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200169 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100170 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200171 unsigned long last_updated; /* In jiffies */
172 unsigned long last_limits; /* In jiffies */
173
174 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100175 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200176 u8 in1_max;
177 u8 in_status;
178 u8 in_beep;
179 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100180 u16 fan_target[4];
181 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200182 u8 fan_status;
183 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100184 /* Note: all models have only 3 temperature channels, but on some
185 they are addressed as 0-2 and on others as 1-3, so for coding
186 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200187 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100188 u8 temp_ovt[4];
189 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100190 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100191 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200192 u8 temp_status;
193 u8 temp_beep;
194 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200195 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100196 u8 pwm[4];
197 u8 pwm_enable;
198 u8 pwm_auto_point_hyst[2];
199 u8 pwm_auto_point_mapping[4];
200 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100201 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200202};
203
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100204/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200205static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
206 char *buf);
207static ssize_t show_in_max(struct device *dev, struct device_attribute
208 *devattr, char *buf);
209static ssize_t store_in_max(struct device *dev, struct device_attribute
210 *devattr, const char *buf, size_t count);
211static ssize_t show_in_beep(struct device *dev, struct device_attribute
212 *devattr, char *buf);
213static ssize_t store_in_beep(struct device *dev, struct device_attribute
214 *devattr, const char *buf, size_t count);
215static ssize_t show_in_alarm(struct device *dev, struct device_attribute
216 *devattr, char *buf);
217/* Sysfs Fan */
218static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
219 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100220static ssize_t show_fan_full_speed(struct device *dev,
221 struct device_attribute *devattr, char *buf);
222static ssize_t store_fan_full_speed(struct device *dev,
223 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200224static ssize_t show_fan_beep(struct device *dev, struct device_attribute
225 *devattr, char *buf);
226static ssize_t store_fan_beep(struct device *dev, struct device_attribute
227 *devattr, const char *buf, size_t count);
228static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
229 *devattr, char *buf);
230/* Sysfs Temp */
231static ssize_t show_temp(struct device *dev, struct device_attribute
232 *devattr, char *buf);
233static ssize_t show_temp_max(struct device *dev, struct device_attribute
234 *devattr, char *buf);
235static ssize_t store_temp_max(struct device *dev, struct device_attribute
236 *devattr, const char *buf, size_t count);
237static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
238 *devattr, char *buf);
239static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
240 *devattr, const char *buf, size_t count);
241static ssize_t show_temp_crit(struct device *dev, struct device_attribute
242 *devattr, char *buf);
243static ssize_t store_temp_crit(struct device *dev, struct device_attribute
244 *devattr, const char *buf, size_t count);
245static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
246 *devattr, char *buf);
247static ssize_t show_temp_type(struct device *dev, struct device_attribute
248 *devattr, char *buf);
249static ssize_t show_temp_beep(struct device *dev, struct device_attribute
250 *devattr, char *buf);
251static ssize_t store_temp_beep(struct device *dev, struct device_attribute
252 *devattr, const char *buf, size_t count);
253static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
254 *devattr, char *buf);
255static ssize_t show_temp_fault(struct device *dev, struct device_attribute
256 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100257/* PWM and Auto point control */
258static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
259 char *buf);
260static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
261 const char *buf, size_t count);
262static ssize_t show_pwm_enable(struct device *dev,
263 struct device_attribute *devattr, char *buf);
264static ssize_t store_pwm_enable(struct device *dev,
265 struct device_attribute *devattr, const char *buf, size_t count);
266static ssize_t show_pwm_interpolate(struct device *dev,
267 struct device_attribute *devattr, char *buf);
268static ssize_t store_pwm_interpolate(struct device *dev,
269 struct device_attribute *devattr, const char *buf, size_t count);
270static ssize_t show_pwm_auto_point_channel(struct device *dev,
271 struct device_attribute *devattr, char *buf);
272static ssize_t store_pwm_auto_point_channel(struct device *dev,
273 struct device_attribute *devattr, const char *buf, size_t count);
274static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
275 struct device_attribute *devattr, char *buf);
276static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
277 struct device_attribute *devattr, const char *buf, size_t count);
278static ssize_t show_pwm_auto_point_pwm(struct device *dev,
279 struct device_attribute *devattr, char *buf);
280static ssize_t store_pwm_auto_point_pwm(struct device *dev,
281 struct device_attribute *devattr, const char *buf, size_t count);
282static ssize_t show_pwm_auto_point_temp(struct device *dev,
283 struct device_attribute *devattr, char *buf);
284static ssize_t store_pwm_auto_point_temp(struct device *dev,
285 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200286/* Sysfs misc */
287static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
288 char *buf);
289
290static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100291static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200292
293static struct platform_driver f71882fg_driver = {
294 .driver = {
295 .owner = THIS_MODULE,
296 .name = DRVNAME,
297 },
298 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200299 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200300};
301
Hans de Goedec13548c2009-01-07 16:37:27 +0100302static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200303
Hans de Goede0bae6402011-03-09 20:57:10 +0100304/* Temp attr for the f71858fg, the f71858fg is special as it has its
305 temperature indexes start at 0 (the others start at 1) */
306static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200307 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
308 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
309 store_temp_max, 0, 0),
310 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
311 store_temp_max_hyst, 0, 0),
312 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
313 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
314 store_temp_crit, 0, 0),
315 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
316 0, 0),
317 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
318 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
319 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
320 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
321 store_temp_max, 0, 1),
322 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
323 store_temp_max_hyst, 0, 1),
324 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
325 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
326 store_temp_crit, 0, 1),
327 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
328 0, 1),
329 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200330 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
331 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
332 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
333 store_temp_max, 0, 2),
334 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
335 store_temp_max_hyst, 0, 2),
336 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
337 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
338 store_temp_crit, 0, 2),
339 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
340 0, 2),
341 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
342 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
343};
344
Hans de Goede0bae6402011-03-09 20:57:10 +0100345/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100346static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100347 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100348 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100349 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100350 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100351 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100352 /* Should really be temp1_max_alarm, but older versions did not handle
353 the max and crit alarms separately and lm_sensors v2 depends on the
354 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
355 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100357 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100358 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100359 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100360 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100361 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100362 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100363}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100364 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
365 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100366 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100368 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100369 /* Should be temp2_max_alarm, see temp1_alarm note */
370 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100371 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100372 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100373 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100374 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100375 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100376 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100377 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100378}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100379 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
380 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
381 store_temp_max, 0, 3),
382 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
383 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100384 /* Should be temp3_max_alarm, see temp1_alarm note */
385 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100386 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
387 store_temp_crit, 0, 3),
388 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
389 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100390 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100391 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100392 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100393} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200394
Hans de Goede78aa4f72011-03-09 20:57:12 +0100395/* Temp attr for models which can beep on temp alarm */
396static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
397 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
398 store_temp_beep, 0, 1),
399 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
400 store_temp_beep, 0, 5),
401}, {
402 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
403 store_temp_beep, 0, 2),
404 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
405 store_temp_beep, 0, 6),
406}, {
407 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
408 store_temp_beep, 0, 3),
409 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
410 store_temp_beep, 0, 7),
411} };
412
Hans de Goede0bae6402011-03-09 20:57:10 +0100413/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100414 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
415 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100416 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100417 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100418static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100419 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
420 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
421 store_temp_crit, 0, 0),
422 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
423 store_temp_max, 0, 0),
424 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200425 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100426 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
427 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
428 store_temp_crit, 0, 1),
429 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
430 store_temp_max, 0, 1),
431 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200432 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100433 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
434 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
435 store_temp_crit, 0, 2),
436 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
437 store_temp_max, 0, 2),
438 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200439 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100440};
441
Hans de Goede0bae6402011-03-09 20:57:10 +0100442/* in attr for all models */
443static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
444 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
445 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
446 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
447 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
448 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
449 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
450 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
451 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
452 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
453};
454
455/* For models with in1 alarm capability */
456static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
457 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
458 0, 1),
459 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
460 0, 1),
461 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
462};
463
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100464/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100465static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100466 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100467 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
468 show_fan_full_speed,
469 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100470 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100471 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
472 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
473 store_pwm_enable, 0, 0),
474 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
475 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100476}, {
477 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
478 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
479 show_fan_full_speed,
480 store_fan_full_speed, 0, 1),
481 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100482 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
483 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
484 store_pwm_enable, 0, 1),
485 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
486 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100487}, {
488 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
489 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
490 show_fan_full_speed,
491 store_fan_full_speed, 0, 2),
492 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200493 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
494 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
495 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100496 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
497 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100498}, {
499 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
500 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
501 show_fan_full_speed,
502 store_fan_full_speed, 0, 3),
503 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
504 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
505 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
506 store_pwm_enable, 0, 3),
507 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
508 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
509} };
Hans de Goede498be962009-01-07 16:37:28 +0100510
Hans de Goede66344aa2009-12-09 20:35:59 +0100511/* Attr for models which can beep on Fan alarm */
512static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100513 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
514 store_fan_beep, 0, 0),
515 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
516 store_fan_beep, 0, 1),
517 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
518 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100519 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
520 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100521};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100522
Hans de Goede66344aa2009-12-09 20:35:59 +0100523/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100524 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100525static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
526 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_channel,
528 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100529 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 1, 0),
532 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
534 4, 0),
535 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 0, 0),
538 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
540 3, 0),
541 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp_hyst,
543 store_pwm_auto_point_temp_hyst,
544 0, 0),
545 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
546 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
547
Hans de Goede66344aa2009-12-09 20:35:59 +0100548 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
549 show_pwm_auto_point_channel,
550 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100551 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
553 1, 1),
554 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
556 4, 1),
557 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
559 0, 1),
560 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
562 3, 1),
563 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_temp_hyst,
565 store_pwm_auto_point_temp_hyst,
566 0, 1),
567 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
568 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100569
Hans de Goede66344aa2009-12-09 20:35:59 +0100570 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
571 show_pwm_auto_point_channel,
572 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100573 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
574 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
575 1, 2),
576 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
577 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
578 4, 2),
579 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
580 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
581 0, 2),
582 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
583 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
584 3, 2),
585 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
586 show_pwm_auto_point_temp_hyst,
587 store_pwm_auto_point_temp_hyst,
588 0, 2),
589 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100591};
592
Hans de Goedec11bb992011-03-09 20:57:15 +0100593/* PWM attr for the f71869, almost identical to the f71862fg, but the
594 pwm setting when the temperature is above the pwmX_auto_point1_temp can be
595 programmed instead of being hardcoded to 0xff */
596static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
597 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
598 show_pwm_auto_point_channel,
599 store_pwm_auto_point_channel, 0, 0),
600 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
601 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
602 0, 0),
603 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
604 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
605 1, 0),
606 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
607 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
608 4, 0),
609 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
610 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
611 0, 0),
612 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
613 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
614 3, 0),
615 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
616 show_pwm_auto_point_temp_hyst,
617 store_pwm_auto_point_temp_hyst,
618 0, 0),
619 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
620 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
621
622 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_channel,
624 store_pwm_auto_point_channel, 0, 1),
625 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
626 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
627 0, 1),
628 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
629 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
630 1, 1),
631 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
633 4, 1),
634 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
636 0, 1),
637 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
639 3, 1),
640 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp_hyst,
642 store_pwm_auto_point_temp_hyst,
643 0, 1),
644 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
645 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
646
647 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
648 show_pwm_auto_point_channel,
649 store_pwm_auto_point_channel, 0, 2),
650 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
651 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
652 0, 2),
653 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
654 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
655 1, 2),
656 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
658 4, 2),
659 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
661 0, 2),
662 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
664 3, 2),
665 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp_hyst,
667 store_pwm_auto_point_temp_hyst,
668 0, 2),
669 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
671};
672
Hans de Goede3cad4022011-03-09 20:57:14 +0100673/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100674static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100675 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_channel,
677 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100678 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 0, 0),
681 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 1, 0),
684 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 2, 0),
687 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
689 3, 0),
690 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
692 4, 0),
693 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
695 0, 0),
696 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
698 1, 0),
699 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
701 2, 0),
702 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
704 3, 0),
705 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_temp_hyst,
707 store_pwm_auto_point_temp_hyst,
708 0, 0),
709 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
710 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
711 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
712 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
713 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
714 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100715}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100716 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_channel,
718 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100719 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
721 0, 1),
722 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
724 1, 1),
725 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
727 2, 1),
728 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 3, 1),
731 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 4, 1),
734 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
736 0, 1),
737 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
739 1, 1),
740 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
742 2, 1),
743 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
745 3, 1),
746 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_temp_hyst,
748 store_pwm_auto_point_temp_hyst,
749 0, 1),
750 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
751 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
752 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
753 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
754 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
755 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100756}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100757 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_channel,
759 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100760 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
761 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
762 0, 2),
763 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
764 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
765 1, 2),
766 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
768 2, 2),
769 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
771 3, 2),
772 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
774 4, 2),
775 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
777 0, 2),
778 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
780 1, 2),
781 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
783 2, 2),
784 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
785 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
786 3, 2),
787 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_temp_hyst,
789 store_pwm_auto_point_temp_hyst,
790 0, 2),
791 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
792 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
793 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
794 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
795 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
796 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100797}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100798 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
799 show_pwm_auto_point_channel,
800 store_pwm_auto_point_channel, 0, 3),
801 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
802 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
803 0, 3),
804 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
805 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
806 1, 3),
807 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
809 2, 3),
810 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
812 3, 3),
813 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
815 4, 3),
816 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
818 0, 3),
819 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
821 1, 3),
822 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
823 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
824 2, 3),
825 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
826 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
827 3, 3),
828 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_temp_hyst,
830 store_pwm_auto_point_temp_hyst,
831 0, 3),
832 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
833 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
834 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
835 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
836 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
837 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100838} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200839
Hans de Goede66344aa2009-12-09 20:35:59 +0100840/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100841static struct sensor_device_attribute_2 f8000_fan_attr[] = {
842 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100843};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100844
Hans de Goede66344aa2009-12-09 20:35:59 +0100845/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
846 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
847 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
848static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
849 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_channel,
851 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100852 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
854 0, 2),
855 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
857 1, 2),
858 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
860 2, 2),
861 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
863 3, 2),
864 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
866 4, 2),
867 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
869 0, 2),
870 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
872 1, 2),
873 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
875 2, 2),
876 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
877 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
878 3, 2),
879 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
880 show_pwm_auto_point_temp_hyst,
881 store_pwm_auto_point_temp_hyst,
882 0, 2),
883 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
884 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
885 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
886 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
887 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
888 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
889
Hans de Goede66344aa2009-12-09 20:35:59 +0100890 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
891 show_pwm_auto_point_channel,
892 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100893 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
894 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
895 0, 0),
896 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
897 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
898 1, 0),
899 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
900 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
901 2, 0),
902 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
903 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
904 3, 0),
905 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
906 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
907 4, 0),
908 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
909 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
910 0, 0),
911 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
912 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
913 1, 0),
914 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
915 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
916 2, 0),
917 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
918 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
919 3, 0),
920 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
921 show_pwm_auto_point_temp_hyst,
922 store_pwm_auto_point_temp_hyst,
923 0, 0),
924 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
925 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
926 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
927 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
928 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
929 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
930
Hans de Goede66344aa2009-12-09 20:35:59 +0100931 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
932 show_pwm_auto_point_channel,
933 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100934 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
935 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
936 0, 1),
937 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
938 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
939 1, 1),
940 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
941 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
942 2, 1),
943 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
944 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
945 3, 1),
946 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
947 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
948 4, 1),
949 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
950 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
951 0, 1),
952 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
953 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
954 1, 1),
955 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
956 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
957 2, 1),
958 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
959 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
960 3, 1),
961 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
962 show_pwm_auto_point_temp_hyst,
963 store_pwm_auto_point_temp_hyst,
964 0, 1),
965 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
966 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
967 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
968 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
969 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
970 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
971};
Hans de Goede45fb3662007-07-13 14:34:19 +0200972
973/* Super I/O functions */
974static inline int superio_inb(int base, int reg)
975{
976 outb(reg, base);
977 return inb(base + 1);
978}
979
980static int superio_inw(int base, int reg)
981{
982 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200983 val = superio_inb(base, reg) << 8;
984 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200985 return val;
986}
987
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400988static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200989{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400990 /* Don't step on other drivers' I/O space by accident */
991 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000992 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400993 return -EBUSY;
994 }
995
Hans de Goede45fb3662007-07-13 14:34:19 +0200996 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200997 outb(SIO_UNLOCK_KEY, base);
998 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400999
1000 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001001}
1002
Giel van Schijndel162bb592010-05-27 19:58:40 +02001003static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001004{
1005 outb(SIO_REG_LDSEL, base);
1006 outb(ld, base + 1);
1007}
1008
1009static inline void superio_exit(int base)
1010{
1011 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001012 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001013}
1014
Hans de Goede2f650632009-01-07 16:37:31 +01001015static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001016{
1017 return reg ? (1500000 / reg) : 0;
1018}
1019
Hans de Goede2f650632009-01-07 16:37:31 +01001020static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001021{
1022 return fan ? (1500000 / fan) : 0;
1023}
1024
Hans de Goede45fb3662007-07-13 14:34:19 +02001025static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1026{
1027 u8 val;
1028
1029 outb(reg, data->addr + ADDR_REG_OFFSET);
1030 val = inb(data->addr + DATA_REG_OFFSET);
1031
1032 return val;
1033}
1034
1035static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1036{
1037 u16 val;
1038
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001039 val = f71882fg_read8(data, reg) << 8;
1040 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001041
1042 return val;
1043}
1044
1045static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1046{
1047 outb(reg, data->addr + ADDR_REG_OFFSET);
1048 outb(val, data->addr + DATA_REG_OFFSET);
1049}
1050
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001051static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1052{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001053 f71882fg_write8(data, reg, val >> 8);
1054 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001055}
1056
Hans de Goede09475d32009-06-15 18:39:52 +02001057static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1058{
1059 if (data->type == f71858fg)
1060 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1061 else
1062 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1063}
1064
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001065static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001066{
1067 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001068 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001069 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001070
1071 mutex_lock(&data->update_lock);
1072
1073 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001074 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001075 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001076 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001077 data->in1_max =
1078 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1079 data->in_beep =
1080 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1081 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001082
1083 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +02001084 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001085 data->temp_ovt[nr] = f71882fg_read8(data,
1086 F71882FG_REG_TEMP_OVT(nr));
1087 data->temp_high[nr] = f71882fg_read8(data,
1088 F71882FG_REG_TEMP_HIGH(nr));
1089 }
1090
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001091 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001092 data->temp_hyst[0] = f71882fg_read8(data,
1093 F71882FG_REG_TEMP_HYST(0));
1094 data->temp_hyst[1] = f71882fg_read8(data,
1095 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001096 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001097 /* All but the f71858fg / f8000 have this register */
1098 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001099 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001100 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001101 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1102 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1103 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001104
Hans de Goede78aa4f72011-03-09 20:57:12 +01001105 if (f71882fg_has_beep[data->type]) {
1106 data->fan_beep = f71882fg_read8(data,
1107 F71882FG_REG_FAN_BEEP);
1108 data->temp_beep = f71882fg_read8(data,
1109 F71882FG_REG_TEMP_BEEP);
1110 }
1111
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001112 data->pwm_enable = f71882fg_read8(data,
1113 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001114 data->pwm_auto_point_hyst[0] =
1115 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1116 data->pwm_auto_point_hyst[1] =
1117 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1118
Hans de Goede498be962009-01-07 16:37:28 +01001119 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001120 data->pwm_auto_point_mapping[nr] =
1121 f71882fg_read8(data,
1122 F71882FG_REG_POINT_MAPPING(nr));
1123
Hans de Goedec11bb992011-03-09 20:57:15 +01001124 if (data->type != f71862fg && data->type != f71869) {
Hans de Goede498be962009-01-07 16:37:28 +01001125 int point;
1126 for (point = 0; point < 5; point++) {
1127 data->pwm_auto_point_pwm[nr][point] =
1128 f71882fg_read8(data,
1129 F71882FG_REG_POINT_PWM
1130 (nr, point));
1131 }
1132 for (point = 0; point < 4; point++) {
1133 data->pwm_auto_point_temp[nr][point] =
1134 f71882fg_read8(data,
1135 F71882FG_REG_POINT_TEMP
1136 (nr, point));
1137 }
1138 } else {
Hans de Goedec11bb992011-03-09 20:57:15 +01001139 if (data->type == f71869) {
1140 data->pwm_auto_point_pwm[nr][0] =
1141 f71882fg_read8(data,
1142 F71882FG_REG_POINT_PWM
1143 (nr, 0));
1144 }
Hans de Goede498be962009-01-07 16:37:28 +01001145 data->pwm_auto_point_pwm[nr][1] =
1146 f71882fg_read8(data,
1147 F71882FG_REG_POINT_PWM
1148 (nr, 1));
1149 data->pwm_auto_point_pwm[nr][4] =
1150 f71882fg_read8(data,
1151 F71882FG_REG_POINT_PWM
1152 (nr, 4));
1153 data->pwm_auto_point_temp[nr][0] =
1154 f71882fg_read8(data,
1155 F71882FG_REG_POINT_TEMP
1156 (nr, 0));
1157 data->pwm_auto_point_temp[nr][3] =
1158 f71882fg_read8(data,
1159 F71882FG_REG_POINT_TEMP
1160 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001161 }
1162 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001163 data->last_limits = jiffies;
1164 }
1165
1166 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001167 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001168 data->temp_status = f71882fg_read8(data,
1169 F71882FG_REG_TEMP_STATUS);
1170 data->temp_diode_open = f71882fg_read8(data,
1171 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001172 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1173 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001174
1175 data->fan_status = f71882fg_read8(data,
1176 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001177 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001178 data->fan[nr] = f71882fg_read16(data,
1179 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001180 data->fan_target[nr] =
1181 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1182 data->fan_full_speed[nr] =
1183 f71882fg_read16(data,
1184 F71882FG_REG_FAN_FULL_SPEED(nr));
1185 data->pwm[nr] =
1186 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1187 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001188 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1189 if (data->type == f8000)
1190 data->fan[3] = f71882fg_read16(data,
1191 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001192
1193 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001194 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001195 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001196 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1197 if (f71882fg_has_in[data->type][nr])
1198 data->in[nr] = f71882fg_read8(data,
1199 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001200
1201 data->last_updated = jiffies;
1202 data->valid = 1;
1203 }
1204
1205 mutex_unlock(&data->update_lock);
1206
1207 return data;
1208}
1209
1210/* Sysfs Interface */
1211static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1212 char *buf)
1213{
1214 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001215 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001216 int speed = fan_from_reg(data->fan[nr]);
1217
1218 if (speed == FAN_MIN_DETECT)
1219 speed = 0;
1220
1221 return sprintf(buf, "%d\n", speed);
1222}
1223
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001224static ssize_t show_fan_full_speed(struct device *dev,
1225 struct device_attribute *devattr, char *buf)
1226{
1227 struct f71882fg_data *data = f71882fg_update_device(dev);
1228 int nr = to_sensor_dev_attr_2(devattr)->index;
1229 int speed = fan_from_reg(data->fan_full_speed[nr]);
1230 return sprintf(buf, "%d\n", speed);
1231}
1232
1233static ssize_t store_fan_full_speed(struct device *dev,
1234 struct device_attribute *devattr,
1235 const char *buf, size_t count)
1236{
1237 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001238 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1239 long val;
1240
1241 err = strict_strtol(buf, 10, &val);
1242 if (err)
1243 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001244
1245 val = SENSORS_LIMIT(val, 23, 1500000);
1246 val = fan_to_reg(val);
1247
1248 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001249 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1250 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001251 mutex_unlock(&data->update_lock);
1252
1253 return count;
1254}
1255
Hans de Goede45fb3662007-07-13 14:34:19 +02001256static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1257 *devattr, char *buf)
1258{
1259 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001260 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001261
1262 if (data->fan_beep & (1 << nr))
1263 return sprintf(buf, "1\n");
1264 else
1265 return sprintf(buf, "0\n");
1266}
1267
1268static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1269 *devattr, const char *buf, size_t count)
1270{
1271 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001272 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1273 unsigned long val;
1274
1275 err = strict_strtoul(buf, 10, &val);
1276 if (err)
1277 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001278
1279 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001280 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001281 if (val)
1282 data->fan_beep |= 1 << nr;
1283 else
1284 data->fan_beep &= ~(1 << nr);
1285
1286 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1287 mutex_unlock(&data->update_lock);
1288
1289 return count;
1290}
1291
1292static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1293 *devattr, char *buf)
1294{
1295 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001296 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001297
1298 if (data->fan_status & (1 << nr))
1299 return sprintf(buf, "1\n");
1300 else
1301 return sprintf(buf, "0\n");
1302}
1303
1304static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1305 char *buf)
1306{
1307 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001308 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001309
1310 return sprintf(buf, "%d\n", data->in[nr] * 8);
1311}
1312
1313static ssize_t show_in_max(struct device *dev, struct device_attribute
1314 *devattr, char *buf)
1315{
1316 struct f71882fg_data *data = f71882fg_update_device(dev);
1317
1318 return sprintf(buf, "%d\n", data->in1_max * 8);
1319}
1320
1321static ssize_t store_in_max(struct device *dev, struct device_attribute
1322 *devattr, const char *buf, size_t count)
1323{
1324 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001325 int err;
1326 long val;
1327
1328 err = strict_strtol(buf, 10, &val);
1329 if (err)
1330 return err;
1331
1332 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001333 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001334
1335 mutex_lock(&data->update_lock);
1336 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1337 data->in1_max = val;
1338 mutex_unlock(&data->update_lock);
1339
1340 return count;
1341}
1342
1343static ssize_t show_in_beep(struct device *dev, struct device_attribute
1344 *devattr, char *buf)
1345{
1346 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001347 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001348
1349 if (data->in_beep & (1 << nr))
1350 return sprintf(buf, "1\n");
1351 else
1352 return sprintf(buf, "0\n");
1353}
1354
1355static ssize_t store_in_beep(struct device *dev, struct device_attribute
1356 *devattr, const char *buf, size_t count)
1357{
1358 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001359 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1360 unsigned long val;
1361
1362 err = strict_strtoul(buf, 10, &val);
1363 if (err)
1364 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001365
1366 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001367 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001368 if (val)
1369 data->in_beep |= 1 << nr;
1370 else
1371 data->in_beep &= ~(1 << nr);
1372
1373 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1374 mutex_unlock(&data->update_lock);
1375
1376 return count;
1377}
1378
1379static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1380 *devattr, char *buf)
1381{
1382 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001383 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001384
1385 if (data->in_status & (1 << nr))
1386 return sprintf(buf, "1\n");
1387 else
1388 return sprintf(buf, "0\n");
1389}
1390
1391static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1392 char *buf)
1393{
1394 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001395 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001396 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001397
Hans de Goede09475d32009-06-15 18:39:52 +02001398 if (data->type == f71858fg) {
1399 /* TEMP_TABLE_SEL 1 or 3 ? */
1400 if (data->temp_config & 1) {
1401 sign = data->temp[nr] & 0x0001;
1402 temp = (data->temp[nr] >> 5) & 0x7ff;
1403 } else {
1404 sign = data->temp[nr] & 0x8000;
1405 temp = (data->temp[nr] >> 5) & 0x3ff;
1406 }
1407 temp *= 125;
1408 if (sign)
1409 temp -= 128000;
1410 } else
1411 temp = data->temp[nr] * 1000;
1412
1413 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001414}
1415
1416static ssize_t show_temp_max(struct device *dev, struct device_attribute
1417 *devattr, char *buf)
1418{
1419 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001420 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001421
1422 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1423}
1424
1425static ssize_t store_temp_max(struct device *dev, struct device_attribute
1426 *devattr, const char *buf, size_t count)
1427{
1428 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001429 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1430 long val;
1431
1432 err = strict_strtol(buf, 10, &val);
1433 if (err)
1434 return err;
1435
1436 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001437 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001438
1439 mutex_lock(&data->update_lock);
1440 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1441 data->temp_high[nr] = val;
1442 mutex_unlock(&data->update_lock);
1443
1444 return count;
1445}
1446
1447static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1448 *devattr, char *buf)
1449{
1450 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001451 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001452 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001453
Hans de Goedece0bfa52009-01-07 16:37:28 +01001454 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001455 if (nr & 1)
1456 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1457 else
1458 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1459 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001460 mutex_unlock(&data->update_lock);
1461
1462 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001463}
1464
1465static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1466 *devattr, const char *buf, size_t count)
1467{
1468 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001469 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001470 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001471 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001472 long val;
1473
1474 err = strict_strtol(buf, 10, &val);
1475 if (err)
1476 return err;
1477
1478 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001479
1480 mutex_lock(&data->update_lock);
1481
1482 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001483 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1484 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1485 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001486 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001487
1488 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001489 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1490 if (nr & 1)
1491 reg = (reg & 0x0f) | (val << 4);
1492 else
1493 reg = (reg & 0xf0) | val;
1494 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1495 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001496
Hans de Goede45fb3662007-07-13 14:34:19 +02001497 mutex_unlock(&data->update_lock);
1498 return ret;
1499}
1500
1501static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1502 *devattr, char *buf)
1503{
1504 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001505 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001506
1507 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1508}
1509
1510static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1511 *devattr, const char *buf, size_t count)
1512{
1513 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001514 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1515 long val;
1516
1517 err = strict_strtol(buf, 10, &val);
1518 if (err)
1519 return err;
1520
1521 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001522 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001523
1524 mutex_lock(&data->update_lock);
1525 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1526 data->temp_ovt[nr] = val;
1527 mutex_unlock(&data->update_lock);
1528
1529 return count;
1530}
1531
1532static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1533 *devattr, char *buf)
1534{
1535 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001536 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001537 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001538
Hans de Goedece0bfa52009-01-07 16:37:28 +01001539 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001540 if (nr & 1)
1541 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1542 else
1543 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1544 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001545 mutex_unlock(&data->update_lock);
1546
1547 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001548}
1549
1550static ssize_t show_temp_type(struct device *dev, struct device_attribute
1551 *devattr, char *buf)
1552{
1553 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001554 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001555
1556 return sprintf(buf, "%d\n", data->temp_type[nr]);
1557}
1558
1559static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1560 *devattr, char *buf)
1561{
1562 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001563 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001564
Hans de Goede7567a042009-01-07 16:37:28 +01001565 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001566 return sprintf(buf, "1\n");
1567 else
1568 return sprintf(buf, "0\n");
1569}
1570
1571static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1572 *devattr, const char *buf, size_t count)
1573{
1574 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001575 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1576 unsigned long val;
1577
1578 err = strict_strtoul(buf, 10, &val);
1579 if (err)
1580 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001581
1582 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001583 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001584 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001585 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001586 else
Hans de Goede7567a042009-01-07 16:37:28 +01001587 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001588
1589 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1590 mutex_unlock(&data->update_lock);
1591
1592 return count;
1593}
1594
1595static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1596 *devattr, char *buf)
1597{
1598 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001599 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001600
Hans de Goede7567a042009-01-07 16:37:28 +01001601 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001602 return sprintf(buf, "1\n");
1603 else
1604 return sprintf(buf, "0\n");
1605}
1606
1607static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1608 *devattr, char *buf)
1609{
1610 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001611 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001612
Hans de Goede7567a042009-01-07 16:37:28 +01001613 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001614 return sprintf(buf, "1\n");
1615 else
1616 return sprintf(buf, "0\n");
1617}
1618
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001619static ssize_t show_pwm(struct device *dev,
1620 struct device_attribute *devattr, char *buf)
1621{
1622 struct f71882fg_data *data = f71882fg_update_device(dev);
1623 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001624 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001625 if (data->pwm_enable & (1 << (2 * nr)))
1626 /* PWM mode */
1627 val = data->pwm[nr];
1628 else {
1629 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001630 val = 255 * fan_from_reg(data->fan_target[nr])
1631 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001632 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001633 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001634 return sprintf(buf, "%d\n", val);
1635}
1636
1637static ssize_t store_pwm(struct device *dev,
1638 struct device_attribute *devattr, const char *buf,
1639 size_t count)
1640{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001641 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001642 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1643 long val;
1644
1645 err = strict_strtol(buf, 10, &val);
1646 if (err)
1647 return err;
1648
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001649 val = SENSORS_LIMIT(val, 0, 255);
1650
1651 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001652 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001653 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1654 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1655 count = -EROFS;
1656 goto leave;
1657 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001658 if (data->pwm_enable & (1 << (2 * nr))) {
1659 /* PWM mode */
1660 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1661 data->pwm[nr] = val;
1662 } else {
1663 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001664 int target, full_speed;
1665 full_speed = f71882fg_read16(data,
1666 F71882FG_REG_FAN_FULL_SPEED(nr));
1667 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1668 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1669 data->fan_target[nr] = target;
1670 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001671 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001672leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001673 mutex_unlock(&data->update_lock);
1674
1675 return count;
1676}
1677
1678static ssize_t show_pwm_enable(struct device *dev,
1679 struct device_attribute *devattr, char *buf)
1680{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001681 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001682 struct f71882fg_data *data = f71882fg_update_device(dev);
1683 int nr = to_sensor_dev_attr_2(devattr)->index;
1684
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001685 switch ((data->pwm_enable >> 2 * nr) & 3) {
1686 case 0:
1687 case 1:
1688 result = 2; /* Normal auto mode */
1689 break;
1690 case 2:
1691 result = 1; /* Manual mode */
1692 break;
1693 case 3:
1694 if (data->type == f8000)
1695 result = 3; /* Thermostat mode */
1696 else
1697 result = 1; /* Manual mode */
1698 break;
1699 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001700
1701 return sprintf(buf, "%d\n", result);
1702}
1703
1704static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1705 *devattr, const char *buf, size_t count)
1706{
1707 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001708 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1709 long val;
1710
1711 err = strict_strtol(buf, 10, &val);
1712 if (err)
1713 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001714
Hans de Goede3fc78382009-06-15 18:39:50 +02001715 /* Special case for F8000 pwm channel 3 which only does auto mode */
1716 if (data->type == f8000 && nr == 2 && val != 2)
1717 return -EINVAL;
1718
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001719 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001720 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001721 /* Special case for F8000 auto PWM mode / Thermostat mode */
1722 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1723 switch (val) {
1724 case 2:
1725 data->pwm_enable &= ~(2 << (2 * nr));
1726 break; /* Normal auto mode */
1727 case 3:
1728 data->pwm_enable |= 2 << (2 * nr);
1729 break; /* Thermostat mode */
1730 default:
1731 count = -EINVAL;
1732 goto leave;
1733 }
1734 } else {
1735 switch (val) {
1736 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001737 /* The f71858fg does not support manual RPM mode */
1738 if (data->type == f71858fg &&
1739 ((data->pwm_enable >> (2 * nr)) & 1)) {
1740 count = -EINVAL;
1741 goto leave;
1742 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001743 data->pwm_enable |= 2 << (2 * nr);
1744 break; /* Manual */
1745 case 2:
1746 data->pwm_enable &= ~(2 << (2 * nr));
1747 break; /* Normal auto mode */
1748 default:
1749 count = -EINVAL;
1750 goto leave;
1751 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001752 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001753 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001754leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001755 mutex_unlock(&data->update_lock);
1756
1757 return count;
1758}
1759
1760static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1761 struct device_attribute *devattr,
1762 char *buf)
1763{
1764 int result;
1765 struct f71882fg_data *data = f71882fg_update_device(dev);
1766 int pwm = to_sensor_dev_attr_2(devattr)->index;
1767 int point = to_sensor_dev_attr_2(devattr)->nr;
1768
Hans de Goedece0bfa52009-01-07 16:37:28 +01001769 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001770 if (data->pwm_enable & (1 << (2 * pwm))) {
1771 /* PWM mode */
1772 result = data->pwm_auto_point_pwm[pwm][point];
1773 } else {
1774 /* RPM mode */
1775 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1776 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001777 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001778
1779 return sprintf(buf, "%d\n", result);
1780}
1781
1782static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1783 struct device_attribute *devattr,
1784 const char *buf, size_t count)
1785{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001786 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001787 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001788 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001789 long val;
1790
1791 err = strict_strtol(buf, 10, &val);
1792 if (err)
1793 return err;
1794
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001795 val = SENSORS_LIMIT(val, 0, 255);
1796
1797 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001798 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001799 if (data->pwm_enable & (1 << (2 * pwm))) {
1800 /* PWM mode */
1801 } else {
1802 /* RPM mode */
1803 if (val < 29) /* Prevent negative numbers */
1804 val = 255;
1805 else
1806 val = (255 - val) * 32 / val;
1807 }
1808 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1809 data->pwm_auto_point_pwm[pwm][point] = val;
1810 mutex_unlock(&data->update_lock);
1811
1812 return count;
1813}
1814
1815static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1816 struct device_attribute *devattr,
1817 char *buf)
1818{
1819 int result = 0;
1820 struct f71882fg_data *data = f71882fg_update_device(dev);
1821 int nr = to_sensor_dev_attr_2(devattr)->index;
1822 int point = to_sensor_dev_attr_2(devattr)->nr;
1823
1824 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001825 if (nr & 1)
1826 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1827 else
1828 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001829 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1830 mutex_unlock(&data->update_lock);
1831
1832 return sprintf(buf, "%d\n", result);
1833}
1834
1835static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1836 struct device_attribute *devattr,
1837 const char *buf, size_t count)
1838{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001839 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001840 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001842 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001843 long val;
1844
1845 err = strict_strtol(buf, 10, &val);
1846 if (err)
1847 return err;
1848
1849 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001850
1851 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001852 data->pwm_auto_point_temp[nr][point] =
1853 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001854 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1855 data->pwm_auto_point_temp[nr][point]);
1856 val = data->pwm_auto_point_temp[nr][point] - val;
1857
Hans de Goedebc274902009-01-07 16:37:29 +01001858 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1859 if (nr & 1)
1860 reg = (reg & 0x0f) | (val << 4);
1861 else
1862 reg = (reg & 0xf0) | val;
1863
1864 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1865 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001866 mutex_unlock(&data->update_lock);
1867
1868 return count;
1869}
1870
1871static ssize_t show_pwm_interpolate(struct device *dev,
1872 struct device_attribute *devattr, char *buf)
1873{
1874 int result;
1875 struct f71882fg_data *data = f71882fg_update_device(dev);
1876 int nr = to_sensor_dev_attr_2(devattr)->index;
1877
1878 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1879
1880 return sprintf(buf, "%d\n", result);
1881}
1882
1883static ssize_t store_pwm_interpolate(struct device *dev,
1884 struct device_attribute *devattr,
1885 const char *buf, size_t count)
1886{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001887 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001888 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1889 unsigned long val;
1890
1891 err = strict_strtoul(buf, 10, &val);
1892 if (err)
1893 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001894
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001895 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001896 data->pwm_auto_point_mapping[nr] =
1897 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001898 if (val)
1899 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1900 else
1901 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1902 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1903 data->pwm_auto_point_mapping[nr] = val;
1904 mutex_unlock(&data->update_lock);
1905
1906 return count;
1907}
1908
1909static ssize_t show_pwm_auto_point_channel(struct device *dev,
1910 struct device_attribute *devattr,
1911 char *buf)
1912{
1913 int result;
1914 struct f71882fg_data *data = f71882fg_update_device(dev);
1915 int nr = to_sensor_dev_attr_2(devattr)->index;
1916
Hans de Goede09475d32009-06-15 18:39:52 +02001917 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1918 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001919
1920 return sprintf(buf, "%d\n", result);
1921}
1922
1923static ssize_t store_pwm_auto_point_channel(struct device *dev,
1924 struct device_attribute *devattr,
1925 const char *buf, size_t count)
1926{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001927 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001928 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1929 long val;
1930
1931 err = strict_strtol(buf, 10, &val);
1932 if (err)
1933 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001934
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001935 switch (val) {
1936 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001937 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001938 break;
1939 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001940 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001941 break;
1942 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001943 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001944 break;
1945 default:
1946 return -EINVAL;
1947 }
Hans de Goede09475d32009-06-15 18:39:52 +02001948 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001949 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001950 data->pwm_auto_point_mapping[nr] =
1951 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001952 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1953 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1954 data->pwm_auto_point_mapping[nr] = val;
1955 mutex_unlock(&data->update_lock);
1956
1957 return count;
1958}
1959
1960static ssize_t show_pwm_auto_point_temp(struct device *dev,
1961 struct device_attribute *devattr,
1962 char *buf)
1963{
1964 int result;
1965 struct f71882fg_data *data = f71882fg_update_device(dev);
1966 int pwm = to_sensor_dev_attr_2(devattr)->index;
1967 int point = to_sensor_dev_attr_2(devattr)->nr;
1968
1969 result = data->pwm_auto_point_temp[pwm][point];
1970 return sprintf(buf, "%d\n", 1000 * result);
1971}
1972
1973static ssize_t store_pwm_auto_point_temp(struct device *dev,
1974 struct device_attribute *devattr,
1975 const char *buf, size_t count)
1976{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001977 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001978 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001979 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001980 long val;
1981
1982 err = strict_strtol(buf, 10, &val);
1983 if (err)
1984 return err;
1985
1986 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001987
Hans de Goede98f7ba12011-03-09 20:57:09 +01001988 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001989 val = SENSORS_LIMIT(val, -128, 127);
1990 else
1991 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001992
1993 mutex_lock(&data->update_lock);
1994 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1995 data->pwm_auto_point_temp[pwm][point] = val;
1996 mutex_unlock(&data->update_lock);
1997
1998 return count;
1999}
2000
Hans de Goede45fb3662007-07-13 14:34:19 +02002001static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2002 char *buf)
2003{
Hans de Goede498be962009-01-07 16:37:28 +01002004 struct f71882fg_data *data = dev_get_drvdata(dev);
2005 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002006}
2007
Hans de Goedec13548c2009-01-07 16:37:27 +01002008static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
2009 struct sensor_device_attribute_2 *attr, int count)
2010{
2011 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002012
Hans de Goedec13548c2009-01-07 16:37:27 +01002013 for (i = 0; i < count; i++) {
2014 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2015 if (err)
2016 return err;
2017 }
2018 return 0;
2019}
2020
Hans de Goedefc16c562009-12-09 20:36:01 +01002021static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2022 struct sensor_device_attribute_2 *attr, int count)
2023{
2024 int i;
2025
2026 for (i = 0; i < count; i++)
2027 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2028}
2029
Hans de Goedec13548c2009-01-07 16:37:27 +01002030static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002031{
2032 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01002033 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01002034 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01002035 int nr_temps = 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002036 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002037
Hans de Goedec13548c2009-01-07 16:37:27 +01002038 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
2039 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002040 return -ENOMEM;
2041
2042 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002043 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002044 data->temp_start =
2045 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002046 mutex_init(&data->update_lock);
2047 platform_set_drvdata(pdev, data);
2048
Hans de Goede3cc74752009-01-07 16:37:28 +01002049 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002050 if (start_reg & 0x04) {
2051 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
2052 err = -ENODEV;
2053 goto exit_free;
2054 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002055 if (!(start_reg & 0x03)) {
2056 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
2057 err = -ENODEV;
2058 goto exit_free;
2059 }
2060
Hans de Goede45fb3662007-07-13 14:34:19 +02002061 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002062 err = device_create_file(&pdev->dev, &dev_attr_name);
2063 if (err)
2064 goto exit_unregister_sysfs;
2065
Hans de Goedec13548c2009-01-07 16:37:27 +01002066 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002067 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002068 case f71858fg:
2069 data->temp_config =
2070 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2071 if (data->temp_config & 0x10)
2072 /* The f71858fg temperature alarms behave as
2073 the f8000 alarms in this mode */
2074 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002075 f8000_temp_attr,
2076 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002077 else
2078 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002079 f71858fg_temp_attr,
2080 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002081 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002082 case f8000:
2083 err = f71882fg_create_sysfs_files(pdev,
2084 f8000_temp_attr,
2085 ARRAY_SIZE(f8000_temp_attr));
2086 break;
2087 default:
2088 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002089 &fxxxx_temp_attr[0][0],
2090 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002091 }
2092 if (err)
2093 goto exit_unregister_sysfs;
2094
Hans de Goede78aa4f72011-03-09 20:57:12 +01002095 if (f71882fg_has_beep[data->type]) {
2096 err = f71882fg_create_sysfs_files(pdev,
2097 &fxxxx_temp_beep_attr[0][0],
2098 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2099 * nr_temps);
2100 if (err)
2101 goto exit_unregister_sysfs;
2102 }
2103
Hans de Goede0bae6402011-03-09 20:57:10 +01002104 for (i = 0; i < F71882FG_MAX_INS; i++) {
2105 if (f71882fg_has_in[data->type][i]) {
2106 err = device_create_file(&pdev->dev,
2107 &fxxxx_in_attr[i].dev_attr);
2108 if (err)
2109 goto exit_unregister_sysfs;
2110 }
2111 }
2112 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002113 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002114 fxxxx_in1_alarm_attr,
2115 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002116 if (err)
2117 goto exit_unregister_sysfs;
2118 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002119 }
2120
Hans de Goede45fb3662007-07-13 14:34:19 +02002121 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002122 switch (data->type) {
Hans de Goedec11bb992011-03-09 20:57:15 +01002123 case f71869:
2124 /* The f71869 always has signed auto point temps */
2125 data->auto_point_temp_signed = 1;
2126 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002127 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002128 case f71889ed:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002129 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2130 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2131 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002132 /* Ensure banked pwm registers point to right bank */
2133 reg &= ~F71882FG_FAN_PROG_SEL;
2134 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002135 break;
2136 default:
2137 break;
2138 }
2139
Hans de Goede996cadb2009-06-15 18:39:51 +02002140 data->pwm_enable =
2141 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2142
2143 /* Sanity check the pwm settings */
2144 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002145 case f71858fg:
2146 err = 0;
2147 for (i = 0; i < nr_fans; i++)
2148 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2149 err = 1;
2150 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002151 case f71862fg:
2152 err = (data->pwm_enable & 0x15) != 0x15;
2153 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002154 case f71869:
Hans de Goede996cadb2009-06-15 18:39:51 +02002155 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002156 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002157 case f71889ed:
Hans de Goede996cadb2009-06-15 18:39:51 +02002158 err = 0;
2159 break;
2160 case f8000:
2161 err = data->pwm_enable & 0x20;
2162 break;
2163 }
2164 if (err) {
2165 dev_err(&pdev->dev,
2166 "Invalid (reserved) pwm settings: 0x%02x\n",
2167 (unsigned int)data->pwm_enable);
2168 err = -ENODEV;
2169 goto exit_unregister_sysfs;
2170 }
2171
Hans de Goedeb69b0392009-12-09 20:36:00 +01002172 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2173 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002174 if (err)
2175 goto exit_unregister_sysfs;
2176
Hans de Goede78aa4f72011-03-09 20:57:12 +01002177 if (f71882fg_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002178 err = f71882fg_create_sysfs_files(pdev,
2179 fxxxx_fan_beep_attr, nr_fans);
2180 if (err)
2181 goto exit_unregister_sysfs;
2182 }
2183
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002184 switch (data->type) {
Hans de Goedec11bb992011-03-09 20:57:15 +01002185 case f71869:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002186 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002187 case f71889ed:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002188 for (i = 0; i < nr_fans; i++) {
2189 data->pwm_auto_point_mapping[i] =
2190 f71882fg_read8(data,
2191 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002192 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2193 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002194 break;
2195 }
2196 if (i != nr_fans) {
2197 dev_warn(&pdev->dev,
2198 "Auto pwm controlled by raw digital "
2199 "data, disabling pwm auto_point "
2200 "sysfs attributes\n");
2201 goto no_pwm_auto_point;
2202 }
2203 break;
2204 default:
2205 break;
2206 }
2207
2208 switch (data->type) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002209 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002210 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002211 f71862fg_auto_pwm_attr,
2212 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002213 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002214 case f71869:
2215 err = f71882fg_create_sysfs_files(pdev,
2216 f71869_auto_pwm_attr,
2217 ARRAY_SIZE(f71869_auto_pwm_attr));
2218 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002219 case f8000:
2220 err = f71882fg_create_sysfs_files(pdev,
2221 f8000_fan_attr,
2222 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002223 if (err)
2224 goto exit_unregister_sysfs;
2225 err = f71882fg_create_sysfs_files(pdev,
2226 f8000_auto_pwm_attr,
2227 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002228 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002229 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002230 err = f71882fg_create_sysfs_files(pdev,
2231 &fxxxx_auto_pwm_attr[0][0],
2232 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002233 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002234 if (err)
2235 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002236
Hans de Goedee48a7f12011-03-09 20:57:13 +01002237no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002238 for (i = 0; i < nr_fans; i++)
2239 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2240 (data->pwm_enable & (1 << 2 * i)) ?
2241 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002242 }
2243
Tony Jones1beeffe2007-08-20 13:46:20 -07002244 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2245 if (IS_ERR(data->hwmon_dev)) {
2246 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002247 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002248 goto exit_unregister_sysfs;
2249 }
2250
2251 return 0;
2252
2253exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002254 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002255 return err; /* f71882fg_remove() also frees our data */
2256exit_free:
2257 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002258 return err;
2259}
2260
Hans de Goedec13548c2009-01-07 16:37:27 +01002261static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002262{
Hans de Goede45fb3662007-07-13 14:34:19 +02002263 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002264 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01002265 int nr_temps = 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002266 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002267
Hans de Goedec13548c2009-01-07 16:37:27 +01002268 if (data->hwmon_dev)
2269 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002270
Hans de Goedec13548c2009-01-07 16:37:27 +01002271 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002272
Hans de Goedefc16c562009-12-09 20:36:01 +01002273 if (start_reg & 0x01) {
2274 switch (data->type) {
2275 case f71858fg:
2276 if (data->temp_config & 0x10)
2277 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002278 f8000_temp_attr,
2279 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002280 else
2281 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002282 f71858fg_temp_attr,
2283 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002284 break;
2285 case f8000:
2286 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002287 f8000_temp_attr,
2288 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002289 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002290 default:
2291 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002292 &fxxxx_temp_attr[0][0],
2293 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002294 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002295 if (f71882fg_has_beep[data->type]) {
2296 f71882fg_remove_sysfs_files(pdev,
2297 &fxxxx_temp_beep_attr[0][0],
2298 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2299 }
2300
Hans de Goede0bae6402011-03-09 20:57:10 +01002301 for (i = 0; i < F71882FG_MAX_INS; i++) {
2302 if (f71882fg_has_in[data->type][i]) {
2303 device_remove_file(&pdev->dev,
2304 &fxxxx_in_attr[i].dev_attr);
2305 }
2306 }
2307 if (f71882fg_has_in1_alarm[data->type]) {
2308 f71882fg_remove_sysfs_files(pdev,
2309 fxxxx_in1_alarm_attr,
2310 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002311 }
2312 }
Hans de Goede498be962009-01-07 16:37:28 +01002313
Hans de Goedefc16c562009-12-09 20:36:01 +01002314 if (start_reg & 0x02) {
2315 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2316 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002317
Hans de Goede78aa4f72011-03-09 20:57:12 +01002318 if (f71882fg_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002319 f71882fg_remove_sysfs_files(pdev,
2320 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002321 }
Hans de Goede498be962009-01-07 16:37:28 +01002322
Hans de Goedefc16c562009-12-09 20:36:01 +01002323 switch (data->type) {
2324 case f71862fg:
2325 f71882fg_remove_sysfs_files(pdev,
2326 f71862fg_auto_pwm_attr,
2327 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2328 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002329 case f71869:
2330 f71882fg_remove_sysfs_files(pdev,
2331 f71869_auto_pwm_attr,
2332 ARRAY_SIZE(f71869_auto_pwm_attr));
2333 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002334 case f8000:
2335 f71882fg_remove_sysfs_files(pdev,
2336 f8000_fan_attr,
2337 ARRAY_SIZE(f8000_fan_attr));
2338 f71882fg_remove_sysfs_files(pdev,
2339 f8000_auto_pwm_attr,
2340 ARRAY_SIZE(f8000_auto_pwm_attr));
2341 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002342 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002343 f71882fg_remove_sysfs_files(pdev,
2344 &fxxxx_auto_pwm_attr[0][0],
2345 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2346 }
2347 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002348
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002349 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002350 kfree(data);
2351
2352 return 0;
2353}
2354
Hans de Goede498be962009-01-07 16:37:28 +01002355static int __init f71882fg_find(int sioaddr, unsigned short *address,
2356 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002357{
Hans de Goede45fb3662007-07-13 14:34:19 +02002358 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002359 int err = superio_enter(sioaddr);
2360 if (err)
2361 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002362
2363 devid = superio_inw(sioaddr, SIO_REG_MANID);
2364 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002365 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002366 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002367 goto exit;
2368 }
2369
Jean Delvare67b671b2007-12-06 23:13:42 +01002370 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002371 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002372 case SIO_F71858_ID:
2373 sio_data->type = f71858fg;
2374 break;
Hans de Goede498be962009-01-07 16:37:28 +01002375 case SIO_F71862_ID:
2376 sio_data->type = f71862fg;
2377 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002378 case SIO_F71869_ID:
2379 sio_data->type = f71869;
2380 break;
Hans de Goede498be962009-01-07 16:37:28 +01002381 case SIO_F71882_ID:
2382 sio_data->type = f71882fg;
2383 break;
Hans de Goede76698962009-12-09 20:36:01 +01002384 case SIO_F71889_ID:
2385 sio_data->type = f71889fg;
2386 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002387 case SIO_F71889E_ID:
2388 sio_data->type = f71889ed;
2389 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002390 case SIO_F8000_ID:
2391 sio_data->type = f8000;
2392 break;
Hans de Goede498be962009-01-07 16:37:28 +01002393 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002394 pr_info("Unsupported Fintek device: %04x\n",
2395 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002396 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002397 goto exit;
2398 }
2399
Hans de Goede09475d32009-06-15 18:39:52 +02002400 if (sio_data->type == f71858fg)
2401 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2402 else
2403 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2404
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002405 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002406 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002407 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002408 goto exit;
2409 }
2410
2411 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002412 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002413 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002414 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002415 goto exit;
2416 }
2417 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2418
Hans de Goede45fb3662007-07-13 14:34:19 +02002419 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002420 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002421 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002422 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2423exit:
2424 superio_exit(sioaddr);
2425 return err;
2426}
2427
Hans de Goede498be962009-01-07 16:37:28 +01002428static int __init f71882fg_device_add(unsigned short address,
2429 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002430{
2431 struct resource res = {
2432 .start = address,
2433 .end = address + REGION_LENGTH - 1,
2434 .flags = IORESOURCE_IO,
2435 };
2436 int err;
2437
2438 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002439 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002440 return -ENOMEM;
2441
2442 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002443 err = acpi_check_resource_conflict(&res);
2444 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002445 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002446
Hans de Goede45fb3662007-07-13 14:34:19 +02002447 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002448 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002449 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002450 goto exit_device_put;
2451 }
2452
Hans de Goede498be962009-01-07 16:37:28 +01002453 err = platform_device_add_data(f71882fg_pdev, sio_data,
2454 sizeof(struct f71882fg_sio_data));
2455 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002456 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002457 goto exit_device_put;
2458 }
2459
Hans de Goede45fb3662007-07-13 14:34:19 +02002460 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002461 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002462 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002463 goto exit_device_put;
2464 }
2465
2466 return 0;
2467
2468exit_device_put:
2469 platform_device_put(f71882fg_pdev);
2470
2471 return err;
2472}
2473
2474static int __init f71882fg_init(void)
2475{
2476 int err = -ENODEV;
2477 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002478 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002479
Hans de Goede498be962009-01-07 16:37:28 +01002480 memset(&sio_data, 0, sizeof(sio_data));
2481
2482 if (f71882fg_find(0x2e, &address, &sio_data) &&
2483 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002484 goto exit;
2485
Hans de Goedec13548c2009-01-07 16:37:27 +01002486 err = platform_driver_register(&f71882fg_driver);
2487 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002488 goto exit;
2489
Hans de Goede498be962009-01-07 16:37:28 +01002490 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002491 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002492 goto exit_driver;
2493
2494 return 0;
2495
2496exit_driver:
2497 platform_driver_unregister(&f71882fg_driver);
2498exit:
2499 return err;
2500}
2501
2502static void __exit f71882fg_exit(void)
2503{
2504 platform_device_unregister(f71882fg_pdev);
2505 platform_driver_unregister(&f71882fg_driver);
2506}
2507
2508MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002509MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002510MODULE_LICENSE("GPL");
2511
2512module_init(f71882fg_init);
2513module_exit(f71882fg_exit);