blob: 4230729780c4664c3b92ab329d1333b1888b84f5 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede3fc78382009-06-15 18:39:50 +02003 * Copyright (C) 2007-2009 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
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/slab.h>
24#include <linux/jiffies.h>
25#include <linux/platform_device.h>
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h>
29#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010030#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010031#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020032
33#define DRVNAME "f71882fg"
34
Hans de Goede09475d32009-06-15 18:39:52 +020035#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010036#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020037#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
38#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
39
40#define SIO_REG_LDSEL 0x07 /* Logical device select */
41#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
42#define SIO_REG_DEVREV 0x22 /* Device revision */
43#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
44#define SIO_REG_ENABLE 0x30 /* Logical device enable */
45#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
46
47#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020048#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010049#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020050#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010051#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010052#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020053
54#define REGION_LENGTH 8
55#define ADDR_REG_OFFSET 5
56#define DATA_REG_OFFSET 6
57
58#define F71882FG_REG_PECI 0x0A
59
Hans de Goede498be962009-01-07 16:37:28 +010060#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
61#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020062#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010063#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010066#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
67#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_FAN_STATUS 0x92
69#define F71882FG_REG_FAN_BEEP 0x93
70
Hans de Goede7567a042009-01-07 16:37:28 +010071#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
72#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
73#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_TEMP_STATUS 0x62
75#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020076#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010077#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020078#define F71882FG_REG_TEMP_TYPE 0x6B
79#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
80
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010081#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
82#define F71882FG_REG_PWM_TYPE 0x94
83#define F71882FG_REG_PWM_ENABLE 0x96
84
Hans de Goedebc274902009-01-07 16:37:29 +010085#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010086
87#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
88#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
89#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
90
Hans de Goede45fb3662007-07-13 14:34:19 +020091#define F71882FG_REG_START 0x01
92
93#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
94
Jean Delvare67b671b2007-12-06 23:13:42 +010095static unsigned short force_id;
96module_param(force_id, ushort, 0);
97MODULE_PARM_DESC(force_id, "Override the detected device ID");
98
Hans de Goede76698962009-12-09 20:36:01 +010099enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100100
101static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200102 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100103 "f71862fg",
104 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100105 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100106 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100107};
108
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100109static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200110
111/* Super-I/O Function prototypes */
112static inline int superio_inb(int base, int reg);
113static inline int superio_inw(int base, int reg);
114static inline void superio_enter(int base);
115static inline void superio_select(int base, int ld);
116static inline void superio_exit(int base);
117
Hans de Goede498be962009-01-07 16:37:28 +0100118struct f71882fg_sio_data {
119 enum chips type;
120};
121
Hans de Goede45fb3662007-07-13 14:34:19 +0200122struct f71882fg_data {
123 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100124 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700125 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200126
127 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200128 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200129 char valid; /* !=0 if following fields are valid */
130 unsigned long last_updated; /* In jiffies */
131 unsigned long last_limits; /* In jiffies */
132
133 /* Register Values */
134 u8 in[9];
135 u8 in1_max;
136 u8 in_status;
137 u8 in_beep;
138 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100139 u16 fan_target[4];
140 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200141 u8 fan_status;
142 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100143 /* Note: all models have only 3 temperature channels, but on some
144 they are addressed as 0-2 and on others as 1-3, so for coding
145 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200146 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100147 u8 temp_ovt[4];
148 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100149 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100150 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200151 u8 temp_status;
152 u8 temp_beep;
153 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200154 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100155 u8 pwm[4];
156 u8 pwm_enable;
157 u8 pwm_auto_point_hyst[2];
158 u8 pwm_auto_point_mapping[4];
159 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100160 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200161};
162
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100163/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200164static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
165 char *buf);
166static ssize_t show_in_max(struct device *dev, struct device_attribute
167 *devattr, char *buf);
168static ssize_t store_in_max(struct device *dev, struct device_attribute
169 *devattr, const char *buf, size_t count);
170static ssize_t show_in_beep(struct device *dev, struct device_attribute
171 *devattr, char *buf);
172static ssize_t store_in_beep(struct device *dev, struct device_attribute
173 *devattr, const char *buf, size_t count);
174static ssize_t show_in_alarm(struct device *dev, struct device_attribute
175 *devattr, char *buf);
176/* Sysfs Fan */
177static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
178 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100179static ssize_t show_fan_full_speed(struct device *dev,
180 struct device_attribute *devattr, char *buf);
181static ssize_t store_fan_full_speed(struct device *dev,
182 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200183static ssize_t show_fan_beep(struct device *dev, struct device_attribute
184 *devattr, char *buf);
185static ssize_t store_fan_beep(struct device *dev, struct device_attribute
186 *devattr, const char *buf, size_t count);
187static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
188 *devattr, char *buf);
189/* Sysfs Temp */
190static ssize_t show_temp(struct device *dev, struct device_attribute
191 *devattr, char *buf);
192static ssize_t show_temp_max(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t store_temp_max(struct device *dev, struct device_attribute
195 *devattr, const char *buf, size_t count);
196static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
197 *devattr, char *buf);
198static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
199 *devattr, const char *buf, size_t count);
200static ssize_t show_temp_crit(struct device *dev, struct device_attribute
201 *devattr, char *buf);
202static ssize_t store_temp_crit(struct device *dev, struct device_attribute
203 *devattr, const char *buf, size_t count);
204static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
205 *devattr, char *buf);
206static ssize_t show_temp_type(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t show_temp_beep(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t store_temp_beep(struct device *dev, struct device_attribute
211 *devattr, const char *buf, size_t count);
212static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
213 *devattr, char *buf);
214static ssize_t show_temp_fault(struct device *dev, struct device_attribute
215 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100216/* PWM and Auto point control */
217static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
218 char *buf);
219static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
220 const char *buf, size_t count);
221static ssize_t show_pwm_enable(struct device *dev,
222 struct device_attribute *devattr, char *buf);
223static ssize_t store_pwm_enable(struct device *dev,
224 struct device_attribute *devattr, const char *buf, size_t count);
225static ssize_t show_pwm_interpolate(struct device *dev,
226 struct device_attribute *devattr, char *buf);
227static ssize_t store_pwm_interpolate(struct device *dev,
228 struct device_attribute *devattr, const char *buf, size_t count);
229static ssize_t show_pwm_auto_point_channel(struct device *dev,
230 struct device_attribute *devattr, char *buf);
231static ssize_t store_pwm_auto_point_channel(struct device *dev,
232 struct device_attribute *devattr, const char *buf, size_t count);
233static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
234 struct device_attribute *devattr, char *buf);
235static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
236 struct device_attribute *devattr, const char *buf, size_t count);
237static ssize_t show_pwm_auto_point_pwm(struct device *dev,
238 struct device_attribute *devattr, char *buf);
239static ssize_t store_pwm_auto_point_pwm(struct device *dev,
240 struct device_attribute *devattr, const char *buf, size_t count);
241static ssize_t show_pwm_auto_point_temp(struct device *dev,
242 struct device_attribute *devattr, char *buf);
243static ssize_t store_pwm_auto_point_temp(struct device *dev,
244 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200245/* Sysfs misc */
246static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
247 char *buf);
248
249static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100250static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200251
252static struct platform_driver f71882fg_driver = {
253 .driver = {
254 .owner = THIS_MODULE,
255 .name = DRVNAME,
256 },
257 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200258 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200259};
260
Hans de Goedec13548c2009-01-07 16:37:27 +0100261static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200262
Hans de Goede66344aa2009-12-09 20:35:59 +0100263/* Temp and in attr for the f71858fg, the f71858fg is special as it
264 has its temperature indexes start at 0 (the others start at 1) and
265 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200266static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
267 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
268 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
269 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
270 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
271 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
272 store_temp_max, 0, 0),
273 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
274 store_temp_max_hyst, 0, 0),
275 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
276 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
277 store_temp_crit, 0, 0),
278 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
279 0, 0),
280 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
281 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
282 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
283 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
284 store_temp_max, 0, 1),
285 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
286 store_temp_max_hyst, 0, 1),
287 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
288 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
289 store_temp_crit, 0, 1),
290 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
291 0, 1),
292 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
293 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
294 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
295 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
296 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
297 store_temp_max, 0, 2),
298 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
299 store_temp_max_hyst, 0, 2),
300 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
301 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
302 store_temp_crit, 0, 2),
303 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
304 0, 2),
305 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
306 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
307};
308
Hans de Goede66344aa2009-12-09 20:35:59 +0100309/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
310static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100311 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
312 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100313 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
314 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
315 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
316 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
317 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
318 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
319 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100320 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100321 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100322 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100323 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100324 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100325 /* Should really be temp1_max_alarm, but older versions did not handle
326 the max and crit alarms separately and lm_sensors v2 depends on the
327 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
328 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
329 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
330 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100331 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100332 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100333 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100334 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100335 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
336 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
337 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100338 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100339 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
340 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
341 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100342 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100343 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100344 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100345 /* Should be temp2_max_alarm, see temp1_alarm note */
346 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
347 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
348 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100349 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100350 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100353 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
354 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
355 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100356 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100357 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
358 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
359 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
360 store_temp_max, 0, 3),
361 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
362 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100363 /* Should be temp3_max_alarm, see temp1_alarm note */
364 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
365 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
366 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100367 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
368 store_temp_crit, 0, 3),
369 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
370 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100371 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
372 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
373 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100374 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100375 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200376};
377
Hans de Goede66344aa2009-12-09 20:35:59 +0100378/* For models with in1 alarm capability */
379static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100380 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
381 0, 1),
382 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
383 0, 1),
384 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
385};
386
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100387/* Temp and in attr for the f8000
388 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
389 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100390 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100391 */
392static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
393 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
394 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
395 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
396 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
397 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
398 store_temp_crit, 0, 0),
399 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
400 store_temp_max, 0, 0),
401 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200402 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100403 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
404 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
405 store_temp_crit, 0, 1),
406 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
407 store_temp_max, 0, 1),
408 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
409 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200410 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100411 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
412 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
413 store_temp_crit, 0, 2),
414 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
415 store_temp_max, 0, 2),
416 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200417 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100418};
419
420/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100421static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100422 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100423 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
424 show_fan_full_speed,
425 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100427 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
428 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
429 store_pwm_enable, 0, 0),
430 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
431 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100432}, {
433 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
434 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
435 show_fan_full_speed,
436 store_fan_full_speed, 0, 1),
437 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100438 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
439 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
440 store_pwm_enable, 0, 1),
441 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
442 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100443}, {
444 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
445 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
446 show_fan_full_speed,
447 store_fan_full_speed, 0, 2),
448 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200449 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
450 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
451 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100452 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
453 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100454}, {
455 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
456 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
457 show_fan_full_speed,
458 store_fan_full_speed, 0, 3),
459 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
460 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
461 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
462 store_pwm_enable, 0, 3),
463 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
464 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
465} };
Hans de Goede498be962009-01-07 16:37:28 +0100466
Hans de Goede66344aa2009-12-09 20:35:59 +0100467/* Attr for models which can beep on Fan alarm */
468static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100469 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
470 store_fan_beep, 0, 0),
471 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
472 store_fan_beep, 0, 1),
473 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100475 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
476 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100477};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100478
Hans de Goede66344aa2009-12-09 20:35:59 +0100479/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
480 f71858fg / f71882fg / f71889fg */
481static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
482 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
483 show_pwm_auto_point_channel,
484 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100485 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
486 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
487 1, 0),
488 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
489 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
490 4, 0),
491 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
492 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
493 0, 0),
494 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
495 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
496 3, 0),
497 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
498 show_pwm_auto_point_temp_hyst,
499 store_pwm_auto_point_temp_hyst,
500 0, 0),
501 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
502 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
503
Hans de Goede66344aa2009-12-09 20:35:59 +0100504 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
505 show_pwm_auto_point_channel,
506 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100507 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
508 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
509 1, 1),
510 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
511 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
512 4, 1),
513 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
514 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
515 0, 1),
516 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
517 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
518 3, 1),
519 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
520 show_pwm_auto_point_temp_hyst,
521 store_pwm_auto_point_temp_hyst,
522 0, 1),
523 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
524 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100525
Hans de Goede66344aa2009-12-09 20:35:59 +0100526 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
527 show_pwm_auto_point_channel,
528 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100529 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
530 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
531 1, 2),
532 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
533 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
534 4, 2),
535 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
536 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
537 0, 2),
538 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
539 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
540 3, 2),
541 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
542 show_pwm_auto_point_temp_hyst,
543 store_pwm_auto_point_temp_hyst,
544 0, 2),
545 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
546 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100547};
548
Hans de Goede66344aa2009-12-09 20:35:59 +0100549/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100550static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100551 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
552 show_pwm_auto_point_channel,
553 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100554 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
555 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
556 0, 0),
557 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
558 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
559 1, 0),
560 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
561 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
562 2, 0),
563 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
564 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
565 3, 0),
566 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
567 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
568 4, 0),
569 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
570 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
571 0, 0),
572 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
573 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
574 1, 0),
575 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
576 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
577 2, 0),
578 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
579 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
580 3, 0),
581 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
582 show_pwm_auto_point_temp_hyst,
583 store_pwm_auto_point_temp_hyst,
584 0, 0),
585 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
586 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
587 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
588 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
589 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100591}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100592 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
593 show_pwm_auto_point_channel,
594 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100595 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
596 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
597 0, 1),
598 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
599 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
600 1, 1),
601 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
602 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
603 2, 1),
604 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
605 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
606 3, 1),
607 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
609 4, 1),
610 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
612 0, 1),
613 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
615 1, 1),
616 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
618 2, 1),
619 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
620 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
621 3, 1),
622 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
623 show_pwm_auto_point_temp_hyst,
624 store_pwm_auto_point_temp_hyst,
625 0, 1),
626 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
627 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
628 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
630 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
631 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100632}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100633 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
634 show_pwm_auto_point_channel,
635 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100636 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
637 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
638 0, 2),
639 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
640 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
641 1, 2),
642 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
643 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
644 2, 2),
645 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
646 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
647 3, 2),
648 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
649 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
650 4, 2),
651 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
652 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
653 0, 2),
654 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
656 1, 2),
657 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
659 2, 2),
660 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
662 3, 2),
663 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_temp_hyst,
665 store_pwm_auto_point_temp_hyst,
666 0, 2),
667 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
668 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
669 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
671 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
672 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100673}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100674 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
675 show_pwm_auto_point_channel,
676 store_pwm_auto_point_channel, 0, 3),
677 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
678 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
679 0, 3),
680 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
682 1, 3),
683 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
685 2, 3),
686 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
688 3, 3),
689 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
691 4, 3),
692 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
693 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
694 0, 3),
695 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
697 1, 3),
698 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
700 2, 3),
701 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
703 3, 3),
704 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_temp_hyst,
706 store_pwm_auto_point_temp_hyst,
707 0, 3),
708 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
709 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
710 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
712 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100714} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200715
Hans de Goede66344aa2009-12-09 20:35:59 +0100716/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100717static struct sensor_device_attribute_2 f8000_fan_attr[] = {
718 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100719};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100720
Hans de Goede66344aa2009-12-09 20:35:59 +0100721/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
722 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
723 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
724static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
725 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_channel,
727 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100728 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 0, 2),
731 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 1, 2),
734 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
736 2, 2),
737 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
739 3, 2),
740 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
742 4, 2),
743 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
744 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
745 0, 2),
746 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
747 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
748 1, 2),
749 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
751 2, 2),
752 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
754 3, 2),
755 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_temp_hyst,
757 store_pwm_auto_point_temp_hyst,
758 0, 2),
759 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
760 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
761 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
763 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
765
Hans de Goede66344aa2009-12-09 20:35:59 +0100766 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_channel,
768 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100769 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
771 0, 0),
772 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
774 1, 0),
775 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
777 2, 0),
778 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
779 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
780 3, 0),
781 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
782 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
783 4, 0),
784 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
785 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
786 0, 0),
787 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
788 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
789 1, 0),
790 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
791 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
792 2, 0),
793 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
794 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
795 3, 0),
796 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
797 show_pwm_auto_point_temp_hyst,
798 store_pwm_auto_point_temp_hyst,
799 0, 0),
800 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
801 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
802 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
804 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
806
Hans de Goede66344aa2009-12-09 20:35:59 +0100807 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
808 show_pwm_auto_point_channel,
809 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100810 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
811 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
812 0, 1),
813 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
814 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
815 1, 1),
816 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
817 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
818 2, 1),
819 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
820 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
821 3, 1),
822 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
823 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
824 4, 1),
825 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
826 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
827 0, 1),
828 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
829 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
830 1, 1),
831 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
832 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
833 2, 1),
834 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
835 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
836 3, 1),
837 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
838 show_pwm_auto_point_temp_hyst,
839 store_pwm_auto_point_temp_hyst,
840 0, 1),
841 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
842 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
843 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
845 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
847};
Hans de Goede45fb3662007-07-13 14:34:19 +0200848
849/* Super I/O functions */
850static inline int superio_inb(int base, int reg)
851{
852 outb(reg, base);
853 return inb(base + 1);
854}
855
856static int superio_inw(int base, int reg)
857{
858 int val;
859 outb(reg++, base);
860 val = inb(base + 1) << 8;
861 outb(reg, base);
862 val |= inb(base + 1);
863 return val;
864}
865
866static inline void superio_enter(int base)
867{
868 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200869 outb(SIO_UNLOCK_KEY, base);
870 outb(SIO_UNLOCK_KEY, base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200871}
872
Giel van Schijndel162bb592010-05-27 19:58:40 +0200873static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200874{
875 outb(SIO_REG_LDSEL, base);
876 outb(ld, base + 1);
877}
878
879static inline void superio_exit(int base)
880{
881 outb(SIO_LOCK_KEY, base);
882}
883
Hans de Goede2f650632009-01-07 16:37:31 +0100884static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200885{
886 return reg ? (1500000 / reg) : 0;
887}
888
Hans de Goede2f650632009-01-07 16:37:31 +0100889static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100890{
891 return fan ? (1500000 / fan) : 0;
892}
893
Hans de Goede45fb3662007-07-13 14:34:19 +0200894static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
895{
896 u8 val;
897
898 outb(reg, data->addr + ADDR_REG_OFFSET);
899 val = inb(data->addr + DATA_REG_OFFSET);
900
901 return val;
902}
903
904static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
905{
906 u16 val;
907
908 outb(reg++, data->addr + ADDR_REG_OFFSET);
909 val = inb(data->addr + DATA_REG_OFFSET) << 8;
910 outb(reg, data->addr + ADDR_REG_OFFSET);
911 val |= inb(data->addr + DATA_REG_OFFSET);
912
913 return val;
914}
915
916static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
917{
918 outb(reg, data->addr + ADDR_REG_OFFSET);
919 outb(val, data->addr + DATA_REG_OFFSET);
920}
921
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100922static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
923{
924 outb(reg++, data->addr + ADDR_REG_OFFSET);
925 outb(val >> 8, data->addr + DATA_REG_OFFSET);
926 outb(reg, data->addr + ADDR_REG_OFFSET);
927 outb(val & 255, data->addr + DATA_REG_OFFSET);
928}
929
Hans de Goede09475d32009-06-15 18:39:52 +0200930static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
931{
932 if (data->type == f71858fg)
933 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
934 else
935 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
936}
937
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100938static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200939{
940 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100941 int nr, reg = 0, reg2;
942 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200943 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200944
945 mutex_lock(&data->update_lock);
946
947 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200948 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200949 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100950 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100951 data->in1_max =
952 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
953 data->in_beep =
954 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
955 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200956
957 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200958 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200959 data->temp_ovt[nr] = f71882fg_read8(data,
960 F71882FG_REG_TEMP_OVT(nr));
961 data->temp_high[nr] = f71882fg_read8(data,
962 F71882FG_REG_TEMP_HIGH(nr));
963 }
964
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100965 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100966 data->temp_hyst[0] = f71882fg_read8(data,
967 F71882FG_REG_TEMP_HYST(0));
968 data->temp_hyst[1] = f71882fg_read8(data,
969 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200970 }
971
Hans de Goede76698962009-12-09 20:36:01 +0100972 if (data->type == f71862fg || data->type == f71882fg ||
973 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200974 data->fan_beep = f71882fg_read8(data,
975 F71882FG_REG_FAN_BEEP);
976 data->temp_beep = f71882fg_read8(data,
977 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100978 /* Have to hardcode type, because temp1 is special */
979 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
980 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
981 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
982 }
Hans de Goede76698962009-12-09 20:36:01 +0100983 /* Determine temp index 1 sensor type */
984 if (data->type == f71889fg) {
985 reg2 = f71882fg_read8(data, F71882FG_REG_START);
986 switch ((reg2 & 0x60) >> 5) {
987 case 0x00: /* BJT / Thermistor */
988 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
989 break;
990 case 0x01: /* AMDSI */
991 data->temp_type[1] = 5;
992 break;
993 case 0x02: /* PECI */
994 case 0x03: /* Ibex Peak ?? Report as PECI for now */
995 data->temp_type[1] = 6;
996 break;
997 }
998 } else {
999 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
1000 if ((reg2 & 0x03) == 0x01)
1001 data->temp_type[1] = 6; /* PECI */
1002 else if ((reg2 & 0x03) == 0x02)
1003 data->temp_type[1] = 5; /* AMDSI */
1004 else if (data->type == f71862fg ||
1005 data->type == f71882fg)
1006 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1007 else /* f71858fg and f8000 only support BJT */
1008 data->temp_type[1] = 2;
1009 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001010
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001011 data->pwm_enable = f71882fg_read8(data,
1012 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001013 data->pwm_auto_point_hyst[0] =
1014 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1015 data->pwm_auto_point_hyst[1] =
1016 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1017
Hans de Goede498be962009-01-07 16:37:28 +01001018 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001019 data->pwm_auto_point_mapping[nr] =
1020 f71882fg_read8(data,
1021 F71882FG_REG_POINT_MAPPING(nr));
1022
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001023 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001024 int point;
1025 for (point = 0; point < 5; point++) {
1026 data->pwm_auto_point_pwm[nr][point] =
1027 f71882fg_read8(data,
1028 F71882FG_REG_POINT_PWM
1029 (nr, point));
1030 }
1031 for (point = 0; point < 4; point++) {
1032 data->pwm_auto_point_temp[nr][point] =
1033 f71882fg_read8(data,
1034 F71882FG_REG_POINT_TEMP
1035 (nr, point));
1036 }
1037 } else {
1038 data->pwm_auto_point_pwm[nr][1] =
1039 f71882fg_read8(data,
1040 F71882FG_REG_POINT_PWM
1041 (nr, 1));
1042 data->pwm_auto_point_pwm[nr][4] =
1043 f71882fg_read8(data,
1044 F71882FG_REG_POINT_PWM
1045 (nr, 4));
1046 data->pwm_auto_point_temp[nr][0] =
1047 f71882fg_read8(data,
1048 F71882FG_REG_POINT_TEMP
1049 (nr, 0));
1050 data->pwm_auto_point_temp[nr][3] =
1051 f71882fg_read8(data,
1052 F71882FG_REG_POINT_TEMP
1053 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001054 }
1055 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001056 data->last_limits = jiffies;
1057 }
1058
1059 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001060 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001061 data->temp_status = f71882fg_read8(data,
1062 F71882FG_REG_TEMP_STATUS);
1063 data->temp_diode_open = f71882fg_read8(data,
1064 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001065 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1066 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001067
1068 data->fan_status = f71882fg_read8(data,
1069 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001070 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001071 data->fan[nr] = f71882fg_read16(data,
1072 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001073 data->fan_target[nr] =
1074 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1075 data->fan_full_speed[nr] =
1076 f71882fg_read16(data,
1077 F71882FG_REG_FAN_FULL_SPEED(nr));
1078 data->pwm[nr] =
1079 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1080 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001081
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001082 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1083 if (data->type == f8000)
1084 data->fan[3] = f71882fg_read16(data,
1085 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001086 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001087 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001088 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001089 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001090 data->in[nr] = f71882fg_read8(data,
1091 F71882FG_REG_IN(nr));
1092
1093 data->last_updated = jiffies;
1094 data->valid = 1;
1095 }
1096
1097 mutex_unlock(&data->update_lock);
1098
1099 return data;
1100}
1101
1102/* Sysfs Interface */
1103static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1104 char *buf)
1105{
1106 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001107 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001108 int speed = fan_from_reg(data->fan[nr]);
1109
1110 if (speed == FAN_MIN_DETECT)
1111 speed = 0;
1112
1113 return sprintf(buf, "%d\n", speed);
1114}
1115
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001116static ssize_t show_fan_full_speed(struct device *dev,
1117 struct device_attribute *devattr, char *buf)
1118{
1119 struct f71882fg_data *data = f71882fg_update_device(dev);
1120 int nr = to_sensor_dev_attr_2(devattr)->index;
1121 int speed = fan_from_reg(data->fan_full_speed[nr]);
1122 return sprintf(buf, "%d\n", speed);
1123}
1124
1125static ssize_t store_fan_full_speed(struct device *dev,
1126 struct device_attribute *devattr,
1127 const char *buf, size_t count)
1128{
1129 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001130 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1131 long val;
1132
1133 err = strict_strtol(buf, 10, &val);
1134 if (err)
1135 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001136
1137 val = SENSORS_LIMIT(val, 23, 1500000);
1138 val = fan_to_reg(val);
1139
1140 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001141 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1142 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001143 mutex_unlock(&data->update_lock);
1144
1145 return count;
1146}
1147
Hans de Goede45fb3662007-07-13 14:34:19 +02001148static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1149 *devattr, char *buf)
1150{
1151 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001152 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001153
1154 if (data->fan_beep & (1 << nr))
1155 return sprintf(buf, "1\n");
1156 else
1157 return sprintf(buf, "0\n");
1158}
1159
1160static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1161 *devattr, const char *buf, size_t count)
1162{
1163 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001164 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1165 unsigned long val;
1166
1167 err = strict_strtoul(buf, 10, &val);
1168 if (err)
1169 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001170
1171 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001172 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001173 if (val)
1174 data->fan_beep |= 1 << nr;
1175 else
1176 data->fan_beep &= ~(1 << nr);
1177
1178 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1179 mutex_unlock(&data->update_lock);
1180
1181 return count;
1182}
1183
1184static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1185 *devattr, char *buf)
1186{
1187 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001188 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001189
1190 if (data->fan_status & (1 << nr))
1191 return sprintf(buf, "1\n");
1192 else
1193 return sprintf(buf, "0\n");
1194}
1195
1196static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1197 char *buf)
1198{
1199 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001200 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001201
1202 return sprintf(buf, "%d\n", data->in[nr] * 8);
1203}
1204
1205static ssize_t show_in_max(struct device *dev, struct device_attribute
1206 *devattr, char *buf)
1207{
1208 struct f71882fg_data *data = f71882fg_update_device(dev);
1209
1210 return sprintf(buf, "%d\n", data->in1_max * 8);
1211}
1212
1213static ssize_t store_in_max(struct device *dev, struct device_attribute
1214 *devattr, const char *buf, size_t count)
1215{
1216 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001217 int err;
1218 long val;
1219
1220 err = strict_strtol(buf, 10, &val);
1221 if (err)
1222 return err;
1223
1224 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001225 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001226
1227 mutex_lock(&data->update_lock);
1228 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1229 data->in1_max = val;
1230 mutex_unlock(&data->update_lock);
1231
1232 return count;
1233}
1234
1235static ssize_t show_in_beep(struct device *dev, struct device_attribute
1236 *devattr, char *buf)
1237{
1238 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001239 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001240
1241 if (data->in_beep & (1 << nr))
1242 return sprintf(buf, "1\n");
1243 else
1244 return sprintf(buf, "0\n");
1245}
1246
1247static ssize_t store_in_beep(struct device *dev, struct device_attribute
1248 *devattr, const char *buf, size_t count)
1249{
1250 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001251 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1252 unsigned long val;
1253
1254 err = strict_strtoul(buf, 10, &val);
1255 if (err)
1256 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001257
1258 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001259 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001260 if (val)
1261 data->in_beep |= 1 << nr;
1262 else
1263 data->in_beep &= ~(1 << nr);
1264
1265 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1266 mutex_unlock(&data->update_lock);
1267
1268 return count;
1269}
1270
1271static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1272 *devattr, char *buf)
1273{
1274 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001275 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001276
1277 if (data->in_status & (1 << nr))
1278 return sprintf(buf, "1\n");
1279 else
1280 return sprintf(buf, "0\n");
1281}
1282
1283static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1284 char *buf)
1285{
1286 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001287 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001288 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001289
Hans de Goede09475d32009-06-15 18:39:52 +02001290 if (data->type == f71858fg) {
1291 /* TEMP_TABLE_SEL 1 or 3 ? */
1292 if (data->temp_config & 1) {
1293 sign = data->temp[nr] & 0x0001;
1294 temp = (data->temp[nr] >> 5) & 0x7ff;
1295 } else {
1296 sign = data->temp[nr] & 0x8000;
1297 temp = (data->temp[nr] >> 5) & 0x3ff;
1298 }
1299 temp *= 125;
1300 if (sign)
1301 temp -= 128000;
1302 } else
1303 temp = data->temp[nr] * 1000;
1304
1305 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001306}
1307
1308static ssize_t show_temp_max(struct device *dev, struct device_attribute
1309 *devattr, char *buf)
1310{
1311 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001312 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001313
1314 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1315}
1316
1317static ssize_t store_temp_max(struct device *dev, struct device_attribute
1318 *devattr, const char *buf, size_t count)
1319{
1320 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001321 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1322 long val;
1323
1324 err = strict_strtol(buf, 10, &val);
1325 if (err)
1326 return err;
1327
1328 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001329 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001330
1331 mutex_lock(&data->update_lock);
1332 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1333 data->temp_high[nr] = val;
1334 mutex_unlock(&data->update_lock);
1335
1336 return count;
1337}
1338
1339static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1340 *devattr, char *buf)
1341{
1342 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001343 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001344 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001345
Hans de Goedece0bfa52009-01-07 16:37:28 +01001346 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001347 if (nr & 1)
1348 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1349 else
1350 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1351 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001352 mutex_unlock(&data->update_lock);
1353
1354 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001355}
1356
1357static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1358 *devattr, const char *buf, size_t count)
1359{
1360 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001361 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001362 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001363 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001364 long val;
1365
1366 err = strict_strtol(buf, 10, &val);
1367 if (err)
1368 return err;
1369
1370 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001371
1372 mutex_lock(&data->update_lock);
1373
1374 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001375 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1376 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1377 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001378 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001379
1380 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001381 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1382 if (nr & 1)
1383 reg = (reg & 0x0f) | (val << 4);
1384 else
1385 reg = (reg & 0xf0) | val;
1386 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1387 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001388
Hans de Goede45fb3662007-07-13 14:34:19 +02001389 mutex_unlock(&data->update_lock);
1390 return ret;
1391}
1392
1393static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1394 *devattr, char *buf)
1395{
1396 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001397 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001398
1399 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1400}
1401
1402static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1403 *devattr, const char *buf, size_t count)
1404{
1405 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001406 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1407 long val;
1408
1409 err = strict_strtol(buf, 10, &val);
1410 if (err)
1411 return err;
1412
1413 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001414 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001415
1416 mutex_lock(&data->update_lock);
1417 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1418 data->temp_ovt[nr] = val;
1419 mutex_unlock(&data->update_lock);
1420
1421 return count;
1422}
1423
1424static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1425 *devattr, char *buf)
1426{
1427 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001428 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001429 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001430
Hans de Goedece0bfa52009-01-07 16:37:28 +01001431 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001432 if (nr & 1)
1433 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1434 else
1435 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1436 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001437 mutex_unlock(&data->update_lock);
1438
1439 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001440}
1441
1442static ssize_t show_temp_type(struct device *dev, struct device_attribute
1443 *devattr, char *buf)
1444{
1445 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001446 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001447
1448 return sprintf(buf, "%d\n", data->temp_type[nr]);
1449}
1450
1451static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1452 *devattr, char *buf)
1453{
1454 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001455 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001456
Hans de Goede7567a042009-01-07 16:37:28 +01001457 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001458 return sprintf(buf, "1\n");
1459 else
1460 return sprintf(buf, "0\n");
1461}
1462
1463static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1464 *devattr, const char *buf, size_t count)
1465{
1466 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001467 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1468 unsigned long val;
1469
1470 err = strict_strtoul(buf, 10, &val);
1471 if (err)
1472 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001473
1474 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001475 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001476 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001477 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001478 else
Hans de Goede7567a042009-01-07 16:37:28 +01001479 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001480
1481 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1482 mutex_unlock(&data->update_lock);
1483
1484 return count;
1485}
1486
1487static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1488 *devattr, char *buf)
1489{
1490 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001491 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001492
Hans de Goede7567a042009-01-07 16:37:28 +01001493 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001494 return sprintf(buf, "1\n");
1495 else
1496 return sprintf(buf, "0\n");
1497}
1498
1499static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1500 *devattr, char *buf)
1501{
1502 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001503 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001504
Hans de Goede7567a042009-01-07 16:37:28 +01001505 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001506 return sprintf(buf, "1\n");
1507 else
1508 return sprintf(buf, "0\n");
1509}
1510
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001511static ssize_t show_pwm(struct device *dev,
1512 struct device_attribute *devattr, char *buf)
1513{
1514 struct f71882fg_data *data = f71882fg_update_device(dev);
1515 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001516 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001517 if (data->pwm_enable & (1 << (2 * nr)))
1518 /* PWM mode */
1519 val = data->pwm[nr];
1520 else {
1521 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001522 val = 255 * fan_from_reg(data->fan_target[nr])
1523 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001524 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001525 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001526 return sprintf(buf, "%d\n", val);
1527}
1528
1529static ssize_t store_pwm(struct device *dev,
1530 struct device_attribute *devattr, const char *buf,
1531 size_t count)
1532{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001533 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001534 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1535 long val;
1536
1537 err = strict_strtol(buf, 10, &val);
1538 if (err)
1539 return err;
1540
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001541 val = SENSORS_LIMIT(val, 0, 255);
1542
1543 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001544 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001545 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1546 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1547 count = -EROFS;
1548 goto leave;
1549 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001550 if (data->pwm_enable & (1 << (2 * nr))) {
1551 /* PWM mode */
1552 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1553 data->pwm[nr] = val;
1554 } else {
1555 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001556 int target, full_speed;
1557 full_speed = f71882fg_read16(data,
1558 F71882FG_REG_FAN_FULL_SPEED(nr));
1559 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1560 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1561 data->fan_target[nr] = target;
1562 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001563 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001564leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001565 mutex_unlock(&data->update_lock);
1566
1567 return count;
1568}
1569
1570static ssize_t show_pwm_enable(struct device *dev,
1571 struct device_attribute *devattr, char *buf)
1572{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001573 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001574 struct f71882fg_data *data = f71882fg_update_device(dev);
1575 int nr = to_sensor_dev_attr_2(devattr)->index;
1576
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001577 switch ((data->pwm_enable >> 2 * nr) & 3) {
1578 case 0:
1579 case 1:
1580 result = 2; /* Normal auto mode */
1581 break;
1582 case 2:
1583 result = 1; /* Manual mode */
1584 break;
1585 case 3:
1586 if (data->type == f8000)
1587 result = 3; /* Thermostat mode */
1588 else
1589 result = 1; /* Manual mode */
1590 break;
1591 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001592
1593 return sprintf(buf, "%d\n", result);
1594}
1595
1596static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1597 *devattr, const char *buf, size_t count)
1598{
1599 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001600 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1601 long val;
1602
1603 err = strict_strtol(buf, 10, &val);
1604 if (err)
1605 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001606
Hans de Goede3fc78382009-06-15 18:39:50 +02001607 /* Special case for F8000 pwm channel 3 which only does auto mode */
1608 if (data->type == f8000 && nr == 2 && val != 2)
1609 return -EINVAL;
1610
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001611 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001612 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001613 /* Special case for F8000 auto PWM mode / Thermostat mode */
1614 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1615 switch (val) {
1616 case 2:
1617 data->pwm_enable &= ~(2 << (2 * nr));
1618 break; /* Normal auto mode */
1619 case 3:
1620 data->pwm_enable |= 2 << (2 * nr);
1621 break; /* Thermostat mode */
1622 default:
1623 count = -EINVAL;
1624 goto leave;
1625 }
1626 } else {
1627 switch (val) {
1628 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001629 /* The f71858fg does not support manual RPM mode */
1630 if (data->type == f71858fg &&
1631 ((data->pwm_enable >> (2 * nr)) & 1)) {
1632 count = -EINVAL;
1633 goto leave;
1634 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001635 data->pwm_enable |= 2 << (2 * nr);
1636 break; /* Manual */
1637 case 2:
1638 data->pwm_enable &= ~(2 << (2 * nr));
1639 break; /* Normal auto mode */
1640 default:
1641 count = -EINVAL;
1642 goto leave;
1643 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001644 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001645 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001646leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001647 mutex_unlock(&data->update_lock);
1648
1649 return count;
1650}
1651
1652static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1653 struct device_attribute *devattr,
1654 char *buf)
1655{
1656 int result;
1657 struct f71882fg_data *data = f71882fg_update_device(dev);
1658 int pwm = to_sensor_dev_attr_2(devattr)->index;
1659 int point = to_sensor_dev_attr_2(devattr)->nr;
1660
Hans de Goedece0bfa52009-01-07 16:37:28 +01001661 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001662 if (data->pwm_enable & (1 << (2 * pwm))) {
1663 /* PWM mode */
1664 result = data->pwm_auto_point_pwm[pwm][point];
1665 } else {
1666 /* RPM mode */
1667 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1668 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001669 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001670
1671 return sprintf(buf, "%d\n", result);
1672}
1673
1674static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1675 struct device_attribute *devattr,
1676 const char *buf, size_t count)
1677{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001678 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001679 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001680 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001681 long val;
1682
1683 err = strict_strtol(buf, 10, &val);
1684 if (err)
1685 return err;
1686
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001687 val = SENSORS_LIMIT(val, 0, 255);
1688
1689 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001690 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001691 if (data->pwm_enable & (1 << (2 * pwm))) {
1692 /* PWM mode */
1693 } else {
1694 /* RPM mode */
1695 if (val < 29) /* Prevent negative numbers */
1696 val = 255;
1697 else
1698 val = (255 - val) * 32 / val;
1699 }
1700 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1701 data->pwm_auto_point_pwm[pwm][point] = val;
1702 mutex_unlock(&data->update_lock);
1703
1704 return count;
1705}
1706
1707static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1708 struct device_attribute *devattr,
1709 char *buf)
1710{
1711 int result = 0;
1712 struct f71882fg_data *data = f71882fg_update_device(dev);
1713 int nr = to_sensor_dev_attr_2(devattr)->index;
1714 int point = to_sensor_dev_attr_2(devattr)->nr;
1715
1716 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001717 if (nr & 1)
1718 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1719 else
1720 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001721 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1722 mutex_unlock(&data->update_lock);
1723
1724 return sprintf(buf, "%d\n", result);
1725}
1726
1727static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1728 struct device_attribute *devattr,
1729 const char *buf, size_t count)
1730{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001731 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001732 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001733 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001734 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001735 long val;
1736
1737 err = strict_strtol(buf, 10, &val);
1738 if (err)
1739 return err;
1740
1741 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001742
1743 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001744 data->pwm_auto_point_temp[nr][point] =
1745 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001746 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1747 data->pwm_auto_point_temp[nr][point]);
1748 val = data->pwm_auto_point_temp[nr][point] - val;
1749
Hans de Goedebc274902009-01-07 16:37:29 +01001750 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1751 if (nr & 1)
1752 reg = (reg & 0x0f) | (val << 4);
1753 else
1754 reg = (reg & 0xf0) | val;
1755
1756 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1757 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001758 mutex_unlock(&data->update_lock);
1759
1760 return count;
1761}
1762
1763static ssize_t show_pwm_interpolate(struct device *dev,
1764 struct device_attribute *devattr, char *buf)
1765{
1766 int result;
1767 struct f71882fg_data *data = f71882fg_update_device(dev);
1768 int nr = to_sensor_dev_attr_2(devattr)->index;
1769
1770 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1771
1772 return sprintf(buf, "%d\n", result);
1773}
1774
1775static ssize_t store_pwm_interpolate(struct device *dev,
1776 struct device_attribute *devattr,
1777 const char *buf, size_t count)
1778{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001779 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001780 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1781 unsigned long val;
1782
1783 err = strict_strtoul(buf, 10, &val);
1784 if (err)
1785 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001786
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001787 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001788 data->pwm_auto_point_mapping[nr] =
1789 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001790 if (val)
1791 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1792 else
1793 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1794 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1795 data->pwm_auto_point_mapping[nr] = val;
1796 mutex_unlock(&data->update_lock);
1797
1798 return count;
1799}
1800
1801static ssize_t show_pwm_auto_point_channel(struct device *dev,
1802 struct device_attribute *devattr,
1803 char *buf)
1804{
1805 int result;
1806 struct f71882fg_data *data = f71882fg_update_device(dev);
1807 int nr = to_sensor_dev_attr_2(devattr)->index;
1808
Hans de Goede09475d32009-06-15 18:39:52 +02001809 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1810 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001811
1812 return sprintf(buf, "%d\n", result);
1813}
1814
1815static ssize_t store_pwm_auto_point_channel(struct device *dev,
1816 struct device_attribute *devattr,
1817 const char *buf, size_t count)
1818{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001819 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001820 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1821 long val;
1822
1823 err = strict_strtol(buf, 10, &val);
1824 if (err)
1825 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001826
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001827 switch (val) {
1828 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001829 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001830 break;
1831 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001832 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001833 break;
1834 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001835 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001836 break;
1837 default:
1838 return -EINVAL;
1839 }
Hans de Goede09475d32009-06-15 18:39:52 +02001840 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001842 data->pwm_auto_point_mapping[nr] =
1843 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001844 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1845 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1846 data->pwm_auto_point_mapping[nr] = val;
1847 mutex_unlock(&data->update_lock);
1848
1849 return count;
1850}
1851
1852static ssize_t show_pwm_auto_point_temp(struct device *dev,
1853 struct device_attribute *devattr,
1854 char *buf)
1855{
1856 int result;
1857 struct f71882fg_data *data = f71882fg_update_device(dev);
1858 int pwm = to_sensor_dev_attr_2(devattr)->index;
1859 int point = to_sensor_dev_attr_2(devattr)->nr;
1860
1861 result = data->pwm_auto_point_temp[pwm][point];
1862 return sprintf(buf, "%d\n", 1000 * result);
1863}
1864
1865static ssize_t store_pwm_auto_point_temp(struct device *dev,
1866 struct device_attribute *devattr,
1867 const char *buf, size_t count)
1868{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001869 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001870 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001871 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001872 long val;
1873
1874 err = strict_strtol(buf, 10, &val);
1875 if (err)
1876 return err;
1877
1878 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001879
1880 if (data->type == f71889fg)
1881 val = SENSORS_LIMIT(val, -128, 127);
1882 else
1883 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001884
1885 mutex_lock(&data->update_lock);
1886 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1887 data->pwm_auto_point_temp[pwm][point] = val;
1888 mutex_unlock(&data->update_lock);
1889
1890 return count;
1891}
1892
Hans de Goede45fb3662007-07-13 14:34:19 +02001893static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1894 char *buf)
1895{
Hans de Goede498be962009-01-07 16:37:28 +01001896 struct f71882fg_data *data = dev_get_drvdata(dev);
1897 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001898}
1899
Hans de Goedec13548c2009-01-07 16:37:27 +01001900static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1901 struct sensor_device_attribute_2 *attr, int count)
1902{
1903 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001904
Hans de Goedec13548c2009-01-07 16:37:27 +01001905 for (i = 0; i < count; i++) {
1906 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1907 if (err)
1908 return err;
1909 }
1910 return 0;
1911}
1912
Hans de Goedefc16c562009-12-09 20:36:01 +01001913static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1914 struct sensor_device_attribute_2 *attr, int count)
1915{
1916 int i;
1917
1918 for (i = 0; i < count; i++)
1919 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1920}
1921
Hans de Goedec13548c2009-01-07 16:37:27 +01001922static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001923{
1924 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001925 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001926 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001927 u8 start_reg;
1928
Hans de Goedec13548c2009-01-07 16:37:27 +01001929 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1930 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001931 return -ENOMEM;
1932
1933 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001934 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001935 data->temp_start =
1936 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001937 mutex_init(&data->update_lock);
1938 platform_set_drvdata(pdev, data);
1939
Hans de Goede3cc74752009-01-07 16:37:28 +01001940 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001941 if (start_reg & 0x04) {
1942 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1943 err = -ENODEV;
1944 goto exit_free;
1945 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001946 if (!(start_reg & 0x03)) {
1947 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1948 err = -ENODEV;
1949 goto exit_free;
1950 }
1951
Hans de Goede45fb3662007-07-13 14:34:19 +02001952 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001953 err = device_create_file(&pdev->dev, &dev_attr_name);
1954 if (err)
1955 goto exit_unregister_sysfs;
1956
Hans de Goedec13548c2009-01-07 16:37:27 +01001957 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001958 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001959 case f71858fg:
1960 data->temp_config =
1961 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1962 if (data->temp_config & 0x10)
1963 /* The f71858fg temperature alarms behave as
1964 the f8000 alarms in this mode */
1965 err = f71882fg_create_sysfs_files(pdev,
1966 f8000_in_temp_attr,
1967 ARRAY_SIZE(f8000_in_temp_attr));
1968 else
1969 err = f71882fg_create_sysfs_files(pdev,
1970 f71858fg_in_temp_attr,
1971 ARRAY_SIZE(f71858fg_in_temp_attr));
1972 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001973 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001974 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001975 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001976 fxxxx_in1_alarm_attr,
1977 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001978 if (err)
1979 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001980 /* fall through! */
1981 case f71862fg:
1982 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001983 fxxxx_in_temp_attr,
1984 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001985 break;
1986 case f8000:
1987 err = f71882fg_create_sysfs_files(pdev,
1988 f8000_in_temp_attr,
1989 ARRAY_SIZE(f8000_in_temp_attr));
1990 break;
Hans de Goede498be962009-01-07 16:37:28 +01001991 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001992 if (err)
1993 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001994 }
1995
Hans de Goede45fb3662007-07-13 14:34:19 +02001996 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02001997 data->pwm_enable =
1998 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
1999
2000 /* Sanity check the pwm settings */
2001 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002002 case f71858fg:
2003 err = 0;
2004 for (i = 0; i < nr_fans; i++)
2005 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2006 err = 1;
2007 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002008 case f71862fg:
2009 err = (data->pwm_enable & 0x15) != 0x15;
2010 break;
2011 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002012 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002013 err = 0;
2014 break;
2015 case f8000:
2016 err = data->pwm_enable & 0x20;
2017 break;
2018 }
2019 if (err) {
2020 dev_err(&pdev->dev,
2021 "Invalid (reserved) pwm settings: 0x%02x\n",
2022 (unsigned int)data->pwm_enable);
2023 err = -ENODEV;
2024 goto exit_unregister_sysfs;
2025 }
2026
Hans de Goedeb69b0392009-12-09 20:36:00 +01002027 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2028 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002029 if (err)
2030 goto exit_unregister_sysfs;
2031
Hans de Goede76698962009-12-09 20:36:01 +01002032 if (data->type == f71862fg || data->type == f71882fg ||
2033 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002034 err = f71882fg_create_sysfs_files(pdev,
2035 fxxxx_fan_beep_attr, nr_fans);
2036 if (err)
2037 goto exit_unregister_sysfs;
2038 }
2039
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002040 switch (data->type) {
2041 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002042 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002043 f71862fg_auto_pwm_attr,
2044 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002045 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002046 case f8000:
2047 err = f71882fg_create_sysfs_files(pdev,
2048 f8000_fan_attr,
2049 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002050 if (err)
2051 goto exit_unregister_sysfs;
2052 err = f71882fg_create_sysfs_files(pdev,
2053 f8000_auto_pwm_attr,
2054 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002055 break;
Hans de Goede76698962009-12-09 20:36:01 +01002056 case f71889fg:
2057 for (i = 0; i < nr_fans; i++) {
2058 data->pwm_auto_point_mapping[i] =
2059 f71882fg_read8(data,
2060 F71882FG_REG_POINT_MAPPING(i));
2061 if (data->pwm_auto_point_mapping[i] & 0x80)
2062 break;
2063 }
2064 if (i != nr_fans) {
2065 dev_warn(&pdev->dev,
2066 "Auto pwm controlled by raw digital "
2067 "data, disabling pwm auto_point "
2068 "sysfs attributes\n");
2069 break;
2070 }
2071 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002072 default: /* f71858fg / f71882fg */
2073 err = f71882fg_create_sysfs_files(pdev,
2074 &fxxxx_auto_pwm_attr[0][0],
2075 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002076 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002077 if (err)
2078 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002079
2080 for (i = 0; i < nr_fans; i++)
2081 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2082 (data->pwm_enable & (1 << 2 * i)) ?
2083 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002084 }
2085
Tony Jones1beeffe2007-08-20 13:46:20 -07002086 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2087 if (IS_ERR(data->hwmon_dev)) {
2088 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002089 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002090 goto exit_unregister_sysfs;
2091 }
2092
2093 return 0;
2094
2095exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002096 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002097 return err; /* f71882fg_remove() also frees our data */
2098exit_free:
2099 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002100 return err;
2101}
2102
Hans de Goedec13548c2009-01-07 16:37:27 +01002103static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002104{
Hans de Goede45fb3662007-07-13 14:34:19 +02002105 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002106 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2107 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002108
2109 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002110 if (data->hwmon_dev)
2111 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002112
Hans de Goedec13548c2009-01-07 16:37:27 +01002113 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002114
Hans de Goedefc16c562009-12-09 20:36:01 +01002115 if (start_reg & 0x01) {
2116 switch (data->type) {
2117 case f71858fg:
2118 if (data->temp_config & 0x10)
2119 f71882fg_remove_sysfs_files(pdev,
2120 f8000_in_temp_attr,
2121 ARRAY_SIZE(f8000_in_temp_attr));
2122 else
2123 f71882fg_remove_sysfs_files(pdev,
2124 f71858fg_in_temp_attr,
2125 ARRAY_SIZE(f71858fg_in_temp_attr));
2126 break;
2127 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002128 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002129 f71882fg_remove_sysfs_files(pdev,
2130 fxxxx_in1_alarm_attr,
2131 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2132 /* fall through! */
2133 case f71862fg:
2134 f71882fg_remove_sysfs_files(pdev,
2135 fxxxx_in_temp_attr,
2136 ARRAY_SIZE(fxxxx_in_temp_attr));
2137 break;
2138 case f8000:
2139 f71882fg_remove_sysfs_files(pdev,
2140 f8000_in_temp_attr,
2141 ARRAY_SIZE(f8000_in_temp_attr));
2142 break;
2143 }
2144 }
Hans de Goede498be962009-01-07 16:37:28 +01002145
Hans de Goedefc16c562009-12-09 20:36:01 +01002146 if (start_reg & 0x02) {
2147 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2148 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002149
Hans de Goede76698962009-12-09 20:36:01 +01002150 if (data->type == f71862fg || data->type == f71882fg ||
2151 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002152 f71882fg_remove_sysfs_files(pdev,
2153 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002154
Hans de Goedefc16c562009-12-09 20:36:01 +01002155 switch (data->type) {
2156 case f71862fg:
2157 f71882fg_remove_sysfs_files(pdev,
2158 f71862fg_auto_pwm_attr,
2159 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2160 break;
2161 case f8000:
2162 f71882fg_remove_sysfs_files(pdev,
2163 f8000_fan_attr,
2164 ARRAY_SIZE(f8000_fan_attr));
2165 f71882fg_remove_sysfs_files(pdev,
2166 f8000_auto_pwm_attr,
2167 ARRAY_SIZE(f8000_auto_pwm_attr));
2168 break;
2169 default: /* f71858fg / f71882fg / f71889fg */
2170 f71882fg_remove_sysfs_files(pdev,
2171 &fxxxx_auto_pwm_attr[0][0],
2172 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2173 }
2174 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002175
Hans de Goede45fb3662007-07-13 14:34:19 +02002176 kfree(data);
2177
2178 return 0;
2179}
2180
Hans de Goede498be962009-01-07 16:37:28 +01002181static int __init f71882fg_find(int sioaddr, unsigned short *address,
2182 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002183{
2184 int err = -ENODEV;
2185 u16 devid;
Hans de Goede45fb3662007-07-13 14:34:19 +02002186
2187 superio_enter(sioaddr);
2188
2189 devid = superio_inw(sioaddr, SIO_REG_MANID);
2190 if (devid != SIO_FINTEK_ID) {
Jean Delvare603eaa12009-02-17 19:59:54 +01002191 pr_debug(DRVNAME ": Not a Fintek device\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002192 goto exit;
2193 }
2194
Jean Delvare67b671b2007-12-06 23:13:42 +01002195 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002196 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002197 case SIO_F71858_ID:
2198 sio_data->type = f71858fg;
2199 break;
Hans de Goede498be962009-01-07 16:37:28 +01002200 case SIO_F71862_ID:
2201 sio_data->type = f71862fg;
2202 break;
2203 case SIO_F71882_ID:
2204 sio_data->type = f71882fg;
2205 break;
Hans de Goede76698962009-12-09 20:36:01 +01002206 case SIO_F71889_ID:
2207 sio_data->type = f71889fg;
2208 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002209 case SIO_F8000_ID:
2210 sio_data->type = f8000;
2211 break;
Hans de Goede498be962009-01-07 16:37:28 +01002212 default:
Hans de Goede76698962009-12-09 20:36:01 +01002213 printk(KERN_INFO DRVNAME ": Unsupported Fintek device: %04x\n",
2214 (unsigned int)devid);
Hans de Goede45fb3662007-07-13 14:34:19 +02002215 goto exit;
2216 }
2217
Hans de Goede09475d32009-06-15 18:39:52 +02002218 if (sio_data->type == f71858fg)
2219 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2220 else
2221 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2222
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002223 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002224 printk(KERN_WARNING DRVNAME ": Device not activated\n");
2225 goto exit;
2226 }
2227
2228 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002229 if (*address == 0) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002230 printk(KERN_WARNING DRVNAME ": Base address not set\n");
2231 goto exit;
2232 }
2233 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2234
Hans de Goede45fb3662007-07-13 14:34:19 +02002235 err = 0;
Hans de Goede498be962009-01-07 16:37:28 +01002236 printk(KERN_INFO DRVNAME ": Found %s chip at %#x, revision %d\n",
2237 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002238 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2239exit:
2240 superio_exit(sioaddr);
2241 return err;
2242}
2243
Hans de Goede498be962009-01-07 16:37:28 +01002244static int __init f71882fg_device_add(unsigned short address,
2245 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002246{
2247 struct resource res = {
2248 .start = address,
2249 .end = address + REGION_LENGTH - 1,
2250 .flags = IORESOURCE_IO,
2251 };
2252 int err;
2253
2254 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002255 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002256 return -ENOMEM;
2257
2258 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002259 err = acpi_check_resource_conflict(&res);
2260 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002261 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002262
Hans de Goede45fb3662007-07-13 14:34:19 +02002263 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002264 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002265 printk(KERN_ERR DRVNAME ": Device resource addition failed\n");
2266 goto exit_device_put;
2267 }
2268
Hans de Goede498be962009-01-07 16:37:28 +01002269 err = platform_device_add_data(f71882fg_pdev, sio_data,
2270 sizeof(struct f71882fg_sio_data));
2271 if (err) {
2272 printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
2273 goto exit_device_put;
2274 }
2275
Hans de Goede45fb3662007-07-13 14:34:19 +02002276 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002277 if (err) {
Hans de Goede45fb3662007-07-13 14:34:19 +02002278 printk(KERN_ERR DRVNAME ": Device addition failed\n");
2279 goto exit_device_put;
2280 }
2281
2282 return 0;
2283
2284exit_device_put:
2285 platform_device_put(f71882fg_pdev);
2286
2287 return err;
2288}
2289
2290static int __init f71882fg_init(void)
2291{
2292 int err = -ENODEV;
2293 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002294 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002295
Hans de Goede498be962009-01-07 16:37:28 +01002296 memset(&sio_data, 0, sizeof(sio_data));
2297
2298 if (f71882fg_find(0x2e, &address, &sio_data) &&
2299 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002300 goto exit;
2301
Hans de Goedec13548c2009-01-07 16:37:27 +01002302 err = platform_driver_register(&f71882fg_driver);
2303 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002304 goto exit;
2305
Hans de Goede498be962009-01-07 16:37:28 +01002306 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002307 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002308 goto exit_driver;
2309
2310 return 0;
2311
2312exit_driver:
2313 platform_driver_unregister(&f71882fg_driver);
2314exit:
2315 return err;
2316}
2317
2318static void __exit f71882fg_exit(void)
2319{
2320 platform_device_unregister(f71882fg_pdev);
2321 platform_driver_unregister(&f71882fg_driver);
2322}
2323
2324MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002325MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002326MODULE_LICENSE("GPL");
2327
2328module_init(f71882fg_init);
2329module_exit(f71882fg_exit);