blob: 49cf19621c0ce209ad321f1c366c4f97756ac0d5 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010053#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010054#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010055#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020056
57#define REGION_LENGTH 8
58#define ADDR_REG_OFFSET 5
59#define DATA_REG_OFFSET 6
60
Hans de Goede3cad4022011-03-09 20:57:14 +010061#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
62#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020063#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010064#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020065
66#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010067#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
68#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020069#define F71882FG_REG_FAN_STATUS 0x92
70#define F71882FG_REG_FAN_BEEP 0x93
71
Hans de Goede7567a042009-01-07 16:37:28 +010072#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
73#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
74#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020075#define F71882FG_REG_TEMP_STATUS 0x62
76#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020077#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010078#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020079#define F71882FG_REG_TEMP_TYPE 0x6B
80#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
81
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010082#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
83#define F71882FG_REG_PWM_TYPE 0x94
84#define F71882FG_REG_PWM_ENABLE 0x96
85
Hans de Goedebc274902009-01-07 16:37:29 +010086#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010087
Hans de Goede98f7ba12011-03-09 20:57:09 +010088#define F71882FG_REG_FAN_FAULT_T 0x9F
89#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010090#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010091
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010092#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
93#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
94#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
95
Hans de Goede45fb3662007-07-13 14:34:19 +020096#define F71882FG_REG_START 0x01
97
Hans de Goede0bae6402011-03-09 20:57:10 +010098#define F71882FG_MAX_INS 9
99
Hans de Goede45fb3662007-07-13 14:34:19 +0200100#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
101
Jean Delvare67b671b2007-12-06 23:13:42 +0100102static unsigned short force_id;
103module_param(force_id, ushort, 0);
104MODULE_PARM_DESC(force_id, "Override the detected device ID");
105
Hans de Goede3cad4022011-03-09 20:57:14 +0100106enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f71889ed, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100107
108static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200109 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100110 "f71862fg",
111 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100112 "f71889fg",
Hans de Goede3cad4022011-03-09 20:57:14 +0100113 "f71889ed",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100114 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100115};
116
Hans de Goede3cad4022011-03-09 20:57:14 +0100117static const char f71882fg_has_in[6][F71882FG_MAX_INS] = {
Hans de Goede0bae6402011-03-09 20:57:10 +0100118 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f71858fg */
119 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71862fg */
120 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71882fg */
121 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100122 { 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* f71889ed */
Hans de Goede0bae6402011-03-09 20:57:10 +0100123 { 1, 1, 1, 0, 0, 0, 0, 0, 0 }, /* f8000 */
124};
125
Hans de Goede3cad4022011-03-09 20:57:14 +0100126static const char f71882fg_has_in1_alarm[6] = {
Hans de Goede0bae6402011-03-09 20:57:10 +0100127 0, /* f71858fg */
128 0, /* f71862fg */
129 1, /* f71882fg */
130 1, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100131 1, /* f71889ed */
Hans de Goede0bae6402011-03-09 20:57:10 +0100132 0, /* f8000 */
133};
134
Hans de Goede3cad4022011-03-09 20:57:14 +0100135static const char f71882fg_has_beep[6] = {
Hans de Goede78aa4f72011-03-09 20:57:12 +0100136 0, /* f71858fg */
137 1, /* f71862fg */
138 1, /* f71882fg */
139 1, /* f71889fg */
Hans de Goede3cad4022011-03-09 20:57:14 +0100140 1, /* f71889ed */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100141 0, /* f8000 */
142};
143
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100144static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200145
146/* Super-I/O Function prototypes */
147static inline int superio_inb(int base, int reg);
148static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400149static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200150static inline void superio_select(int base, int ld);
151static inline void superio_exit(int base);
152
Hans de Goede498be962009-01-07 16:37:28 +0100153struct f71882fg_sio_data {
154 enum chips type;
155};
156
Hans de Goede45fb3662007-07-13 14:34:19 +0200157struct f71882fg_data {
158 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100159 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700160 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200161
162 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200163 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200164 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100165 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200166 unsigned long last_updated; /* In jiffies */
167 unsigned long last_limits; /* In jiffies */
168
169 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100170 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200171 u8 in1_max;
172 u8 in_status;
173 u8 in_beep;
174 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100175 u16 fan_target[4];
176 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200177 u8 fan_status;
178 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100179 /* Note: all models have only 3 temperature channels, but on some
180 they are addressed as 0-2 and on others as 1-3, so for coding
181 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200182 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100183 u8 temp_ovt[4];
184 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100185 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100186 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200187 u8 temp_status;
188 u8 temp_beep;
189 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200190 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100191 u8 pwm[4];
192 u8 pwm_enable;
193 u8 pwm_auto_point_hyst[2];
194 u8 pwm_auto_point_mapping[4];
195 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100196 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200197};
198
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100199/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200200static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
201 char *buf);
202static ssize_t show_in_max(struct device *dev, struct device_attribute
203 *devattr, char *buf);
204static ssize_t store_in_max(struct device *dev, struct device_attribute
205 *devattr, const char *buf, size_t count);
206static ssize_t show_in_beep(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t store_in_beep(struct device *dev, struct device_attribute
209 *devattr, const char *buf, size_t count);
210static ssize_t show_in_alarm(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212/* Sysfs Fan */
213static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
214 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100215static ssize_t show_fan_full_speed(struct device *dev,
216 struct device_attribute *devattr, char *buf);
217static ssize_t store_fan_full_speed(struct device *dev,
218 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200219static ssize_t show_fan_beep(struct device *dev, struct device_attribute
220 *devattr, char *buf);
221static ssize_t store_fan_beep(struct device *dev, struct device_attribute
222 *devattr, const char *buf, size_t count);
223static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
224 *devattr, char *buf);
225/* Sysfs Temp */
226static ssize_t show_temp(struct device *dev, struct device_attribute
227 *devattr, char *buf);
228static ssize_t show_temp_max(struct device *dev, struct device_attribute
229 *devattr, char *buf);
230static ssize_t store_temp_max(struct device *dev, struct device_attribute
231 *devattr, const char *buf, size_t count);
232static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
233 *devattr, char *buf);
234static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
235 *devattr, const char *buf, size_t count);
236static ssize_t show_temp_crit(struct device *dev, struct device_attribute
237 *devattr, char *buf);
238static ssize_t store_temp_crit(struct device *dev, struct device_attribute
239 *devattr, const char *buf, size_t count);
240static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
241 *devattr, char *buf);
242static ssize_t show_temp_type(struct device *dev, struct device_attribute
243 *devattr, char *buf);
244static ssize_t show_temp_beep(struct device *dev, struct device_attribute
245 *devattr, char *buf);
246static ssize_t store_temp_beep(struct device *dev, struct device_attribute
247 *devattr, const char *buf, size_t count);
248static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
249 *devattr, char *buf);
250static ssize_t show_temp_fault(struct device *dev, struct device_attribute
251 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100252/* PWM and Auto point control */
253static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
254 char *buf);
255static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
256 const char *buf, size_t count);
257static ssize_t show_pwm_enable(struct device *dev,
258 struct device_attribute *devattr, char *buf);
259static ssize_t store_pwm_enable(struct device *dev,
260 struct device_attribute *devattr, const char *buf, size_t count);
261static ssize_t show_pwm_interpolate(struct device *dev,
262 struct device_attribute *devattr, char *buf);
263static ssize_t store_pwm_interpolate(struct device *dev,
264 struct device_attribute *devattr, const char *buf, size_t count);
265static ssize_t show_pwm_auto_point_channel(struct device *dev,
266 struct device_attribute *devattr, char *buf);
267static ssize_t store_pwm_auto_point_channel(struct device *dev,
268 struct device_attribute *devattr, const char *buf, size_t count);
269static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
270 struct device_attribute *devattr, char *buf);
271static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
272 struct device_attribute *devattr, const char *buf, size_t count);
273static ssize_t show_pwm_auto_point_pwm(struct device *dev,
274 struct device_attribute *devattr, char *buf);
275static ssize_t store_pwm_auto_point_pwm(struct device *dev,
276 struct device_attribute *devattr, const char *buf, size_t count);
277static ssize_t show_pwm_auto_point_temp(struct device *dev,
278 struct device_attribute *devattr, char *buf);
279static ssize_t store_pwm_auto_point_temp(struct device *dev,
280 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200281/* Sysfs misc */
282static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
283 char *buf);
284
285static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100286static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200287
288static struct platform_driver f71882fg_driver = {
289 .driver = {
290 .owner = THIS_MODULE,
291 .name = DRVNAME,
292 },
293 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200294 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200295};
296
Hans de Goedec13548c2009-01-07 16:37:27 +0100297static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200298
Hans de Goede0bae6402011-03-09 20:57:10 +0100299/* Temp attr for the f71858fg, the f71858fg is special as it has its
300 temperature indexes start at 0 (the others start at 1) */
301static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200302 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
303 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
304 store_temp_max, 0, 0),
305 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
306 store_temp_max_hyst, 0, 0),
307 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
308 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
309 store_temp_crit, 0, 0),
310 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
311 0, 0),
312 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
313 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
314 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
315 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
316 store_temp_max, 0, 1),
317 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
318 store_temp_max_hyst, 0, 1),
319 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
320 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
321 store_temp_crit, 0, 1),
322 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
323 0, 1),
324 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200325 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
326 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
327 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
328 store_temp_max, 0, 2),
329 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
330 store_temp_max_hyst, 0, 2),
331 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
332 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
333 store_temp_crit, 0, 2),
334 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
335 0, 2),
336 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
337 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
338};
339
Hans de Goede0bae6402011-03-09 20:57:10 +0100340/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100341static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100342 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100343 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100344 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100345 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100346 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100347 /* Should really be temp1_max_alarm, but older versions did not handle
348 the max and crit alarms separately and lm_sensors v2 depends on the
349 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
350 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100354 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100355 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100357 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100358}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100359 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
360 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100361 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100362 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100363 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100364 /* Should be temp2_max_alarm, see temp1_alarm note */
365 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100366 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100367 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100368 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100369 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100370 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100371 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100372 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100373}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100374 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
375 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
376 store_temp_max, 0, 3),
377 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
378 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100379 /* Should be temp3_max_alarm, see temp1_alarm note */
380 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100381 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
382 store_temp_crit, 0, 3),
383 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
384 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100385 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100386 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100387 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100388} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200389
Hans de Goede78aa4f72011-03-09 20:57:12 +0100390/* Temp attr for models which can beep on temp alarm */
391static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
392 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
393 store_temp_beep, 0, 1),
394 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
395 store_temp_beep, 0, 5),
396}, {
397 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
398 store_temp_beep, 0, 2),
399 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
400 store_temp_beep, 0, 6),
401}, {
402 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
403 store_temp_beep, 0, 3),
404 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
405 store_temp_beep, 0, 7),
406} };
407
Hans de Goede0bae6402011-03-09 20:57:10 +0100408/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100409 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
410 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100411 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100412 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100413static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100414 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
415 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
416 store_temp_crit, 0, 0),
417 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
418 store_temp_max, 0, 0),
419 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200420 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100421 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
422 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
423 store_temp_crit, 0, 1),
424 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
425 store_temp_max, 0, 1),
426 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200427 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100428 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
429 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
430 store_temp_crit, 0, 2),
431 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
432 store_temp_max, 0, 2),
433 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200434 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100435};
436
Hans de Goede0bae6402011-03-09 20:57:10 +0100437/* in attr for all models */
438static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
439 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
440 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
441 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
442 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
443 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
444 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
445 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
446 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
447 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
448};
449
450/* For models with in1 alarm capability */
451static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
452 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
453 0, 1),
454 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
455 0, 1),
456 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
457};
458
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100459/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100460static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100461 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100462 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
463 show_fan_full_speed,
464 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100465 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100466 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
467 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
468 store_pwm_enable, 0, 0),
469 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
470 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100471}, {
472 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
473 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
474 show_fan_full_speed,
475 store_fan_full_speed, 0, 1),
476 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100477 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
478 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
479 store_pwm_enable, 0, 1),
480 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
481 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100482}, {
483 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
484 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
485 show_fan_full_speed,
486 store_fan_full_speed, 0, 2),
487 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200488 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
489 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
490 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100491 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
492 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100493}, {
494 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
495 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
496 show_fan_full_speed,
497 store_fan_full_speed, 0, 3),
498 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
499 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
500 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
501 store_pwm_enable, 0, 3),
502 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
503 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
504} };
Hans de Goede498be962009-01-07 16:37:28 +0100505
Hans de Goede66344aa2009-12-09 20:35:59 +0100506/* Attr for models which can beep on Fan alarm */
507static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100508 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
509 store_fan_beep, 0, 0),
510 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
511 store_fan_beep, 0, 1),
512 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
513 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100514 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
515 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100516};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100517
Hans de Goede66344aa2009-12-09 20:35:59 +0100518/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100519 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100520static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
521 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
522 show_pwm_auto_point_channel,
523 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100524 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
525 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
526 1, 0),
527 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
528 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
529 4, 0),
530 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
531 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
532 0, 0),
533 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
534 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
535 3, 0),
536 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
537 show_pwm_auto_point_temp_hyst,
538 store_pwm_auto_point_temp_hyst,
539 0, 0),
540 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
541 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
542
Hans de Goede66344aa2009-12-09 20:35:59 +0100543 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
544 show_pwm_auto_point_channel,
545 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100546 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
547 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
548 1, 1),
549 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
550 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
551 4, 1),
552 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
553 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
554 0, 1),
555 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
556 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
557 3, 1),
558 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
559 show_pwm_auto_point_temp_hyst,
560 store_pwm_auto_point_temp_hyst,
561 0, 1),
562 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
563 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100564
Hans de Goede66344aa2009-12-09 20:35:59 +0100565 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
566 show_pwm_auto_point_channel,
567 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100568 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
569 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
570 1, 2),
571 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
572 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
573 4, 2),
574 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
575 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
576 0, 2),
577 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
578 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
579 3, 2),
580 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
581 show_pwm_auto_point_temp_hyst,
582 store_pwm_auto_point_temp_hyst,
583 0, 2),
584 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
585 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100586};
587
Hans de Goede3cad4022011-03-09 20:57:14 +0100588/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100589static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100590 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
591 show_pwm_auto_point_channel,
592 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100593 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
594 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
595 0, 0),
596 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
597 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
598 1, 0),
599 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
600 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
601 2, 0),
602 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
603 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
604 3, 0),
605 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
606 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
607 4, 0),
608 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
609 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
610 0, 0),
611 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
612 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
613 1, 0),
614 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
615 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
616 2, 0),
617 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
618 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
619 3, 0),
620 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
621 show_pwm_auto_point_temp_hyst,
622 store_pwm_auto_point_temp_hyst,
623 0, 0),
624 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
625 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
626 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
627 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
628 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100630}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100631 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_channel,
633 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100634 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 0, 1),
637 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 1, 1),
640 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
642 2, 1),
643 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
645 3, 1),
646 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
648 4, 1),
649 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
651 0, 1),
652 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
653 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
654 1, 1),
655 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
656 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
657 2, 1),
658 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
659 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
660 3, 1),
661 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
662 show_pwm_auto_point_temp_hyst,
663 store_pwm_auto_point_temp_hyst,
664 0, 1),
665 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
666 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
667 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
668 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
669 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100671}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100672 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_channel,
674 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100675 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
677 0, 2),
678 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 1, 2),
681 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 2, 2),
684 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 3, 2),
687 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
689 4, 2),
690 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
692 0, 2),
693 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
695 1, 2),
696 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
697 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
698 2, 2),
699 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
700 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
701 3, 2),
702 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
703 show_pwm_auto_point_temp_hyst,
704 store_pwm_auto_point_temp_hyst,
705 0, 2),
706 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
707 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
708 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
709 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
710 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100712}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100713 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
714 show_pwm_auto_point_channel,
715 store_pwm_auto_point_channel, 0, 3),
716 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
718 0, 3),
719 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
721 1, 3),
722 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
724 2, 3),
725 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
727 3, 3),
728 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 4, 3),
731 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
733 0, 3),
734 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
736 1, 3),
737 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
739 2, 3),
740 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
742 3, 3),
743 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp_hyst,
745 store_pwm_auto_point_temp_hyst,
746 0, 3),
747 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
748 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
749 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
750 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
751 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
752 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100753} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200754
Hans de Goede66344aa2009-12-09 20:35:59 +0100755/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100756static struct sensor_device_attribute_2 f8000_fan_attr[] = {
757 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100758};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100759
Hans de Goede66344aa2009-12-09 20:35:59 +0100760/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
761 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
762 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
763static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
764 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_channel,
766 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100767 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
769 0, 2),
770 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
772 1, 2),
773 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
775 2, 2),
776 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
778 3, 2),
779 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
780 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
781 4, 2),
782 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
783 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
784 0, 2),
785 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
787 1, 2),
788 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
790 2, 2),
791 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
793 3, 2),
794 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_temp_hyst,
796 store_pwm_auto_point_temp_hyst,
797 0, 2),
798 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
799 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
800 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
801 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
802 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
804
Hans de Goede66344aa2009-12-09 20:35:59 +0100805 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_channel,
807 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100808 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
810 0, 0),
811 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
813 1, 0),
814 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 2, 0),
817 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
819 3, 0),
820 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
822 4, 0),
823 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
825 0, 0),
826 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
828 1, 0),
829 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
831 2, 0),
832 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
834 3, 0),
835 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_temp_hyst,
837 store_pwm_auto_point_temp_hyst,
838 0, 0),
839 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
840 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
841 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
842 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
843 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
845
Hans de Goede66344aa2009-12-09 20:35:59 +0100846 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
847 show_pwm_auto_point_channel,
848 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100849 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
851 0, 1),
852 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
854 1, 1),
855 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
857 2, 1),
858 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
860 3, 1),
861 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
863 4, 1),
864 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
866 0, 1),
867 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
869 1, 1),
870 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
872 2, 1),
873 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
875 3, 1),
876 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
877 show_pwm_auto_point_temp_hyst,
878 store_pwm_auto_point_temp_hyst,
879 0, 1),
880 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
881 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
882 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
883 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
884 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
885 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
886};
Hans de Goede45fb3662007-07-13 14:34:19 +0200887
888/* Super I/O functions */
889static inline int superio_inb(int base, int reg)
890{
891 outb(reg, base);
892 return inb(base + 1);
893}
894
895static int superio_inw(int base, int reg)
896{
897 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200898 val = superio_inb(base, reg) << 8;
899 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200900 return val;
901}
902
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400903static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200904{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400905 /* Don't step on other drivers' I/O space by accident */
906 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000907 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400908 return -EBUSY;
909 }
910
Hans de Goede45fb3662007-07-13 14:34:19 +0200911 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200912 outb(SIO_UNLOCK_KEY, base);
913 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400914
915 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200916}
917
Giel van Schijndel162bb592010-05-27 19:58:40 +0200918static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200919{
920 outb(SIO_REG_LDSEL, base);
921 outb(ld, base + 1);
922}
923
924static inline void superio_exit(int base)
925{
926 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400927 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200928}
929
Hans de Goede2f650632009-01-07 16:37:31 +0100930static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200931{
932 return reg ? (1500000 / reg) : 0;
933}
934
Hans de Goede2f650632009-01-07 16:37:31 +0100935static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100936{
937 return fan ? (1500000 / fan) : 0;
938}
939
Hans de Goede45fb3662007-07-13 14:34:19 +0200940static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
941{
942 u8 val;
943
944 outb(reg, data->addr + ADDR_REG_OFFSET);
945 val = inb(data->addr + DATA_REG_OFFSET);
946
947 return val;
948}
949
950static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
951{
952 u16 val;
953
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200954 val = f71882fg_read8(data, reg) << 8;
955 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200956
957 return val;
958}
959
960static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
961{
962 outb(reg, data->addr + ADDR_REG_OFFSET);
963 outb(val, data->addr + DATA_REG_OFFSET);
964}
965
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100966static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
967{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200968 f71882fg_write8(data, reg, val >> 8);
969 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100970}
971
Hans de Goede09475d32009-06-15 18:39:52 +0200972static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
973{
974 if (data->type == f71858fg)
975 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
976 else
977 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
978}
979
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100980static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200981{
982 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goede44c4dc52011-03-09 20:57:07 +0100983 int nr, reg;
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100984 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +0200985
986 mutex_lock(&data->update_lock);
987
988 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200989 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200990 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +0100991 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +0100992 data->in1_max =
993 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
994 data->in_beep =
995 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
996 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200997
998 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200999 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001000 data->temp_ovt[nr] = f71882fg_read8(data,
1001 F71882FG_REG_TEMP_OVT(nr));
1002 data->temp_high[nr] = f71882fg_read8(data,
1003 F71882FG_REG_TEMP_HIGH(nr));
1004 }
1005
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001006 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001007 data->temp_hyst[0] = f71882fg_read8(data,
1008 F71882FG_REG_TEMP_HYST(0));
1009 data->temp_hyst[1] = f71882fg_read8(data,
1010 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001011 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001012 /* All but the f71858fg / f8000 have this register */
1013 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001014 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001015 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001016 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1017 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1018 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001019
Hans de Goede78aa4f72011-03-09 20:57:12 +01001020 if (f71882fg_has_beep[data->type]) {
1021 data->fan_beep = f71882fg_read8(data,
1022 F71882FG_REG_FAN_BEEP);
1023 data->temp_beep = f71882fg_read8(data,
1024 F71882FG_REG_TEMP_BEEP);
1025 }
1026
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001027 data->pwm_enable = f71882fg_read8(data,
1028 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001029 data->pwm_auto_point_hyst[0] =
1030 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1031 data->pwm_auto_point_hyst[1] =
1032 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1033
Hans de Goede498be962009-01-07 16:37:28 +01001034 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001035 data->pwm_auto_point_mapping[nr] =
1036 f71882fg_read8(data,
1037 F71882FG_REG_POINT_MAPPING(nr));
1038
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001039 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001040 int point;
1041 for (point = 0; point < 5; point++) {
1042 data->pwm_auto_point_pwm[nr][point] =
1043 f71882fg_read8(data,
1044 F71882FG_REG_POINT_PWM
1045 (nr, point));
1046 }
1047 for (point = 0; point < 4; point++) {
1048 data->pwm_auto_point_temp[nr][point] =
1049 f71882fg_read8(data,
1050 F71882FG_REG_POINT_TEMP
1051 (nr, point));
1052 }
1053 } else {
1054 data->pwm_auto_point_pwm[nr][1] =
1055 f71882fg_read8(data,
1056 F71882FG_REG_POINT_PWM
1057 (nr, 1));
1058 data->pwm_auto_point_pwm[nr][4] =
1059 f71882fg_read8(data,
1060 F71882FG_REG_POINT_PWM
1061 (nr, 4));
1062 data->pwm_auto_point_temp[nr][0] =
1063 f71882fg_read8(data,
1064 F71882FG_REG_POINT_TEMP
1065 (nr, 0));
1066 data->pwm_auto_point_temp[nr][3] =
1067 f71882fg_read8(data,
1068 F71882FG_REG_POINT_TEMP
1069 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001070 }
1071 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001072 data->last_limits = jiffies;
1073 }
1074
1075 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001076 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001077 data->temp_status = f71882fg_read8(data,
1078 F71882FG_REG_TEMP_STATUS);
1079 data->temp_diode_open = f71882fg_read8(data,
1080 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001081 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1082 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001083
1084 data->fan_status = f71882fg_read8(data,
1085 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001086 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001087 data->fan[nr] = f71882fg_read16(data,
1088 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001089 data->fan_target[nr] =
1090 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1091 data->fan_full_speed[nr] =
1092 f71882fg_read16(data,
1093 F71882FG_REG_FAN_FULL_SPEED(nr));
1094 data->pwm[nr] =
1095 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1096 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001097 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1098 if (data->type == f8000)
1099 data->fan[3] = f71882fg_read16(data,
1100 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001101
1102 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001103 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001104 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001105 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1106 if (f71882fg_has_in[data->type][nr])
1107 data->in[nr] = f71882fg_read8(data,
1108 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001109
1110 data->last_updated = jiffies;
1111 data->valid = 1;
1112 }
1113
1114 mutex_unlock(&data->update_lock);
1115
1116 return data;
1117}
1118
1119/* Sysfs Interface */
1120static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1121 char *buf)
1122{
1123 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001124 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001125 int speed = fan_from_reg(data->fan[nr]);
1126
1127 if (speed == FAN_MIN_DETECT)
1128 speed = 0;
1129
1130 return sprintf(buf, "%d\n", speed);
1131}
1132
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001133static ssize_t show_fan_full_speed(struct device *dev,
1134 struct device_attribute *devattr, char *buf)
1135{
1136 struct f71882fg_data *data = f71882fg_update_device(dev);
1137 int nr = to_sensor_dev_attr_2(devattr)->index;
1138 int speed = fan_from_reg(data->fan_full_speed[nr]);
1139 return sprintf(buf, "%d\n", speed);
1140}
1141
1142static ssize_t store_fan_full_speed(struct device *dev,
1143 struct device_attribute *devattr,
1144 const char *buf, size_t count)
1145{
1146 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001147 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1148 long val;
1149
1150 err = strict_strtol(buf, 10, &val);
1151 if (err)
1152 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001153
1154 val = SENSORS_LIMIT(val, 23, 1500000);
1155 val = fan_to_reg(val);
1156
1157 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001158 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1159 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001160 mutex_unlock(&data->update_lock);
1161
1162 return count;
1163}
1164
Hans de Goede45fb3662007-07-13 14:34:19 +02001165static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1166 *devattr, char *buf)
1167{
1168 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001169 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001170
1171 if (data->fan_beep & (1 << nr))
1172 return sprintf(buf, "1\n");
1173 else
1174 return sprintf(buf, "0\n");
1175}
1176
1177static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1178 *devattr, const char *buf, size_t count)
1179{
1180 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001181 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1182 unsigned long val;
1183
1184 err = strict_strtoul(buf, 10, &val);
1185 if (err)
1186 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001187
1188 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001189 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001190 if (val)
1191 data->fan_beep |= 1 << nr;
1192 else
1193 data->fan_beep &= ~(1 << nr);
1194
1195 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1196 mutex_unlock(&data->update_lock);
1197
1198 return count;
1199}
1200
1201static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1202 *devattr, char *buf)
1203{
1204 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001205 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001206
1207 if (data->fan_status & (1 << nr))
1208 return sprintf(buf, "1\n");
1209 else
1210 return sprintf(buf, "0\n");
1211}
1212
1213static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1214 char *buf)
1215{
1216 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001217 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001218
1219 return sprintf(buf, "%d\n", data->in[nr] * 8);
1220}
1221
1222static ssize_t show_in_max(struct device *dev, struct device_attribute
1223 *devattr, char *buf)
1224{
1225 struct f71882fg_data *data = f71882fg_update_device(dev);
1226
1227 return sprintf(buf, "%d\n", data->in1_max * 8);
1228}
1229
1230static ssize_t store_in_max(struct device *dev, struct device_attribute
1231 *devattr, const char *buf, size_t count)
1232{
1233 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001234 int err;
1235 long val;
1236
1237 err = strict_strtol(buf, 10, &val);
1238 if (err)
1239 return err;
1240
1241 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001242 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001243
1244 mutex_lock(&data->update_lock);
1245 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1246 data->in1_max = val;
1247 mutex_unlock(&data->update_lock);
1248
1249 return count;
1250}
1251
1252static ssize_t show_in_beep(struct device *dev, struct device_attribute
1253 *devattr, char *buf)
1254{
1255 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001256 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001257
1258 if (data->in_beep & (1 << nr))
1259 return sprintf(buf, "1\n");
1260 else
1261 return sprintf(buf, "0\n");
1262}
1263
1264static ssize_t store_in_beep(struct device *dev, struct device_attribute
1265 *devattr, const char *buf, size_t count)
1266{
1267 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001268 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1269 unsigned long val;
1270
1271 err = strict_strtoul(buf, 10, &val);
1272 if (err)
1273 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001274
1275 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001276 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001277 if (val)
1278 data->in_beep |= 1 << nr;
1279 else
1280 data->in_beep &= ~(1 << nr);
1281
1282 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1283 mutex_unlock(&data->update_lock);
1284
1285 return count;
1286}
1287
1288static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1289 *devattr, char *buf)
1290{
1291 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001292 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001293
1294 if (data->in_status & (1 << nr))
1295 return sprintf(buf, "1\n");
1296 else
1297 return sprintf(buf, "0\n");
1298}
1299
1300static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1301 char *buf)
1302{
1303 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001304 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001305 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001306
Hans de Goede09475d32009-06-15 18:39:52 +02001307 if (data->type == f71858fg) {
1308 /* TEMP_TABLE_SEL 1 or 3 ? */
1309 if (data->temp_config & 1) {
1310 sign = data->temp[nr] & 0x0001;
1311 temp = (data->temp[nr] >> 5) & 0x7ff;
1312 } else {
1313 sign = data->temp[nr] & 0x8000;
1314 temp = (data->temp[nr] >> 5) & 0x3ff;
1315 }
1316 temp *= 125;
1317 if (sign)
1318 temp -= 128000;
1319 } else
1320 temp = data->temp[nr] * 1000;
1321
1322 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001323}
1324
1325static ssize_t show_temp_max(struct device *dev, struct device_attribute
1326 *devattr, char *buf)
1327{
1328 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001329 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001330
1331 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1332}
1333
1334static ssize_t store_temp_max(struct device *dev, struct device_attribute
1335 *devattr, const char *buf, size_t count)
1336{
1337 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001338 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1339 long val;
1340
1341 err = strict_strtol(buf, 10, &val);
1342 if (err)
1343 return err;
1344
1345 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001346 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001347
1348 mutex_lock(&data->update_lock);
1349 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1350 data->temp_high[nr] = val;
1351 mutex_unlock(&data->update_lock);
1352
1353 return count;
1354}
1355
1356static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1357 *devattr, char *buf)
1358{
1359 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001360 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001361 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001362
Hans de Goedece0bfa52009-01-07 16:37:28 +01001363 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001364 if (nr & 1)
1365 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1366 else
1367 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1368 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001369 mutex_unlock(&data->update_lock);
1370
1371 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001372}
1373
1374static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1375 *devattr, const char *buf, size_t count)
1376{
1377 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001378 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001379 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001380 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001381 long val;
1382
1383 err = strict_strtol(buf, 10, &val);
1384 if (err)
1385 return err;
1386
1387 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001388
1389 mutex_lock(&data->update_lock);
1390
1391 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001392 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1393 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1394 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001395 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001396
1397 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001398 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1399 if (nr & 1)
1400 reg = (reg & 0x0f) | (val << 4);
1401 else
1402 reg = (reg & 0xf0) | val;
1403 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1404 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001405
Hans de Goede45fb3662007-07-13 14:34:19 +02001406 mutex_unlock(&data->update_lock);
1407 return ret;
1408}
1409
1410static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1411 *devattr, char *buf)
1412{
1413 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001414 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001415
1416 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1417}
1418
1419static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1420 *devattr, const char *buf, size_t count)
1421{
1422 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001423 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1424 long val;
1425
1426 err = strict_strtol(buf, 10, &val);
1427 if (err)
1428 return err;
1429
1430 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001431 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001432
1433 mutex_lock(&data->update_lock);
1434 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1435 data->temp_ovt[nr] = val;
1436 mutex_unlock(&data->update_lock);
1437
1438 return count;
1439}
1440
1441static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1442 *devattr, char *buf)
1443{
1444 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001445 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001446 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001447
Hans de Goedece0bfa52009-01-07 16:37:28 +01001448 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001449 if (nr & 1)
1450 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1451 else
1452 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1453 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001454 mutex_unlock(&data->update_lock);
1455
1456 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001457}
1458
1459static ssize_t show_temp_type(struct device *dev, struct device_attribute
1460 *devattr, char *buf)
1461{
1462 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001463 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001464
1465 return sprintf(buf, "%d\n", data->temp_type[nr]);
1466}
1467
1468static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1469 *devattr, char *buf)
1470{
1471 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001472 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001473
Hans de Goede7567a042009-01-07 16:37:28 +01001474 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001475 return sprintf(buf, "1\n");
1476 else
1477 return sprintf(buf, "0\n");
1478}
1479
1480static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1481 *devattr, const char *buf, size_t count)
1482{
1483 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001484 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1485 unsigned long val;
1486
1487 err = strict_strtoul(buf, 10, &val);
1488 if (err)
1489 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001490
1491 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001492 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001493 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001494 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001495 else
Hans de Goede7567a042009-01-07 16:37:28 +01001496 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001497
1498 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1499 mutex_unlock(&data->update_lock);
1500
1501 return count;
1502}
1503
1504static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1505 *devattr, char *buf)
1506{
1507 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001508 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001509
Hans de Goede7567a042009-01-07 16:37:28 +01001510 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001511 return sprintf(buf, "1\n");
1512 else
1513 return sprintf(buf, "0\n");
1514}
1515
1516static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1517 *devattr, char *buf)
1518{
1519 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001520 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001521
Hans de Goede7567a042009-01-07 16:37:28 +01001522 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001523 return sprintf(buf, "1\n");
1524 else
1525 return sprintf(buf, "0\n");
1526}
1527
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001528static ssize_t show_pwm(struct device *dev,
1529 struct device_attribute *devattr, char *buf)
1530{
1531 struct f71882fg_data *data = f71882fg_update_device(dev);
1532 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001533 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001534 if (data->pwm_enable & (1 << (2 * nr)))
1535 /* PWM mode */
1536 val = data->pwm[nr];
1537 else {
1538 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001539 val = 255 * fan_from_reg(data->fan_target[nr])
1540 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001541 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001542 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001543 return sprintf(buf, "%d\n", val);
1544}
1545
1546static ssize_t store_pwm(struct device *dev,
1547 struct device_attribute *devattr, const char *buf,
1548 size_t count)
1549{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001550 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001551 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1552 long val;
1553
1554 err = strict_strtol(buf, 10, &val);
1555 if (err)
1556 return err;
1557
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001558 val = SENSORS_LIMIT(val, 0, 255);
1559
1560 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001561 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001562 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1563 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1564 count = -EROFS;
1565 goto leave;
1566 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001567 if (data->pwm_enable & (1 << (2 * nr))) {
1568 /* PWM mode */
1569 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1570 data->pwm[nr] = val;
1571 } else {
1572 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001573 int target, full_speed;
1574 full_speed = f71882fg_read16(data,
1575 F71882FG_REG_FAN_FULL_SPEED(nr));
1576 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1577 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1578 data->fan_target[nr] = target;
1579 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001580 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001581leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001582 mutex_unlock(&data->update_lock);
1583
1584 return count;
1585}
1586
1587static ssize_t show_pwm_enable(struct device *dev,
1588 struct device_attribute *devattr, char *buf)
1589{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001590 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001591 struct f71882fg_data *data = f71882fg_update_device(dev);
1592 int nr = to_sensor_dev_attr_2(devattr)->index;
1593
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001594 switch ((data->pwm_enable >> 2 * nr) & 3) {
1595 case 0:
1596 case 1:
1597 result = 2; /* Normal auto mode */
1598 break;
1599 case 2:
1600 result = 1; /* Manual mode */
1601 break;
1602 case 3:
1603 if (data->type == f8000)
1604 result = 3; /* Thermostat mode */
1605 else
1606 result = 1; /* Manual mode */
1607 break;
1608 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001609
1610 return sprintf(buf, "%d\n", result);
1611}
1612
1613static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1614 *devattr, const char *buf, size_t count)
1615{
1616 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001617 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1618 long val;
1619
1620 err = strict_strtol(buf, 10, &val);
1621 if (err)
1622 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001623
Hans de Goede3fc78382009-06-15 18:39:50 +02001624 /* Special case for F8000 pwm channel 3 which only does auto mode */
1625 if (data->type == f8000 && nr == 2 && val != 2)
1626 return -EINVAL;
1627
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001628 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001629 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001630 /* Special case for F8000 auto PWM mode / Thermostat mode */
1631 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1632 switch (val) {
1633 case 2:
1634 data->pwm_enable &= ~(2 << (2 * nr));
1635 break; /* Normal auto mode */
1636 case 3:
1637 data->pwm_enable |= 2 << (2 * nr);
1638 break; /* Thermostat mode */
1639 default:
1640 count = -EINVAL;
1641 goto leave;
1642 }
1643 } else {
1644 switch (val) {
1645 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001646 /* The f71858fg does not support manual RPM mode */
1647 if (data->type == f71858fg &&
1648 ((data->pwm_enable >> (2 * nr)) & 1)) {
1649 count = -EINVAL;
1650 goto leave;
1651 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001652 data->pwm_enable |= 2 << (2 * nr);
1653 break; /* Manual */
1654 case 2:
1655 data->pwm_enable &= ~(2 << (2 * nr));
1656 break; /* Normal auto mode */
1657 default:
1658 count = -EINVAL;
1659 goto leave;
1660 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001661 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001662 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001663leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001664 mutex_unlock(&data->update_lock);
1665
1666 return count;
1667}
1668
1669static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1670 struct device_attribute *devattr,
1671 char *buf)
1672{
1673 int result;
1674 struct f71882fg_data *data = f71882fg_update_device(dev);
1675 int pwm = to_sensor_dev_attr_2(devattr)->index;
1676 int point = to_sensor_dev_attr_2(devattr)->nr;
1677
Hans de Goedece0bfa52009-01-07 16:37:28 +01001678 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001679 if (data->pwm_enable & (1 << (2 * pwm))) {
1680 /* PWM mode */
1681 result = data->pwm_auto_point_pwm[pwm][point];
1682 } else {
1683 /* RPM mode */
1684 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1685 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001686 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001687
1688 return sprintf(buf, "%d\n", result);
1689}
1690
1691static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1692 struct device_attribute *devattr,
1693 const char *buf, size_t count)
1694{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001695 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001696 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001697 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001698 long val;
1699
1700 err = strict_strtol(buf, 10, &val);
1701 if (err)
1702 return err;
1703
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001704 val = SENSORS_LIMIT(val, 0, 255);
1705
1706 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001707 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001708 if (data->pwm_enable & (1 << (2 * pwm))) {
1709 /* PWM mode */
1710 } else {
1711 /* RPM mode */
1712 if (val < 29) /* Prevent negative numbers */
1713 val = 255;
1714 else
1715 val = (255 - val) * 32 / val;
1716 }
1717 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1718 data->pwm_auto_point_pwm[pwm][point] = val;
1719 mutex_unlock(&data->update_lock);
1720
1721 return count;
1722}
1723
1724static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1725 struct device_attribute *devattr,
1726 char *buf)
1727{
1728 int result = 0;
1729 struct f71882fg_data *data = f71882fg_update_device(dev);
1730 int nr = to_sensor_dev_attr_2(devattr)->index;
1731 int point = to_sensor_dev_attr_2(devattr)->nr;
1732
1733 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001734 if (nr & 1)
1735 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1736 else
1737 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001738 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1739 mutex_unlock(&data->update_lock);
1740
1741 return sprintf(buf, "%d\n", result);
1742}
1743
1744static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1745 struct device_attribute *devattr,
1746 const char *buf, size_t count)
1747{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001748 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001749 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001750 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001751 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001752 long val;
1753
1754 err = strict_strtol(buf, 10, &val);
1755 if (err)
1756 return err;
1757
1758 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001759
1760 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001761 data->pwm_auto_point_temp[nr][point] =
1762 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001763 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1764 data->pwm_auto_point_temp[nr][point]);
1765 val = data->pwm_auto_point_temp[nr][point] - val;
1766
Hans de Goedebc274902009-01-07 16:37:29 +01001767 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1768 if (nr & 1)
1769 reg = (reg & 0x0f) | (val << 4);
1770 else
1771 reg = (reg & 0xf0) | val;
1772
1773 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1774 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001775 mutex_unlock(&data->update_lock);
1776
1777 return count;
1778}
1779
1780static ssize_t show_pwm_interpolate(struct device *dev,
1781 struct device_attribute *devattr, char *buf)
1782{
1783 int result;
1784 struct f71882fg_data *data = f71882fg_update_device(dev);
1785 int nr = to_sensor_dev_attr_2(devattr)->index;
1786
1787 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1788
1789 return sprintf(buf, "%d\n", result);
1790}
1791
1792static ssize_t store_pwm_interpolate(struct device *dev,
1793 struct device_attribute *devattr,
1794 const char *buf, size_t count)
1795{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001796 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001797 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1798 unsigned long val;
1799
1800 err = strict_strtoul(buf, 10, &val);
1801 if (err)
1802 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001803
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001804 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001805 data->pwm_auto_point_mapping[nr] =
1806 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001807 if (val)
1808 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1809 else
1810 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1811 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1812 data->pwm_auto_point_mapping[nr] = val;
1813 mutex_unlock(&data->update_lock);
1814
1815 return count;
1816}
1817
1818static ssize_t show_pwm_auto_point_channel(struct device *dev,
1819 struct device_attribute *devattr,
1820 char *buf)
1821{
1822 int result;
1823 struct f71882fg_data *data = f71882fg_update_device(dev);
1824 int nr = to_sensor_dev_attr_2(devattr)->index;
1825
Hans de Goede09475d32009-06-15 18:39:52 +02001826 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1827 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001828
1829 return sprintf(buf, "%d\n", result);
1830}
1831
1832static ssize_t store_pwm_auto_point_channel(struct device *dev,
1833 struct device_attribute *devattr,
1834 const char *buf, size_t count)
1835{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001836 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001837 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1838 long val;
1839
1840 err = strict_strtol(buf, 10, &val);
1841 if (err)
1842 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001843
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001844 switch (val) {
1845 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001846 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001847 break;
1848 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001849 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001850 break;
1851 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001852 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001853 break;
1854 default:
1855 return -EINVAL;
1856 }
Hans de Goede09475d32009-06-15 18:39:52 +02001857 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001858 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001859 data->pwm_auto_point_mapping[nr] =
1860 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001861 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1862 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1863 data->pwm_auto_point_mapping[nr] = val;
1864 mutex_unlock(&data->update_lock);
1865
1866 return count;
1867}
1868
1869static ssize_t show_pwm_auto_point_temp(struct device *dev,
1870 struct device_attribute *devattr,
1871 char *buf)
1872{
1873 int result;
1874 struct f71882fg_data *data = f71882fg_update_device(dev);
1875 int pwm = to_sensor_dev_attr_2(devattr)->index;
1876 int point = to_sensor_dev_attr_2(devattr)->nr;
1877
1878 result = data->pwm_auto_point_temp[pwm][point];
1879 return sprintf(buf, "%d\n", 1000 * result);
1880}
1881
1882static ssize_t store_pwm_auto_point_temp(struct device *dev,
1883 struct device_attribute *devattr,
1884 const char *buf, size_t count)
1885{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001886 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001887 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001888 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001889 long val;
1890
1891 err = strict_strtol(buf, 10, &val);
1892 if (err)
1893 return err;
1894
1895 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001896
Hans de Goede98f7ba12011-03-09 20:57:09 +01001897 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01001898 val = SENSORS_LIMIT(val, -128, 127);
1899 else
1900 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001901
1902 mutex_lock(&data->update_lock);
1903 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1904 data->pwm_auto_point_temp[pwm][point] = val;
1905 mutex_unlock(&data->update_lock);
1906
1907 return count;
1908}
1909
Hans de Goede45fb3662007-07-13 14:34:19 +02001910static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1911 char *buf)
1912{
Hans de Goede498be962009-01-07 16:37:28 +01001913 struct f71882fg_data *data = dev_get_drvdata(dev);
1914 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001915}
1916
Hans de Goedec13548c2009-01-07 16:37:27 +01001917static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1918 struct sensor_device_attribute_2 *attr, int count)
1919{
1920 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001921
Hans de Goedec13548c2009-01-07 16:37:27 +01001922 for (i = 0; i < count; i++) {
1923 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1924 if (err)
1925 return err;
1926 }
1927 return 0;
1928}
1929
Hans de Goedefc16c562009-12-09 20:36:01 +01001930static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1931 struct sensor_device_attribute_2 *attr, int count)
1932{
1933 int i;
1934
1935 for (i = 0; i < count; i++)
1936 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1937}
1938
Hans de Goedec13548c2009-01-07 16:37:27 +01001939static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001940{
1941 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001942 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001943 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01001944 int nr_temps = 3;
Hans de Goede98f7ba12011-03-09 20:57:09 +01001945 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001946
Hans de Goedec13548c2009-01-07 16:37:27 +01001947 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1948 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001949 return -ENOMEM;
1950
1951 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001952 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001953 data->temp_start =
1954 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001955 mutex_init(&data->update_lock);
1956 platform_set_drvdata(pdev, data);
1957
Hans de Goede3cc74752009-01-07 16:37:28 +01001958 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001959 if (start_reg & 0x04) {
1960 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1961 err = -ENODEV;
1962 goto exit_free;
1963 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001964 if (!(start_reg & 0x03)) {
1965 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1966 err = -ENODEV;
1967 goto exit_free;
1968 }
1969
Hans de Goede45fb3662007-07-13 14:34:19 +02001970 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001971 err = device_create_file(&pdev->dev, &dev_attr_name);
1972 if (err)
1973 goto exit_unregister_sysfs;
1974
Hans de Goedec13548c2009-01-07 16:37:27 +01001975 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001976 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001977 case f71858fg:
1978 data->temp_config =
1979 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1980 if (data->temp_config & 0x10)
1981 /* The f71858fg temperature alarms behave as
1982 the f8000 alarms in this mode */
1983 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001984 f8000_temp_attr,
1985 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001986 else
1987 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01001988 f71858fg_temp_attr,
1989 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02001990 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01001991 case f8000:
1992 err = f71882fg_create_sysfs_files(pdev,
1993 f8000_temp_attr,
1994 ARRAY_SIZE(f8000_temp_attr));
1995 break;
1996 default:
1997 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01001998 &fxxxx_temp_attr[0][0],
1999 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002000 }
2001 if (err)
2002 goto exit_unregister_sysfs;
2003
Hans de Goede78aa4f72011-03-09 20:57:12 +01002004 if (f71882fg_has_beep[data->type]) {
2005 err = f71882fg_create_sysfs_files(pdev,
2006 &fxxxx_temp_beep_attr[0][0],
2007 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2008 * nr_temps);
2009 if (err)
2010 goto exit_unregister_sysfs;
2011 }
2012
Hans de Goede0bae6402011-03-09 20:57:10 +01002013 for (i = 0; i < F71882FG_MAX_INS; i++) {
2014 if (f71882fg_has_in[data->type][i]) {
2015 err = device_create_file(&pdev->dev,
2016 &fxxxx_in_attr[i].dev_attr);
2017 if (err)
2018 goto exit_unregister_sysfs;
2019 }
2020 }
2021 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002022 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002023 fxxxx_in1_alarm_attr,
2024 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002025 if (err)
2026 goto exit_unregister_sysfs;
2027 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002028 }
2029
Hans de Goede45fb3662007-07-13 14:34:19 +02002030 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002031 switch (data->type) {
2032 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002033 case f71889ed:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002034 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2035 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2036 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002037 /* Ensure banked pwm registers point to right bank */
2038 reg &= ~F71882FG_FAN_PROG_SEL;
2039 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002040 break;
2041 default:
2042 break;
2043 }
2044
Hans de Goede996cadb2009-06-15 18:39:51 +02002045 data->pwm_enable =
2046 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2047
2048 /* Sanity check the pwm settings */
2049 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002050 case f71858fg:
2051 err = 0;
2052 for (i = 0; i < nr_fans; i++)
2053 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2054 err = 1;
2055 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002056 case f71862fg:
2057 err = (data->pwm_enable & 0x15) != 0x15;
2058 break;
2059 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002060 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002061 case f71889ed:
Hans de Goede996cadb2009-06-15 18:39:51 +02002062 err = 0;
2063 break;
2064 case f8000:
2065 err = data->pwm_enable & 0x20;
2066 break;
2067 }
2068 if (err) {
2069 dev_err(&pdev->dev,
2070 "Invalid (reserved) pwm settings: 0x%02x\n",
2071 (unsigned int)data->pwm_enable);
2072 err = -ENODEV;
2073 goto exit_unregister_sysfs;
2074 }
2075
Hans de Goedeb69b0392009-12-09 20:36:00 +01002076 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2077 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002078 if (err)
2079 goto exit_unregister_sysfs;
2080
Hans de Goede78aa4f72011-03-09 20:57:12 +01002081 if (f71882fg_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002082 err = f71882fg_create_sysfs_files(pdev,
2083 fxxxx_fan_beep_attr, nr_fans);
2084 if (err)
2085 goto exit_unregister_sysfs;
2086 }
2087
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002088 switch (data->type) {
Hans de Goedee48a7f12011-03-09 20:57:13 +01002089 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002090 case f71889ed:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002091 for (i = 0; i < nr_fans; i++) {
2092 data->pwm_auto_point_mapping[i] =
2093 f71882fg_read8(data,
2094 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002095 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2096 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002097 break;
2098 }
2099 if (i != nr_fans) {
2100 dev_warn(&pdev->dev,
2101 "Auto pwm controlled by raw digital "
2102 "data, disabling pwm auto_point "
2103 "sysfs attributes\n");
2104 goto no_pwm_auto_point;
2105 }
2106 break;
2107 default:
2108 break;
2109 }
2110
2111 switch (data->type) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002112 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002113 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002114 f71862fg_auto_pwm_attr,
2115 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002116 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002117 case f8000:
2118 err = f71882fg_create_sysfs_files(pdev,
2119 f8000_fan_attr,
2120 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002121 if (err)
2122 goto exit_unregister_sysfs;
2123 err = f71882fg_create_sysfs_files(pdev,
2124 f8000_auto_pwm_attr,
2125 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002126 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002127 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002128 err = f71882fg_create_sysfs_files(pdev,
2129 &fxxxx_auto_pwm_attr[0][0],
2130 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002131 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002132 if (err)
2133 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002134
Hans de Goedee48a7f12011-03-09 20:57:13 +01002135no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002136 for (i = 0; i < nr_fans; i++)
2137 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2138 (data->pwm_enable & (1 << 2 * i)) ?
2139 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002140 }
2141
Tony Jones1beeffe2007-08-20 13:46:20 -07002142 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2143 if (IS_ERR(data->hwmon_dev)) {
2144 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002145 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002146 goto exit_unregister_sysfs;
2147 }
2148
2149 return 0;
2150
2151exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002152 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002153 return err; /* f71882fg_remove() also frees our data */
2154exit_free:
2155 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002156 return err;
2157}
2158
Hans de Goedec13548c2009-01-07 16:37:27 +01002159static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002160{
Hans de Goede45fb3662007-07-13 14:34:19 +02002161 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goede0bae6402011-03-09 20:57:10 +01002162 int i, nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede60d2b372011-03-09 20:57:11 +01002163 int nr_temps = 3;
Hans de Goedefc16c562009-12-09 20:36:01 +01002164 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002165
Hans de Goedec13548c2009-01-07 16:37:27 +01002166 if (data->hwmon_dev)
2167 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002168
Hans de Goedec13548c2009-01-07 16:37:27 +01002169 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002170
Hans de Goedefc16c562009-12-09 20:36:01 +01002171 if (start_reg & 0x01) {
2172 switch (data->type) {
2173 case f71858fg:
2174 if (data->temp_config & 0x10)
2175 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002176 f8000_temp_attr,
2177 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002178 else
2179 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002180 f71858fg_temp_attr,
2181 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002182 break;
2183 case f8000:
2184 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002185 f8000_temp_attr,
2186 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002187 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002188 default:
2189 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002190 &fxxxx_temp_attr[0][0],
2191 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002192 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002193 if (f71882fg_has_beep[data->type]) {
2194 f71882fg_remove_sysfs_files(pdev,
2195 &fxxxx_temp_beep_attr[0][0],
2196 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2197 }
2198
Hans de Goede0bae6402011-03-09 20:57:10 +01002199 for (i = 0; i < F71882FG_MAX_INS; i++) {
2200 if (f71882fg_has_in[data->type][i]) {
2201 device_remove_file(&pdev->dev,
2202 &fxxxx_in_attr[i].dev_attr);
2203 }
2204 }
2205 if (f71882fg_has_in1_alarm[data->type]) {
2206 f71882fg_remove_sysfs_files(pdev,
2207 fxxxx_in1_alarm_attr,
2208 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002209 }
2210 }
Hans de Goede498be962009-01-07 16:37:28 +01002211
Hans de Goedefc16c562009-12-09 20:36:01 +01002212 if (start_reg & 0x02) {
2213 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2214 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002215
Hans de Goede78aa4f72011-03-09 20:57:12 +01002216 if (f71882fg_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002217 f71882fg_remove_sysfs_files(pdev,
2218 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002219 }
Hans de Goede498be962009-01-07 16:37:28 +01002220
Hans de Goedefc16c562009-12-09 20:36:01 +01002221 switch (data->type) {
2222 case f71862fg:
2223 f71882fg_remove_sysfs_files(pdev,
2224 f71862fg_auto_pwm_attr,
2225 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2226 break;
2227 case f8000:
2228 f71882fg_remove_sysfs_files(pdev,
2229 f8000_fan_attr,
2230 ARRAY_SIZE(f8000_fan_attr));
2231 f71882fg_remove_sysfs_files(pdev,
2232 f8000_auto_pwm_attr,
2233 ARRAY_SIZE(f8000_auto_pwm_attr));
2234 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002235 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002236 f71882fg_remove_sysfs_files(pdev,
2237 &fxxxx_auto_pwm_attr[0][0],
2238 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2239 }
2240 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002241
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002242 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002243 kfree(data);
2244
2245 return 0;
2246}
2247
Hans de Goede498be962009-01-07 16:37:28 +01002248static int __init f71882fg_find(int sioaddr, unsigned short *address,
2249 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002250{
Hans de Goede45fb3662007-07-13 14:34:19 +02002251 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002252 int err = superio_enter(sioaddr);
2253 if (err)
2254 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002255
2256 devid = superio_inw(sioaddr, SIO_REG_MANID);
2257 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002258 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002259 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002260 goto exit;
2261 }
2262
Jean Delvare67b671b2007-12-06 23:13:42 +01002263 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002264 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002265 case SIO_F71858_ID:
2266 sio_data->type = f71858fg;
2267 break;
Hans de Goede498be962009-01-07 16:37:28 +01002268 case SIO_F71862_ID:
2269 sio_data->type = f71862fg;
2270 break;
2271 case SIO_F71882_ID:
2272 sio_data->type = f71882fg;
2273 break;
Hans de Goede76698962009-12-09 20:36:01 +01002274 case SIO_F71889_ID:
2275 sio_data->type = f71889fg;
2276 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002277 case SIO_F71889E_ID:
2278 sio_data->type = f71889ed;
2279 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002280 case SIO_F8000_ID:
2281 sio_data->type = f8000;
2282 break;
Hans de Goede498be962009-01-07 16:37:28 +01002283 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002284 pr_info("Unsupported Fintek device: %04x\n",
2285 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002286 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002287 goto exit;
2288 }
2289
Hans de Goede09475d32009-06-15 18:39:52 +02002290 if (sio_data->type == f71858fg)
2291 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2292 else
2293 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2294
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002295 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002296 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002297 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002298 goto exit;
2299 }
2300
2301 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002302 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002303 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002304 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002305 goto exit;
2306 }
2307 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2308
Hans de Goede45fb3662007-07-13 14:34:19 +02002309 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002310 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002311 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002312 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2313exit:
2314 superio_exit(sioaddr);
2315 return err;
2316}
2317
Hans de Goede498be962009-01-07 16:37:28 +01002318static int __init f71882fg_device_add(unsigned short address,
2319 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002320{
2321 struct resource res = {
2322 .start = address,
2323 .end = address + REGION_LENGTH - 1,
2324 .flags = IORESOURCE_IO,
2325 };
2326 int err;
2327
2328 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002329 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002330 return -ENOMEM;
2331
2332 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002333 err = acpi_check_resource_conflict(&res);
2334 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002335 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002336
Hans de Goede45fb3662007-07-13 14:34:19 +02002337 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002338 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002339 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002340 goto exit_device_put;
2341 }
2342
Hans de Goede498be962009-01-07 16:37:28 +01002343 err = platform_device_add_data(f71882fg_pdev, sio_data,
2344 sizeof(struct f71882fg_sio_data));
2345 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002346 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002347 goto exit_device_put;
2348 }
2349
Hans de Goede45fb3662007-07-13 14:34:19 +02002350 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002351 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002352 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002353 goto exit_device_put;
2354 }
2355
2356 return 0;
2357
2358exit_device_put:
2359 platform_device_put(f71882fg_pdev);
2360
2361 return err;
2362}
2363
2364static int __init f71882fg_init(void)
2365{
2366 int err = -ENODEV;
2367 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002368 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002369
Hans de Goede498be962009-01-07 16:37:28 +01002370 memset(&sio_data, 0, sizeof(sio_data));
2371
2372 if (f71882fg_find(0x2e, &address, &sio_data) &&
2373 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002374 goto exit;
2375
Hans de Goedec13548c2009-01-07 16:37:27 +01002376 err = platform_driver_register(&f71882fg_driver);
2377 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002378 goto exit;
2379
Hans de Goede498be962009-01-07 16:37:28 +01002380 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002381 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002382 goto exit_driver;
2383
2384 return 0;
2385
2386exit_driver:
2387 platform_driver_unregister(&f71882fg_driver);
2388exit:
2389 return err;
2390}
2391
2392static void __exit f71882fg_exit(void)
2393{
2394 platform_device_unregister(f71882fg_pdev);
2395 platform_driver_unregister(&f71882fg_driver);
2396}
2397
2398MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002399MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002400MODULE_LICENSE("GPL");
2401
2402module_init(f71882fg_init);
2403module_exit(f71882fg_exit);