blob: 3f49dd376f023e1e6d4a281bc84ae9f05c59288a [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
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
40#define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */
41
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goede09475d32009-06-15 18:39:52 +020050#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010051#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020052#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010053#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010054#define SIO_F8000_ID 0x0581 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020055
56#define REGION_LENGTH 8
57#define ADDR_REG_OFFSET 5
58#define DATA_REG_OFFSET 6
59
60#define F71882FG_REG_PECI 0x0A
61
Hans de Goede498be962009-01-07 16:37:28 +010062#define F71882FG_REG_IN_STATUS 0x12 /* f71882fg only */
63#define F71882FG_REG_IN_BEEP 0x13 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020064#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede498be962009-01-07 16:37:28 +010065#define F71882FG_REG_IN1_HIGH 0x32 /* f71882fg only */
Hans de Goede45fb3662007-07-13 14:34:19 +020066
67#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010068#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
69#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020070#define F71882FG_REG_FAN_STATUS 0x92
71#define F71882FG_REG_FAN_BEEP 0x93
72
Hans de Goede7567a042009-01-07 16:37:28 +010073#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
74#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
75#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020076#define F71882FG_REG_TEMP_STATUS 0x62
77#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020078#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010079#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020080#define F71882FG_REG_TEMP_TYPE 0x6B
81#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
82
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010083#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
84#define F71882FG_REG_PWM_TYPE 0x94
85#define F71882FG_REG_PWM_ENABLE 0x96
86
Hans de Goedebc274902009-01-07 16:37:29 +010087#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010088
89#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
90#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
91#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
92
Hans de Goede45fb3662007-07-13 14:34:19 +020093#define F71882FG_REG_START 0x01
94
95#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
96
Jean Delvare67b671b2007-12-06 23:13:42 +010097static unsigned short force_id;
98module_param(force_id, ushort, 0);
99MODULE_PARM_DESC(force_id, "Override the detected device ID");
100
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700101enum chips { f71858fg, f71862fg, f71882fg, f71889fg, f8000 };
Hans de Goede498be962009-01-07 16:37:28 +0100102
103static const char *f71882fg_names[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200104 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100105 "f71862fg",
106 "f71882fg",
Hans de Goede76698962009-12-09 20:36:01 +0100107 "f71889fg",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100108 "f8000",
Hans de Goede498be962009-01-07 16:37:28 +0100109};
110
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100111static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200112
113/* Super-I/O Function prototypes */
114static inline int superio_inb(int base, int reg);
115static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400116static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200117static inline void superio_select(int base, int ld);
118static inline void superio_exit(int base);
119
Hans de Goede498be962009-01-07 16:37:28 +0100120struct f71882fg_sio_data {
121 enum chips type;
122};
123
Hans de Goede45fb3662007-07-13 14:34:19 +0200124struct f71882fg_data {
125 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100126 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700127 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200128
129 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200130 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200131 char valid; /* !=0 if following fields are valid */
132 unsigned long last_updated; /* In jiffies */
133 unsigned long last_limits; /* In jiffies */
134
135 /* Register Values */
136 u8 in[9];
137 u8 in1_max;
138 u8 in_status;
139 u8 in_beep;
140 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100141 u16 fan_target[4];
142 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200143 u8 fan_status;
144 u8 fan_beep;
Hans de Goede7567a042009-01-07 16:37:28 +0100145 /* Note: all models have only 3 temperature channels, but on some
146 they are addressed as 0-2 and on others as 1-3, so for coding
147 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200148 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100149 u8 temp_ovt[4];
150 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100151 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100152 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200153 u8 temp_status;
154 u8 temp_beep;
155 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200156 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100157 u8 pwm[4];
158 u8 pwm_enable;
159 u8 pwm_auto_point_hyst[2];
160 u8 pwm_auto_point_mapping[4];
161 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100162 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200163};
164
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100165/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200166static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
167 char *buf);
168static ssize_t show_in_max(struct device *dev, struct device_attribute
169 *devattr, char *buf);
170static ssize_t store_in_max(struct device *dev, struct device_attribute
171 *devattr, const char *buf, size_t count);
172static ssize_t show_in_beep(struct device *dev, struct device_attribute
173 *devattr, char *buf);
174static ssize_t store_in_beep(struct device *dev, struct device_attribute
175 *devattr, const char *buf, size_t count);
176static ssize_t show_in_alarm(struct device *dev, struct device_attribute
177 *devattr, char *buf);
178/* Sysfs Fan */
179static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
180 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100181static ssize_t show_fan_full_speed(struct device *dev,
182 struct device_attribute *devattr, char *buf);
183static ssize_t store_fan_full_speed(struct device *dev,
184 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200185static ssize_t show_fan_beep(struct device *dev, struct device_attribute
186 *devattr, char *buf);
187static ssize_t store_fan_beep(struct device *dev, struct device_attribute
188 *devattr, const char *buf, size_t count);
189static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
190 *devattr, char *buf);
191/* Sysfs Temp */
192static ssize_t show_temp(struct device *dev, struct device_attribute
193 *devattr, char *buf);
194static ssize_t show_temp_max(struct device *dev, struct device_attribute
195 *devattr, char *buf);
196static ssize_t store_temp_max(struct device *dev, struct device_attribute
197 *devattr, const char *buf, size_t count);
198static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
199 *devattr, char *buf);
200static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
201 *devattr, const char *buf, size_t count);
202static ssize_t show_temp_crit(struct device *dev, struct device_attribute
203 *devattr, char *buf);
204static ssize_t store_temp_crit(struct device *dev, struct device_attribute
205 *devattr, const char *buf, size_t count);
206static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
207 *devattr, char *buf);
208static ssize_t show_temp_type(struct device *dev, struct device_attribute
209 *devattr, char *buf);
210static ssize_t show_temp_beep(struct device *dev, struct device_attribute
211 *devattr, char *buf);
212static ssize_t store_temp_beep(struct device *dev, struct device_attribute
213 *devattr, const char *buf, size_t count);
214static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
215 *devattr, char *buf);
216static ssize_t show_temp_fault(struct device *dev, struct device_attribute
217 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100218/* PWM and Auto point control */
219static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
220 char *buf);
221static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
222 const char *buf, size_t count);
223static ssize_t show_pwm_enable(struct device *dev,
224 struct device_attribute *devattr, char *buf);
225static ssize_t store_pwm_enable(struct device *dev,
226 struct device_attribute *devattr, const char *buf, size_t count);
227static ssize_t show_pwm_interpolate(struct device *dev,
228 struct device_attribute *devattr, char *buf);
229static ssize_t store_pwm_interpolate(struct device *dev,
230 struct device_attribute *devattr, const char *buf, size_t count);
231static ssize_t show_pwm_auto_point_channel(struct device *dev,
232 struct device_attribute *devattr, char *buf);
233static ssize_t store_pwm_auto_point_channel(struct device *dev,
234 struct device_attribute *devattr, const char *buf, size_t count);
235static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
236 struct device_attribute *devattr, char *buf);
237static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
238 struct device_attribute *devattr, const char *buf, size_t count);
239static ssize_t show_pwm_auto_point_pwm(struct device *dev,
240 struct device_attribute *devattr, char *buf);
241static ssize_t store_pwm_auto_point_pwm(struct device *dev,
242 struct device_attribute *devattr, const char *buf, size_t count);
243static ssize_t show_pwm_auto_point_temp(struct device *dev,
244 struct device_attribute *devattr, char *buf);
245static ssize_t store_pwm_auto_point_temp(struct device *dev,
246 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200247/* Sysfs misc */
248static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
249 char *buf);
250
251static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100252static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200253
254static struct platform_driver f71882fg_driver = {
255 .driver = {
256 .owner = THIS_MODULE,
257 .name = DRVNAME,
258 },
259 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200260 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200261};
262
Hans de Goedec13548c2009-01-07 16:37:27 +0100263static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200264
Hans de Goede66344aa2009-12-09 20:35:59 +0100265/* Temp and in attr for the f71858fg, the f71858fg is special as it
266 has its temperature indexes start at 0 (the others start at 1) and
267 it only has 3 voltage inputs */
Hans de Goede09475d32009-06-15 18:39:52 +0200268static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
269 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
270 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
271 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
272 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
273 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
274 store_temp_max, 0, 0),
275 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
276 store_temp_max_hyst, 0, 0),
277 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
278 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
279 store_temp_crit, 0, 0),
280 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
281 0, 0),
282 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
283 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
284 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
285 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
286 store_temp_max, 0, 1),
287 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
288 store_temp_max_hyst, 0, 1),
289 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
290 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
291 store_temp_crit, 0, 1),
292 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
293 0, 1),
294 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
295 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
296 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
297 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
298 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
299 store_temp_max, 0, 2),
300 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
301 store_temp_max_hyst, 0, 2),
302 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
303 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
304 store_temp_crit, 0, 2),
305 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
306 0, 2),
307 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
308 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
309};
310
Andrew Mortonf2e41e92010-08-19 14:13:31 -0700311/* Temp and in attr common to the f71862fg, f71882fg and f71889fg */
312static struct sensor_device_attribute_2 fxxxx_in_temp_attr[] = {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100313 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
314 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100315 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
316 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
317 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
318 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
319 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
320 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
321 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Hans de Goede7567a042009-01-07 16:37:28 +0100322 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100323 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100324 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100325 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100326 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100327 /* Should really be temp1_max_alarm, but older versions did not handle
328 the max and crit alarms separately and lm_sensors v2 depends on the
329 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
330 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
331 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
332 store_temp_beep, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100333 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100334 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100335 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100336 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100337 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
338 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
339 store_temp_beep, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100340 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100341 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
342 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
343 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100344 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100345 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100346 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100347 /* Should be temp2_max_alarm, see temp1_alarm note */
348 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
349 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
350 store_temp_beep, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100351 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100352 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100353 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100354 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100355 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
356 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
357 store_temp_beep, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100358 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100359 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
360 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
361 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
362 store_temp_max, 0, 3),
363 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
364 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100365 /* Should be temp3_max_alarm, see temp1_alarm note */
366 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
367 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
368 store_temp_beep, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100369 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
370 store_temp_crit, 0, 3),
371 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
372 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100373 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
374 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
375 store_temp_beep, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100376 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100377 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede45fb3662007-07-13 14:34:19 +0200378};
379
Hans de Goede66344aa2009-12-09 20:35:59 +0100380/* For models with in1 alarm capability */
381static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
Hans de Goede498be962009-01-07 16:37:28 +0100382 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
383 0, 1),
384 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
385 0, 1),
386 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
387};
388
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100389/* Temp and in attr for the f8000
390 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
391 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100392 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100393 */
394static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
395 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
396 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
397 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
398 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
399 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
400 store_temp_crit, 0, 0),
401 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
402 store_temp_max, 0, 0),
403 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200404 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100405 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
406 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
407 store_temp_crit, 0, 1),
408 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
409 store_temp_max, 0, 1),
410 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
411 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200412 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100413 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
414 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
415 store_temp_crit, 0, 2),
416 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
417 store_temp_max, 0, 2),
418 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200419 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100420};
421
422/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100423static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100424 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100425 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
426 show_fan_full_speed,
427 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100428 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100429 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
430 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
431 store_pwm_enable, 0, 0),
432 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
433 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100434}, {
435 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
436 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
437 show_fan_full_speed,
438 store_fan_full_speed, 0, 1),
439 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100440 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
441 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
442 store_pwm_enable, 0, 1),
443 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
444 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100445}, {
446 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
447 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
448 show_fan_full_speed,
449 store_fan_full_speed, 0, 2),
450 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200451 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
452 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
453 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100454 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
455 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100456}, {
457 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
458 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
459 show_fan_full_speed,
460 store_fan_full_speed, 0, 3),
461 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
462 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
463 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
464 store_pwm_enable, 0, 3),
465 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
466 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
467} };
Hans de Goede498be962009-01-07 16:37:28 +0100468
Hans de Goede66344aa2009-12-09 20:35:59 +0100469/* Attr for models which can beep on Fan alarm */
470static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100471 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
472 store_fan_beep, 0, 0),
473 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
474 store_fan_beep, 0, 1),
475 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
476 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100477 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
478 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100479};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100480
Hans de Goede66344aa2009-12-09 20:35:59 +0100481/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
482 f71858fg / f71882fg / f71889fg */
483static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
484 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
485 show_pwm_auto_point_channel,
486 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100487 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
488 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
489 1, 0),
490 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
491 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
492 4, 0),
493 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
494 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
495 0, 0),
496 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
497 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
498 3, 0),
499 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
500 show_pwm_auto_point_temp_hyst,
501 store_pwm_auto_point_temp_hyst,
502 0, 0),
503 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
504 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
505
Hans de Goede66344aa2009-12-09 20:35:59 +0100506 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
507 show_pwm_auto_point_channel,
508 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100509 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
510 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
511 1, 1),
512 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
513 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
514 4, 1),
515 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
516 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
517 0, 1),
518 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
519 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
520 3, 1),
521 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
522 show_pwm_auto_point_temp_hyst,
523 store_pwm_auto_point_temp_hyst,
524 0, 1),
525 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
526 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100527
Hans de Goede66344aa2009-12-09 20:35:59 +0100528 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
529 show_pwm_auto_point_channel,
530 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100531 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
532 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
533 1, 2),
534 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
535 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
536 4, 2),
537 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
538 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
539 0, 2),
540 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
541 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
542 3, 2),
543 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
544 show_pwm_auto_point_temp_hyst,
545 store_pwm_auto_point_temp_hyst,
546 0, 2),
547 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
548 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100549};
550
Hans de Goede66344aa2009-12-09 20:35:59 +0100551/* PWM attr common to the f71858fg, f71882fg and f71889fg */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100552static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100553 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
554 show_pwm_auto_point_channel,
555 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100556 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
557 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
558 0, 0),
559 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
560 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
561 1, 0),
562 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
563 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
564 2, 0),
565 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
566 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
567 3, 0),
568 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
569 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
570 4, 0),
571 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
572 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
573 0, 0),
574 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
575 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
576 1, 0),
577 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
578 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
579 2, 0),
580 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
581 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
582 3, 0),
583 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
584 show_pwm_auto_point_temp_hyst,
585 store_pwm_auto_point_temp_hyst,
586 0, 0),
587 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
588 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
589 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
590 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
591 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
592 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100593}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100594 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
595 show_pwm_auto_point_channel,
596 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100597 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
598 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
599 0, 1),
600 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
601 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
602 1, 1),
603 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
604 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
605 2, 1),
606 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
607 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
608 3, 1),
609 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
610 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
611 4, 1),
612 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
613 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
614 0, 1),
615 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
616 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
617 1, 1),
618 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
619 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
620 2, 1),
621 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
622 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
623 3, 1),
624 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
625 show_pwm_auto_point_temp_hyst,
626 store_pwm_auto_point_temp_hyst,
627 0, 1),
628 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
630 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
631 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
632 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
633 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100634}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100635 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_channel,
637 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100638 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
640 0, 2),
641 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
642 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
643 1, 2),
644 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
645 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
646 2, 2),
647 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
648 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
649 3, 2),
650 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
651 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
652 4, 2),
653 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
654 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
655 0, 2),
656 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
658 1, 2),
659 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
661 2, 2),
662 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
664 3, 2),
665 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp_hyst,
667 store_pwm_auto_point_temp_hyst,
668 0, 2),
669 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
670 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
671 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
672 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
673 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
674 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100675}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100676 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_channel,
678 store_pwm_auto_point_channel, 0, 3),
679 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
681 0, 3),
682 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
684 1, 3),
685 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
686 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
687 2, 3),
688 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
689 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
690 3, 3),
691 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
692 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
693 4, 3),
694 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
695 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
696 0, 3),
697 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
698 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
699 1, 3),
700 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
701 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
702 2, 3),
703 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
705 3, 3),
706 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_temp_hyst,
708 store_pwm_auto_point_temp_hyst,
709 0, 3),
710 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
711 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
712 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
713 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
714 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
715 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100716} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200717
Hans de Goede66344aa2009-12-09 20:35:59 +0100718/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100719static struct sensor_device_attribute_2 f8000_fan_attr[] = {
720 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100721};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100722
Hans de Goede66344aa2009-12-09 20:35:59 +0100723/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
724 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
725 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
726static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
727 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
728 show_pwm_auto_point_channel,
729 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100730 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
731 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
732 0, 2),
733 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
734 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
735 1, 2),
736 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
737 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
738 2, 2),
739 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
740 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
741 3, 2),
742 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
743 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
744 4, 2),
745 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
746 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
747 0, 2),
748 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
749 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
750 1, 2),
751 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
752 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
753 2, 2),
754 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
755 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
756 3, 2),
757 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_temp_hyst,
759 store_pwm_auto_point_temp_hyst,
760 0, 2),
761 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
762 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
763 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
764 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
765 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
766 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
767
Hans de Goede66344aa2009-12-09 20:35:59 +0100768 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_channel,
770 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100771 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
773 0, 0),
774 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
776 1, 0),
777 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
778 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
779 2, 0),
780 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
781 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
782 3, 0),
783 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
784 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
785 4, 0),
786 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
787 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
788 0, 0),
789 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
790 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
791 1, 0),
792 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
793 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
794 2, 0),
795 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
796 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
797 3, 0),
798 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
799 show_pwm_auto_point_temp_hyst,
800 store_pwm_auto_point_temp_hyst,
801 0, 0),
802 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
803 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
804 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
805 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
806 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
807 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
808
Hans de Goede66344aa2009-12-09 20:35:59 +0100809 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_channel,
811 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100812 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
814 0, 1),
815 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
817 1, 1),
818 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
819 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
820 2, 1),
821 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
822 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
823 3, 1),
824 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
825 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
826 4, 1),
827 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
828 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
829 0, 1),
830 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
831 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
832 1, 1),
833 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
834 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
835 2, 1),
836 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
837 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
838 3, 1),
839 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
840 show_pwm_auto_point_temp_hyst,
841 store_pwm_auto_point_temp_hyst,
842 0, 1),
843 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
844 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
845 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
846 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
847 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
848 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
849};
Hans de Goede45fb3662007-07-13 14:34:19 +0200850
851/* Super I/O functions */
852static inline int superio_inb(int base, int reg)
853{
854 outb(reg, base);
855 return inb(base + 1);
856}
857
858static int superio_inw(int base, int reg)
859{
860 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200861 val = superio_inb(base, reg) << 8;
862 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200863 return val;
864}
865
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400866static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +0200867{
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400868 /* Don't step on other drivers' I/O space by accident */
869 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +0000870 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400871 return -EBUSY;
872 }
873
Hans de Goede45fb3662007-07-13 14:34:19 +0200874 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200875 outb(SIO_UNLOCK_KEY, base);
876 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400877
878 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +0200879}
880
Giel van Schijndel162bb592010-05-27 19:58:40 +0200881static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +0200882{
883 outb(SIO_REG_LDSEL, base);
884 outb(ld, base + 1);
885}
886
887static inline void superio_exit(int base)
888{
889 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400890 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +0200891}
892
Hans de Goede2f650632009-01-07 16:37:31 +0100893static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +0200894{
895 return reg ? (1500000 / reg) : 0;
896}
897
Hans de Goede2f650632009-01-07 16:37:31 +0100898static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100899{
900 return fan ? (1500000 / fan) : 0;
901}
902
Hans de Goede45fb3662007-07-13 14:34:19 +0200903static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
904{
905 u8 val;
906
907 outb(reg, data->addr + ADDR_REG_OFFSET);
908 val = inb(data->addr + DATA_REG_OFFSET);
909
910 return val;
911}
912
913static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
914{
915 u16 val;
916
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200917 val = f71882fg_read8(data, reg) << 8;
918 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +0200919
920 return val;
921}
922
923static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
924{
925 outb(reg, data->addr + ADDR_REG_OFFSET);
926 outb(val, data->addr + DATA_REG_OFFSET);
927}
928
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100929static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
930{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +0200931 f71882fg_write8(data, reg, val >> 8);
932 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100933}
934
Hans de Goede09475d32009-06-15 18:39:52 +0200935static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
936{
937 if (data->type == f71858fg)
938 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
939 else
940 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
941}
942
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100943static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +0200944{
945 struct f71882fg_data *data = dev_get_drvdata(dev);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100946 int nr, reg = 0, reg2;
947 int nr_fans = (data->type == f71882fg) ? 4 : 3;
Hans de Goede09475d32009-06-15 18:39:52 +0200948 int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
Hans de Goede45fb3662007-07-13 14:34:19 +0200949
950 mutex_lock(&data->update_lock);
951
952 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +0200953 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +0200954 !data->valid) {
Hans de Goede76698962009-12-09 20:36:01 +0100955 if (data->type == f71882fg || data->type == f71889fg) {
Hans de Goede498be962009-01-07 16:37:28 +0100956 data->in1_max =
957 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
958 data->in_beep =
959 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
960 }
Hans de Goede45fb3662007-07-13 14:34:19 +0200961
962 /* Get High & boundary temps*/
Hans de Goede09475d32009-06-15 18:39:52 +0200963 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +0200964 data->temp_ovt[nr] = f71882fg_read8(data,
965 F71882FG_REG_TEMP_OVT(nr));
966 data->temp_high[nr] = f71882fg_read8(data,
967 F71882FG_REG_TEMP_HIGH(nr));
968 }
969
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100970 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100971 data->temp_hyst[0] = f71882fg_read8(data,
972 F71882FG_REG_TEMP_HYST(0));
973 data->temp_hyst[1] = f71882fg_read8(data,
974 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +0200975 }
976
Hans de Goede76698962009-12-09 20:36:01 +0100977 if (data->type == f71862fg || data->type == f71882fg ||
978 data->type == f71889fg) {
Hans de Goede09475d32009-06-15 18:39:52 +0200979 data->fan_beep = f71882fg_read8(data,
980 F71882FG_REG_FAN_BEEP);
981 data->temp_beep = f71882fg_read8(data,
982 F71882FG_REG_TEMP_BEEP);
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100983 /* Have to hardcode type, because temp1 is special */
984 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
985 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
986 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
987 }
Hans de Goede76698962009-12-09 20:36:01 +0100988 /* Determine temp index 1 sensor type */
989 if (data->type == f71889fg) {
990 reg2 = f71882fg_read8(data, F71882FG_REG_START);
991 switch ((reg2 & 0x60) >> 5) {
992 case 0x00: /* BJT / Thermistor */
993 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
994 break;
995 case 0x01: /* AMDSI */
996 data->temp_type[1] = 5;
997 break;
998 case 0x02: /* PECI */
999 case 0x03: /* Ibex Peak ?? Report as PECI for now */
1000 data->temp_type[1] = 6;
1001 break;
1002 }
1003 } else {
1004 reg2 = f71882fg_read8(data, F71882FG_REG_PECI);
1005 if ((reg2 & 0x03) == 0x01)
1006 data->temp_type[1] = 6; /* PECI */
1007 else if ((reg2 & 0x03) == 0x02)
1008 data->temp_type[1] = 5; /* AMDSI */
1009 else if (data->type == f71862fg ||
1010 data->type == f71882fg)
1011 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
1012 else /* f71858fg and f8000 only support BJT */
1013 data->temp_type[1] = 2;
1014 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001015
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001016 data->pwm_enable = f71882fg_read8(data,
1017 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001018 data->pwm_auto_point_hyst[0] =
1019 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1020 data->pwm_auto_point_hyst[1] =
1021 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1022
Hans de Goede498be962009-01-07 16:37:28 +01001023 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001024 data->pwm_auto_point_mapping[nr] =
1025 f71882fg_read8(data,
1026 F71882FG_REG_POINT_MAPPING(nr));
1027
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001028 if (data->type != f71862fg) {
Hans de Goede498be962009-01-07 16:37:28 +01001029 int point;
1030 for (point = 0; point < 5; point++) {
1031 data->pwm_auto_point_pwm[nr][point] =
1032 f71882fg_read8(data,
1033 F71882FG_REG_POINT_PWM
1034 (nr, point));
1035 }
1036 for (point = 0; point < 4; point++) {
1037 data->pwm_auto_point_temp[nr][point] =
1038 f71882fg_read8(data,
1039 F71882FG_REG_POINT_TEMP
1040 (nr, point));
1041 }
1042 } else {
1043 data->pwm_auto_point_pwm[nr][1] =
1044 f71882fg_read8(data,
1045 F71882FG_REG_POINT_PWM
1046 (nr, 1));
1047 data->pwm_auto_point_pwm[nr][4] =
1048 f71882fg_read8(data,
1049 F71882FG_REG_POINT_PWM
1050 (nr, 4));
1051 data->pwm_auto_point_temp[nr][0] =
1052 f71882fg_read8(data,
1053 F71882FG_REG_POINT_TEMP
1054 (nr, 0));
1055 data->pwm_auto_point_temp[nr][3] =
1056 f71882fg_read8(data,
1057 F71882FG_REG_POINT_TEMP
1058 (nr, 3));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001059 }
1060 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001061 data->last_limits = jiffies;
1062 }
1063
1064 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001065 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001066 data->temp_status = f71882fg_read8(data,
1067 F71882FG_REG_TEMP_STATUS);
1068 data->temp_diode_open = f71882fg_read8(data,
1069 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goede09475d32009-06-15 18:39:52 +02001070 for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
1071 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001072
1073 data->fan_status = f71882fg_read8(data,
1074 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001075 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001076 data->fan[nr] = f71882fg_read16(data,
1077 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001078 data->fan_target[nr] =
1079 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1080 data->fan_full_speed[nr] =
1081 f71882fg_read16(data,
1082 F71882FG_REG_FAN_FULL_SPEED(nr));
1083 data->pwm[nr] =
1084 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1085 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001086
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001087 /* The f8000 can monitor 1 more fan, but has no pwm for it */
1088 if (data->type == f8000)
1089 data->fan[3] = f71882fg_read16(data,
1090 F71882FG_REG_FAN(3));
Hans de Goede76698962009-12-09 20:36:01 +01001091 if (data->type == f71882fg || data->type == f71889fg)
Hans de Goede498be962009-01-07 16:37:28 +01001092 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001093 F71882FG_REG_IN_STATUS);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001094 for (nr = 0; nr < nr_ins; nr++)
Hans de Goede45fb3662007-07-13 14:34:19 +02001095 data->in[nr] = f71882fg_read8(data,
1096 F71882FG_REG_IN(nr));
1097
1098 data->last_updated = jiffies;
1099 data->valid = 1;
1100 }
1101
1102 mutex_unlock(&data->update_lock);
1103
1104 return data;
1105}
1106
1107/* Sysfs Interface */
1108static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1109 char *buf)
1110{
1111 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001112 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001113 int speed = fan_from_reg(data->fan[nr]);
1114
1115 if (speed == FAN_MIN_DETECT)
1116 speed = 0;
1117
1118 return sprintf(buf, "%d\n", speed);
1119}
1120
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001121static ssize_t show_fan_full_speed(struct device *dev,
1122 struct device_attribute *devattr, char *buf)
1123{
1124 struct f71882fg_data *data = f71882fg_update_device(dev);
1125 int nr = to_sensor_dev_attr_2(devattr)->index;
1126 int speed = fan_from_reg(data->fan_full_speed[nr]);
1127 return sprintf(buf, "%d\n", speed);
1128}
1129
1130static ssize_t store_fan_full_speed(struct device *dev,
1131 struct device_attribute *devattr,
1132 const char *buf, size_t count)
1133{
1134 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001135 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1136 long val;
1137
1138 err = strict_strtol(buf, 10, &val);
1139 if (err)
1140 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001141
1142 val = SENSORS_LIMIT(val, 23, 1500000);
1143 val = fan_to_reg(val);
1144
1145 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001146 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1147 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001148 mutex_unlock(&data->update_lock);
1149
1150 return count;
1151}
1152
Hans de Goede45fb3662007-07-13 14:34:19 +02001153static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1154 *devattr, char *buf)
1155{
1156 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001157 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001158
1159 if (data->fan_beep & (1 << nr))
1160 return sprintf(buf, "1\n");
1161 else
1162 return sprintf(buf, "0\n");
1163}
1164
1165static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1166 *devattr, const char *buf, size_t count)
1167{
1168 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001169 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1170 unsigned long val;
1171
1172 err = strict_strtoul(buf, 10, &val);
1173 if (err)
1174 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001175
1176 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001177 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001178 if (val)
1179 data->fan_beep |= 1 << nr;
1180 else
1181 data->fan_beep &= ~(1 << nr);
1182
1183 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1184 mutex_unlock(&data->update_lock);
1185
1186 return count;
1187}
1188
1189static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1190 *devattr, char *buf)
1191{
1192 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001193 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001194
1195 if (data->fan_status & (1 << nr))
1196 return sprintf(buf, "1\n");
1197 else
1198 return sprintf(buf, "0\n");
1199}
1200
1201static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1202 char *buf)
1203{
1204 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001205 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001206
1207 return sprintf(buf, "%d\n", data->in[nr] * 8);
1208}
1209
1210static ssize_t show_in_max(struct device *dev, struct device_attribute
1211 *devattr, char *buf)
1212{
1213 struct f71882fg_data *data = f71882fg_update_device(dev);
1214
1215 return sprintf(buf, "%d\n", data->in1_max * 8);
1216}
1217
1218static ssize_t store_in_max(struct device *dev, struct device_attribute
1219 *devattr, const char *buf, size_t count)
1220{
1221 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001222 int err;
1223 long val;
1224
1225 err = strict_strtol(buf, 10, &val);
1226 if (err)
1227 return err;
1228
1229 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001230 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001231
1232 mutex_lock(&data->update_lock);
1233 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1234 data->in1_max = val;
1235 mutex_unlock(&data->update_lock);
1236
1237 return count;
1238}
1239
1240static ssize_t show_in_beep(struct device *dev, struct device_attribute
1241 *devattr, char *buf)
1242{
1243 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001244 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001245
1246 if (data->in_beep & (1 << nr))
1247 return sprintf(buf, "1\n");
1248 else
1249 return sprintf(buf, "0\n");
1250}
1251
1252static ssize_t store_in_beep(struct device *dev, struct device_attribute
1253 *devattr, const char *buf, size_t count)
1254{
1255 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001256 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1257 unsigned long val;
1258
1259 err = strict_strtoul(buf, 10, &val);
1260 if (err)
1261 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001262
1263 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001264 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001265 if (val)
1266 data->in_beep |= 1 << nr;
1267 else
1268 data->in_beep &= ~(1 << nr);
1269
1270 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1271 mutex_unlock(&data->update_lock);
1272
1273 return count;
1274}
1275
1276static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1277 *devattr, char *buf)
1278{
1279 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001280 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001281
1282 if (data->in_status & (1 << nr))
1283 return sprintf(buf, "1\n");
1284 else
1285 return sprintf(buf, "0\n");
1286}
1287
1288static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1289 char *buf)
1290{
1291 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001292 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001293 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001294
Hans de Goede09475d32009-06-15 18:39:52 +02001295 if (data->type == f71858fg) {
1296 /* TEMP_TABLE_SEL 1 or 3 ? */
1297 if (data->temp_config & 1) {
1298 sign = data->temp[nr] & 0x0001;
1299 temp = (data->temp[nr] >> 5) & 0x7ff;
1300 } else {
1301 sign = data->temp[nr] & 0x8000;
1302 temp = (data->temp[nr] >> 5) & 0x3ff;
1303 }
1304 temp *= 125;
1305 if (sign)
1306 temp -= 128000;
1307 } else
1308 temp = data->temp[nr] * 1000;
1309
1310 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001311}
1312
1313static ssize_t show_temp_max(struct device *dev, struct device_attribute
1314 *devattr, char *buf)
1315{
1316 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001317 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001318
1319 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1320}
1321
1322static ssize_t store_temp_max(struct device *dev, struct device_attribute
1323 *devattr, const char *buf, size_t count)
1324{
1325 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001326 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1327 long val;
1328
1329 err = strict_strtol(buf, 10, &val);
1330 if (err)
1331 return err;
1332
1333 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001334 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001335
1336 mutex_lock(&data->update_lock);
1337 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1338 data->temp_high[nr] = val;
1339 mutex_unlock(&data->update_lock);
1340
1341 return count;
1342}
1343
1344static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1345 *devattr, char *buf)
1346{
1347 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001348 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001349 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001350
Hans de Goedece0bfa52009-01-07 16:37:28 +01001351 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001352 if (nr & 1)
1353 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1354 else
1355 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1356 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001357 mutex_unlock(&data->update_lock);
1358
1359 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001360}
1361
1362static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1363 *devattr, const char *buf, size_t count)
1364{
1365 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001366 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001367 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001368 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001369 long val;
1370
1371 err = strict_strtol(buf, 10, &val);
1372 if (err)
1373 return err;
1374
1375 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001376
1377 mutex_lock(&data->update_lock);
1378
1379 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001380 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1381 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1382 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001383 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001384
1385 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001386 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1387 if (nr & 1)
1388 reg = (reg & 0x0f) | (val << 4);
1389 else
1390 reg = (reg & 0xf0) | val;
1391 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1392 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001393
Hans de Goede45fb3662007-07-13 14:34:19 +02001394 mutex_unlock(&data->update_lock);
1395 return ret;
1396}
1397
1398static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1399 *devattr, char *buf)
1400{
1401 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001402 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001403
1404 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1405}
1406
1407static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1408 *devattr, const char *buf, size_t count)
1409{
1410 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001411 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1412 long val;
1413
1414 err = strict_strtol(buf, 10, &val);
1415 if (err)
1416 return err;
1417
1418 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001419 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001420
1421 mutex_lock(&data->update_lock);
1422 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1423 data->temp_ovt[nr] = val;
1424 mutex_unlock(&data->update_lock);
1425
1426 return count;
1427}
1428
1429static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1430 *devattr, char *buf)
1431{
1432 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001433 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001434 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001435
Hans de Goedece0bfa52009-01-07 16:37:28 +01001436 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001437 if (nr & 1)
1438 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1439 else
1440 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1441 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001442 mutex_unlock(&data->update_lock);
1443
1444 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001445}
1446
1447static ssize_t show_temp_type(struct device *dev, struct device_attribute
1448 *devattr, char *buf)
1449{
1450 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001451 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001452
1453 return sprintf(buf, "%d\n", data->temp_type[nr]);
1454}
1455
1456static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1457 *devattr, char *buf)
1458{
1459 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001460 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001461
Hans de Goede7567a042009-01-07 16:37:28 +01001462 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001463 return sprintf(buf, "1\n");
1464 else
1465 return sprintf(buf, "0\n");
1466}
1467
1468static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1469 *devattr, const char *buf, size_t count)
1470{
1471 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001472 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1473 unsigned long val;
1474
1475 err = strict_strtoul(buf, 10, &val);
1476 if (err)
1477 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001478
1479 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001480 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001481 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001482 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001483 else
Hans de Goede7567a042009-01-07 16:37:28 +01001484 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001485
1486 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1487 mutex_unlock(&data->update_lock);
1488
1489 return count;
1490}
1491
1492static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1493 *devattr, char *buf)
1494{
1495 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001496 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001497
Hans de Goede7567a042009-01-07 16:37:28 +01001498 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001499 return sprintf(buf, "1\n");
1500 else
1501 return sprintf(buf, "0\n");
1502}
1503
1504static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1505 *devattr, char *buf)
1506{
1507 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001508 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001509
Hans de Goede7567a042009-01-07 16:37:28 +01001510 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001511 return sprintf(buf, "1\n");
1512 else
1513 return sprintf(buf, "0\n");
1514}
1515
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001516static ssize_t show_pwm(struct device *dev,
1517 struct device_attribute *devattr, char *buf)
1518{
1519 struct f71882fg_data *data = f71882fg_update_device(dev);
1520 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001521 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001522 if (data->pwm_enable & (1 << (2 * nr)))
1523 /* PWM mode */
1524 val = data->pwm[nr];
1525 else {
1526 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001527 val = 255 * fan_from_reg(data->fan_target[nr])
1528 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001529 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001530 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001531 return sprintf(buf, "%d\n", val);
1532}
1533
1534static ssize_t store_pwm(struct device *dev,
1535 struct device_attribute *devattr, const char *buf,
1536 size_t count)
1537{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001538 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001539 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1540 long val;
1541
1542 err = strict_strtol(buf, 10, &val);
1543 if (err)
1544 return err;
1545
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001546 val = SENSORS_LIMIT(val, 0, 255);
1547
1548 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001549 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001550 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1551 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1552 count = -EROFS;
1553 goto leave;
1554 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001555 if (data->pwm_enable & (1 << (2 * nr))) {
1556 /* PWM mode */
1557 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1558 data->pwm[nr] = val;
1559 } else {
1560 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001561 int target, full_speed;
1562 full_speed = f71882fg_read16(data,
1563 F71882FG_REG_FAN_FULL_SPEED(nr));
1564 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1565 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1566 data->fan_target[nr] = target;
1567 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001568 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001569leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001570 mutex_unlock(&data->update_lock);
1571
1572 return count;
1573}
1574
1575static ssize_t show_pwm_enable(struct device *dev,
1576 struct device_attribute *devattr, char *buf)
1577{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001578 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001579 struct f71882fg_data *data = f71882fg_update_device(dev);
1580 int nr = to_sensor_dev_attr_2(devattr)->index;
1581
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001582 switch ((data->pwm_enable >> 2 * nr) & 3) {
1583 case 0:
1584 case 1:
1585 result = 2; /* Normal auto mode */
1586 break;
1587 case 2:
1588 result = 1; /* Manual mode */
1589 break;
1590 case 3:
1591 if (data->type == f8000)
1592 result = 3; /* Thermostat mode */
1593 else
1594 result = 1; /* Manual mode */
1595 break;
1596 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001597
1598 return sprintf(buf, "%d\n", result);
1599}
1600
1601static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1602 *devattr, const char *buf, size_t count)
1603{
1604 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001605 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1606 long val;
1607
1608 err = strict_strtol(buf, 10, &val);
1609 if (err)
1610 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001611
Hans de Goede3fc78382009-06-15 18:39:50 +02001612 /* Special case for F8000 pwm channel 3 which only does auto mode */
1613 if (data->type == f8000 && nr == 2 && val != 2)
1614 return -EINVAL;
1615
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001616 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001617 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001618 /* Special case for F8000 auto PWM mode / Thermostat mode */
1619 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1620 switch (val) {
1621 case 2:
1622 data->pwm_enable &= ~(2 << (2 * nr));
1623 break; /* Normal auto mode */
1624 case 3:
1625 data->pwm_enable |= 2 << (2 * nr);
1626 break; /* Thermostat mode */
1627 default:
1628 count = -EINVAL;
1629 goto leave;
1630 }
1631 } else {
1632 switch (val) {
1633 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001634 /* The f71858fg does not support manual RPM mode */
1635 if (data->type == f71858fg &&
1636 ((data->pwm_enable >> (2 * nr)) & 1)) {
1637 count = -EINVAL;
1638 goto leave;
1639 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001640 data->pwm_enable |= 2 << (2 * nr);
1641 break; /* Manual */
1642 case 2:
1643 data->pwm_enable &= ~(2 << (2 * nr));
1644 break; /* Normal auto mode */
1645 default:
1646 count = -EINVAL;
1647 goto leave;
1648 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001649 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001650 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001651leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001652 mutex_unlock(&data->update_lock);
1653
1654 return count;
1655}
1656
1657static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1658 struct device_attribute *devattr,
1659 char *buf)
1660{
1661 int result;
1662 struct f71882fg_data *data = f71882fg_update_device(dev);
1663 int pwm = to_sensor_dev_attr_2(devattr)->index;
1664 int point = to_sensor_dev_attr_2(devattr)->nr;
1665
Hans de Goedece0bfa52009-01-07 16:37:28 +01001666 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001667 if (data->pwm_enable & (1 << (2 * pwm))) {
1668 /* PWM mode */
1669 result = data->pwm_auto_point_pwm[pwm][point];
1670 } else {
1671 /* RPM mode */
1672 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1673 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001674 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001675
1676 return sprintf(buf, "%d\n", result);
1677}
1678
1679static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1680 struct device_attribute *devattr,
1681 const char *buf, size_t count)
1682{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001683 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001684 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001685 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001686 long val;
1687
1688 err = strict_strtol(buf, 10, &val);
1689 if (err)
1690 return err;
1691
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001692 val = SENSORS_LIMIT(val, 0, 255);
1693
1694 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001695 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001696 if (data->pwm_enable & (1 << (2 * pwm))) {
1697 /* PWM mode */
1698 } else {
1699 /* RPM mode */
1700 if (val < 29) /* Prevent negative numbers */
1701 val = 255;
1702 else
1703 val = (255 - val) * 32 / val;
1704 }
1705 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1706 data->pwm_auto_point_pwm[pwm][point] = val;
1707 mutex_unlock(&data->update_lock);
1708
1709 return count;
1710}
1711
1712static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1713 struct device_attribute *devattr,
1714 char *buf)
1715{
1716 int result = 0;
1717 struct f71882fg_data *data = f71882fg_update_device(dev);
1718 int nr = to_sensor_dev_attr_2(devattr)->index;
1719 int point = to_sensor_dev_attr_2(devattr)->nr;
1720
1721 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001722 if (nr & 1)
1723 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1724 else
1725 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001726 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1727 mutex_unlock(&data->update_lock);
1728
1729 return sprintf(buf, "%d\n", result);
1730}
1731
1732static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1733 struct device_attribute *devattr,
1734 const char *buf, size_t count)
1735{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001736 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001737 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001738 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001739 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001740 long val;
1741
1742 err = strict_strtol(buf, 10, &val);
1743 if (err)
1744 return err;
1745
1746 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001747
1748 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001749 data->pwm_auto_point_temp[nr][point] =
1750 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001751 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1752 data->pwm_auto_point_temp[nr][point]);
1753 val = data->pwm_auto_point_temp[nr][point] - val;
1754
Hans de Goedebc274902009-01-07 16:37:29 +01001755 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1756 if (nr & 1)
1757 reg = (reg & 0x0f) | (val << 4);
1758 else
1759 reg = (reg & 0xf0) | val;
1760
1761 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1762 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001763 mutex_unlock(&data->update_lock);
1764
1765 return count;
1766}
1767
1768static ssize_t show_pwm_interpolate(struct device *dev,
1769 struct device_attribute *devattr, char *buf)
1770{
1771 int result;
1772 struct f71882fg_data *data = f71882fg_update_device(dev);
1773 int nr = to_sensor_dev_attr_2(devattr)->index;
1774
1775 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1776
1777 return sprintf(buf, "%d\n", result);
1778}
1779
1780static ssize_t store_pwm_interpolate(struct device *dev,
1781 struct device_attribute *devattr,
1782 const char *buf, size_t count)
1783{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001784 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001785 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1786 unsigned long val;
1787
1788 err = strict_strtoul(buf, 10, &val);
1789 if (err)
1790 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001791
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001792 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001793 data->pwm_auto_point_mapping[nr] =
1794 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001795 if (val)
1796 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
1797 else
1798 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
1799 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1800 data->pwm_auto_point_mapping[nr] = val;
1801 mutex_unlock(&data->update_lock);
1802
1803 return count;
1804}
1805
1806static ssize_t show_pwm_auto_point_channel(struct device *dev,
1807 struct device_attribute *devattr,
1808 char *buf)
1809{
1810 int result;
1811 struct f71882fg_data *data = f71882fg_update_device(dev);
1812 int nr = to_sensor_dev_attr_2(devattr)->index;
1813
Hans de Goede09475d32009-06-15 18:39:52 +02001814 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
1815 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001816
1817 return sprintf(buf, "%d\n", result);
1818}
1819
1820static ssize_t store_pwm_auto_point_channel(struct device *dev,
1821 struct device_attribute *devattr,
1822 const char *buf, size_t count)
1823{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001824 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001825 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1826 long val;
1827
1828 err = strict_strtol(buf, 10, &val);
1829 if (err)
1830 return err;
Hans de Goede30453012009-01-07 16:37:30 +01001831
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001832 switch (val) {
1833 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01001834 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001835 break;
1836 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01001837 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001838 break;
1839 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01001840 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841 break;
1842 default:
1843 return -EINVAL;
1844 }
Hans de Goede09475d32009-06-15 18:39:52 +02001845 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001846 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001847 data->pwm_auto_point_mapping[nr] =
1848 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001849 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
1850 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
1851 data->pwm_auto_point_mapping[nr] = val;
1852 mutex_unlock(&data->update_lock);
1853
1854 return count;
1855}
1856
1857static ssize_t show_pwm_auto_point_temp(struct device *dev,
1858 struct device_attribute *devattr,
1859 char *buf)
1860{
1861 int result;
1862 struct f71882fg_data *data = f71882fg_update_device(dev);
1863 int pwm = to_sensor_dev_attr_2(devattr)->index;
1864 int point = to_sensor_dev_attr_2(devattr)->nr;
1865
1866 result = data->pwm_auto_point_temp[pwm][point];
1867 return sprintf(buf, "%d\n", 1000 * result);
1868}
1869
1870static ssize_t store_pwm_auto_point_temp(struct device *dev,
1871 struct device_attribute *devattr,
1872 const char *buf, size_t count)
1873{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001874 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001875 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001876 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001877 long val;
1878
1879 err = strict_strtol(buf, 10, &val);
1880 if (err)
1881 return err;
1882
1883 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01001884
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001885 if (data->type == f71889fg)
Hans de Goede76698962009-12-09 20:36:01 +01001886 val = SENSORS_LIMIT(val, -128, 127);
1887 else
1888 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001889
1890 mutex_lock(&data->update_lock);
1891 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
1892 data->pwm_auto_point_temp[pwm][point] = val;
1893 mutex_unlock(&data->update_lock);
1894
1895 return count;
1896}
1897
Hans de Goede45fb3662007-07-13 14:34:19 +02001898static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
1899 char *buf)
1900{
Hans de Goede498be962009-01-07 16:37:28 +01001901 struct f71882fg_data *data = dev_get_drvdata(dev);
1902 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001903}
1904
Hans de Goedec13548c2009-01-07 16:37:27 +01001905static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
1906 struct sensor_device_attribute_2 *attr, int count)
1907{
1908 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02001909
Hans de Goedec13548c2009-01-07 16:37:27 +01001910 for (i = 0; i < count; i++) {
1911 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
1912 if (err)
1913 return err;
1914 }
1915 return 0;
1916}
1917
Hans de Goedefc16c562009-12-09 20:36:01 +01001918static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
1919 struct sensor_device_attribute_2 *attr, int count)
1920{
1921 int i;
1922
1923 for (i = 0; i < count; i++)
1924 device_remove_file(&pdev->dev, &attr[i].dev_attr);
1925}
1926
Hans de Goedec13548c2009-01-07 16:37:27 +01001927static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001928{
1929 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01001930 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Hans de Goede28ba8582009-01-07 16:37:31 +01001931 int err, i, nr_fans = (sio_data->type == f71882fg) ? 4 : 3;
Hans de Goede45fb3662007-07-13 14:34:19 +02001932 u8 start_reg;
1933
Hans de Goedec13548c2009-01-07 16:37:27 +01001934 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
1935 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02001936 return -ENOMEM;
1937
1938 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01001939 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02001940 data->temp_start =
1941 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02001942 mutex_init(&data->update_lock);
1943 platform_set_drvdata(pdev, data);
1944
Hans de Goede3cc74752009-01-07 16:37:28 +01001945 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01001946 if (start_reg & 0x04) {
1947 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
1948 err = -ENODEV;
1949 goto exit_free;
1950 }
Hans de Goede3cc74752009-01-07 16:37:28 +01001951 if (!(start_reg & 0x03)) {
1952 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
1953 err = -ENODEV;
1954 goto exit_free;
1955 }
1956
Hans de Goede45fb3662007-07-13 14:34:19 +02001957 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01001958 err = device_create_file(&pdev->dev, &dev_attr_name);
1959 if (err)
1960 goto exit_unregister_sysfs;
1961
Hans de Goedec13548c2009-01-07 16:37:27 +01001962 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001963 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02001964 case f71858fg:
1965 data->temp_config =
1966 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
1967 if (data->temp_config & 0x10)
1968 /* The f71858fg temperature alarms behave as
1969 the f8000 alarms in this mode */
1970 err = f71882fg_create_sysfs_files(pdev,
1971 f8000_in_temp_attr,
1972 ARRAY_SIZE(f8000_in_temp_attr));
1973 else
1974 err = f71882fg_create_sysfs_files(pdev,
1975 f71858fg_in_temp_attr,
1976 ARRAY_SIZE(f71858fg_in_temp_attr));
1977 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001978 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01001979 case f71889fg:
Hans de Goede498be962009-01-07 16:37:28 +01001980 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01001981 fxxxx_in1_alarm_attr,
1982 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01001983 if (err)
1984 goto exit_unregister_sysfs;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001985 /* fall through! */
1986 case f71862fg:
1987 err = f71882fg_create_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07001988 fxxxx_in_temp_attr,
1989 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001990 break;
1991 case f8000:
1992 err = f71882fg_create_sysfs_files(pdev,
1993 f8000_in_temp_attr,
1994 ARRAY_SIZE(f8000_in_temp_attr));
1995 break;
Hans de Goede498be962009-01-07 16:37:28 +01001996 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001997 if (err)
1998 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02001999 }
2000
Hans de Goede45fb3662007-07-13 14:34:19 +02002001 if (start_reg & 0x02) {
Hans de Goede996cadb2009-06-15 18:39:51 +02002002 data->pwm_enable =
2003 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2004
2005 /* Sanity check the pwm settings */
2006 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002007 case f71858fg:
2008 err = 0;
2009 for (i = 0; i < nr_fans; i++)
2010 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2011 err = 1;
2012 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002013 case f71862fg:
2014 err = (data->pwm_enable & 0x15) != 0x15;
2015 break;
2016 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002017 case f71889fg:
Hans de Goede996cadb2009-06-15 18:39:51 +02002018 err = 0;
2019 break;
2020 case f8000:
2021 err = data->pwm_enable & 0x20;
2022 break;
2023 }
2024 if (err) {
2025 dev_err(&pdev->dev,
2026 "Invalid (reserved) pwm settings: 0x%02x\n",
2027 (unsigned int)data->pwm_enable);
2028 err = -ENODEV;
2029 goto exit_unregister_sysfs;
2030 }
2031
Hans de Goedeb69b0392009-12-09 20:36:00 +01002032 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2033 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002034 if (err)
2035 goto exit_unregister_sysfs;
2036
Hans de Goede76698962009-12-09 20:36:01 +01002037 if (data->type == f71862fg || data->type == f71882fg ||
2038 data->type == f71889fg) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002039 err = f71882fg_create_sysfs_files(pdev,
2040 fxxxx_fan_beep_attr, nr_fans);
2041 if (err)
2042 goto exit_unregister_sysfs;
2043 }
2044
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002045 switch (data->type) {
2046 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002047 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002048 f71862fg_auto_pwm_attr,
2049 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002050 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002051 case f8000:
2052 err = f71882fg_create_sysfs_files(pdev,
2053 f8000_fan_attr,
2054 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002055 if (err)
2056 goto exit_unregister_sysfs;
2057 err = f71882fg_create_sysfs_files(pdev,
2058 f8000_auto_pwm_attr,
2059 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002060 break;
Hans de Goede76698962009-12-09 20:36:01 +01002061 case f71889fg:
2062 for (i = 0; i < nr_fans; i++) {
2063 data->pwm_auto_point_mapping[i] =
2064 f71882fg_read8(data,
2065 F71882FG_REG_POINT_MAPPING(i));
2066 if (data->pwm_auto_point_mapping[i] & 0x80)
2067 break;
2068 }
2069 if (i != nr_fans) {
2070 dev_warn(&pdev->dev,
2071 "Auto pwm controlled by raw digital "
2072 "data, disabling pwm auto_point "
2073 "sysfs attributes\n");
2074 break;
2075 }
2076 /* fall through */
Hans de Goedeb69b0392009-12-09 20:36:00 +01002077 default: /* f71858fg / f71882fg */
2078 err = f71882fg_create_sysfs_files(pdev,
2079 &fxxxx_auto_pwm_attr[0][0],
2080 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002081 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002082 if (err)
2083 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002084
2085 for (i = 0; i < nr_fans; i++)
2086 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2087 (data->pwm_enable & (1 << 2 * i)) ?
2088 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002089 }
2090
Tony Jones1beeffe2007-08-20 13:46:20 -07002091 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2092 if (IS_ERR(data->hwmon_dev)) {
2093 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002094 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002095 goto exit_unregister_sysfs;
2096 }
2097
2098 return 0;
2099
2100exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002101 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002102 return err; /* f71882fg_remove() also frees our data */
2103exit_free:
2104 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002105 return err;
2106}
2107
Hans de Goedec13548c2009-01-07 16:37:27 +01002108static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002109{
Hans de Goede45fb3662007-07-13 14:34:19 +02002110 struct f71882fg_data *data = platform_get_drvdata(pdev);
Hans de Goedefc16c562009-12-09 20:36:01 +01002111 int nr_fans = (data->type == f71882fg) ? 4 : 3;
2112 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002113
2114 platform_set_drvdata(pdev, NULL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002115 if (data->hwmon_dev)
2116 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002117
Hans de Goedec13548c2009-01-07 16:37:27 +01002118 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002119
Hans de Goedefc16c562009-12-09 20:36:01 +01002120 if (start_reg & 0x01) {
2121 switch (data->type) {
2122 case f71858fg:
2123 if (data->temp_config & 0x10)
2124 f71882fg_remove_sysfs_files(pdev,
2125 f8000_in_temp_attr,
2126 ARRAY_SIZE(f8000_in_temp_attr));
2127 else
2128 f71882fg_remove_sysfs_files(pdev,
2129 f71858fg_in_temp_attr,
2130 ARRAY_SIZE(f71858fg_in_temp_attr));
2131 break;
2132 case f71882fg:
Hans de Goede76698962009-12-09 20:36:01 +01002133 case f71889fg:
Hans de Goedefc16c562009-12-09 20:36:01 +01002134 f71882fg_remove_sysfs_files(pdev,
2135 fxxxx_in1_alarm_attr,
2136 ARRAY_SIZE(fxxxx_in1_alarm_attr));
2137 /* fall through! */
2138 case f71862fg:
2139 f71882fg_remove_sysfs_files(pdev,
Andrew Mortonf2e41e92010-08-19 14:13:31 -07002140 fxxxx_in_temp_attr,
2141 ARRAY_SIZE(fxxxx_in_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002142 break;
2143 case f8000:
2144 f71882fg_remove_sysfs_files(pdev,
2145 f8000_in_temp_attr,
2146 ARRAY_SIZE(f8000_in_temp_attr));
2147 break;
2148 }
2149 }
Hans de Goede498be962009-01-07 16:37:28 +01002150
Hans de Goedefc16c562009-12-09 20:36:01 +01002151 if (start_reg & 0x02) {
2152 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2153 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002154
Hans de Goede76698962009-12-09 20:36:01 +01002155 if (data->type == f71862fg || data->type == f71882fg ||
2156 data->type == f71889fg)
Hans de Goedefc16c562009-12-09 20:36:01 +01002157 f71882fg_remove_sysfs_files(pdev,
2158 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002159
Hans de Goedefc16c562009-12-09 20:36:01 +01002160 switch (data->type) {
2161 case f71862fg:
2162 f71882fg_remove_sysfs_files(pdev,
2163 f71862fg_auto_pwm_attr,
2164 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2165 break;
2166 case f8000:
2167 f71882fg_remove_sysfs_files(pdev,
2168 f8000_fan_attr,
2169 ARRAY_SIZE(f8000_fan_attr));
2170 f71882fg_remove_sysfs_files(pdev,
2171 f8000_auto_pwm_attr,
2172 ARRAY_SIZE(f8000_auto_pwm_attr));
2173 break;
2174 default: /* f71858fg / f71882fg / f71889fg */
2175 f71882fg_remove_sysfs_files(pdev,
2176 &fxxxx_auto_pwm_attr[0][0],
2177 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2178 }
2179 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002180
Hans de Goede45fb3662007-07-13 14:34:19 +02002181 kfree(data);
2182
2183 return 0;
2184}
2185
Hans de Goede498be962009-01-07 16:37:28 +01002186static int __init f71882fg_find(int sioaddr, unsigned short *address,
2187 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002188{
Hans de Goede45fb3662007-07-13 14:34:19 +02002189 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002190 int err = superio_enter(sioaddr);
2191 if (err)
2192 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002193
2194 devid = superio_inw(sioaddr, SIO_REG_MANID);
2195 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002196 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002197 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002198 goto exit;
2199 }
2200
Jean Delvare67b671b2007-12-06 23:13:42 +01002201 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002202 switch (devid) {
Hans de Goede09475d32009-06-15 18:39:52 +02002203 case SIO_F71858_ID:
2204 sio_data->type = f71858fg;
2205 break;
Hans de Goede498be962009-01-07 16:37:28 +01002206 case SIO_F71862_ID:
2207 sio_data->type = f71862fg;
2208 break;
2209 case SIO_F71882_ID:
2210 sio_data->type = f71882fg;
2211 break;
Hans de Goede76698962009-12-09 20:36:01 +01002212 case SIO_F71889_ID:
2213 sio_data->type = f71889fg;
2214 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002215 case SIO_F8000_ID:
2216 sio_data->type = f8000;
2217 break;
Hans de Goede498be962009-01-07 16:37:28 +01002218 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002219 pr_info("Unsupported Fintek device: %04x\n",
2220 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002221 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002222 goto exit;
2223 }
2224
Hans de Goede09475d32009-06-15 18:39:52 +02002225 if (sio_data->type == f71858fg)
2226 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2227 else
2228 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2229
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002230 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002231 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002232 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002233 goto exit;
2234 }
2235
2236 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002237 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002238 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002239 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002240 goto exit;
2241 }
2242 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2243
Hans de Goede45fb3662007-07-13 14:34:19 +02002244 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002245 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002246 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002247 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2248exit:
2249 superio_exit(sioaddr);
2250 return err;
2251}
2252
Hans de Goede498be962009-01-07 16:37:28 +01002253static int __init f71882fg_device_add(unsigned short address,
2254 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002255{
2256 struct resource res = {
2257 .start = address,
2258 .end = address + REGION_LENGTH - 1,
2259 .flags = IORESOURCE_IO,
2260 };
2261 int err;
2262
2263 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002264 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002265 return -ENOMEM;
2266
2267 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002268 err = acpi_check_resource_conflict(&res);
2269 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002270 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002271
Hans de Goede45fb3662007-07-13 14:34:19 +02002272 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002273 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002274 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002275 goto exit_device_put;
2276 }
2277
Hans de Goede498be962009-01-07 16:37:28 +01002278 err = platform_device_add_data(f71882fg_pdev, sio_data,
2279 sizeof(struct f71882fg_sio_data));
2280 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002281 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002282 goto exit_device_put;
2283 }
2284
Hans de Goede45fb3662007-07-13 14:34:19 +02002285 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002286 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002287 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002288 goto exit_device_put;
2289 }
2290
2291 return 0;
2292
2293exit_device_put:
2294 platform_device_put(f71882fg_pdev);
2295
2296 return err;
2297}
2298
2299static int __init f71882fg_init(void)
2300{
2301 int err = -ENODEV;
2302 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002303 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002304
Hans de Goede498be962009-01-07 16:37:28 +01002305 memset(&sio_data, 0, sizeof(sio_data));
2306
2307 if (f71882fg_find(0x2e, &address, &sio_data) &&
2308 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002309 goto exit;
2310
Hans de Goedec13548c2009-01-07 16:37:27 +01002311 err = platform_driver_register(&f71882fg_driver);
2312 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002313 goto exit;
2314
Hans de Goede498be962009-01-07 16:37:28 +01002315 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002316 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002317 goto exit_driver;
2318
2319 return 0;
2320
2321exit_driver:
2322 platform_driver_unregister(&f71882fg_driver);
2323exit:
2324 return err;
2325}
2326
2327static void __exit f71882fg_exit(void)
2328{
2329 platform_device_unregister(f71882fg_pdev);
2330 platform_driver_unregister(&f71882fg_driver);
2331}
2332
2333MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goedec13548c2009-01-07 16:37:27 +01002334MODULE_AUTHOR("Hans Edgington, Hans de Goede (hdegoede@redhat.com)");
Hans de Goede45fb3662007-07-13 14:34:19 +02002335MODULE_LICENSE("GPL");
2336
2337module_init(f71882fg_init);
2338module_exit(f71882fg_exit);