blob: f8ef196733914903152fd82c9bf3ef12b2793d45 [file] [log] [blame]
Hans de Goede45fb3662007-07-13 14:34:19 +02001/***************************************************************************
2 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
Hans de Goede44c4dc52011-03-09 20:57:07 +01003 * Copyright (C) 2007-2011 Hans de Goede <hdegoede@redhat.com> *
Hans de Goede45fb3662007-07-13 14:34:19 +02004 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
Joe Perches22d3b412010-10-20 06:51:34 +000021#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
Hans de Goede45fb3662007-07-13 14:34:19 +020023#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/jiffies.h>
27#include <linux/platform_device.h>
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
30#include <linux/err.h>
31#include <linux/mutex.h>
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010032#include <linux/io.h>
Jean Delvareb9acb642009-01-07 16:37:35 +010033#include <linux/acpi.h>
Hans de Goede45fb3662007-07-13 14:34:19 +020034
35#define DRVNAME "f71882fg"
36
Hans de Goede09475d32009-06-15 18:39:52 +020037#define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +010038#define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */
Hans de Goede45fb3662007-07-13 14:34:19 +020039#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
Hans de Goede14a40192011-03-13 13:50:32 +010040#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
Hans de Goede45fb3662007-07-13 14:34:19 +020041
42#define SIO_REG_LDSEL 0x07 /* Logical device select */
43#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
44#define SIO_REG_DEVREV 0x22 /* Device revision */
45#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
46#define SIO_REG_ENABLE 0x30 /* Logical device enable */
47#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
48
49#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
Hans de Goedee5e713c2011-03-10 08:54:02 +010050#define SIO_F71808E_ID 0x0901 /* Chipset ID */
Hans de Goede629c58b2011-05-25 20:43:32 +020051#define SIO_F71808A_ID 0x1001 /* Chipset ID */
Hans de Goede09475d32009-06-15 18:39:52 +020052#define SIO_F71858_ID 0x0507 /* Chipset ID */
Hans de Goede498be962009-01-07 16:37:28 +010053#define SIO_F71862_ID 0x0601 /* Chipset ID */
Hans de Goedec11bb992011-03-09 20:57:15 +010054#define SIO_F71869_ID 0x0814 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020055#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010056#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010057#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedea66c1082011-03-26 10:45:02 +010058#define SIO_F71889A_ID 0x1005 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010059#define SIO_F8000_ID 0x0581 /* Chipset ID */
Jean Delvare383586b2011-03-26 10:45:02 +010060#define SIO_F81865_ID 0x0704 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020061
62#define REGION_LENGTH 8
63#define ADDR_REG_OFFSET 5
64#define DATA_REG_OFFSET 6
65
Hans de Goede3cad4022011-03-09 20:57:14 +010066#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
67#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020068#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010069#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020070
71#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010072#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
73#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020074#define F71882FG_REG_FAN_STATUS 0x92
75#define F71882FG_REG_FAN_BEEP 0x93
76
Hans de Goede7567a042009-01-07 16:37:28 +010077#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
78#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
79#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020080#define F71882FG_REG_TEMP_STATUS 0x62
81#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020082#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010083#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020084#define F71882FG_REG_TEMP_TYPE 0x6B
85#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
86
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010087#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
88#define F71882FG_REG_PWM_TYPE 0x94
89#define F71882FG_REG_PWM_ENABLE 0x96
90
Hans de Goedebc274902009-01-07 16:37:29 +010091#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010092
Hans de Goede98f7ba12011-03-09 20:57:09 +010093#define F71882FG_REG_FAN_FAULT_T 0x9F
94#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010095#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010096
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010097#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
98#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
99#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
100
Hans de Goede45fb3662007-07-13 14:34:19 +0200101#define F71882FG_REG_START 0x01
102
Hans de Goede0bae6402011-03-09 20:57:10 +0100103#define F71882FG_MAX_INS 9
104
Hans de Goede45fb3662007-07-13 14:34:19 +0200105#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
106
Jean Delvare67b671b2007-12-06 23:13:42 +0100107static unsigned short force_id;
108module_param(force_id, ushort, 0);
109MODULE_PARM_DESC(force_id, "Override the detected device ID");
110
Hans de Goede629c58b2011-05-25 20:43:32 +0200111enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
Hans de Goedea66c1082011-03-26 10:45:02 +0100112 f71889ed, f71889a, f8000, f81865f };
Hans de Goede498be962009-01-07 16:37:28 +0100113
114static const char *f71882fg_names[] = {
Hans de Goedee5e713c2011-03-10 08:54:02 +0100115 "f71808e",
Hans de Goede629c58b2011-05-25 20:43:32 +0200116 "f71808a",
Hans de Goede09475d32009-06-15 18:39:52 +0200117 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100118 "f71862fg",
Hans de Goedec11bb992011-03-09 20:57:15 +0100119 "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
Hans de Goede498be962009-01-07 16:37:28 +0100120 "f71882fg",
Jean Delvare5d7f77b2011-03-26 10:45:02 +0100121 "f71889fg", /* f81801u too, same id */
Hans de Goede3cad4022011-03-09 20:57:14 +0100122 "f71889ed",
Hans de Goedea66c1082011-03-26 10:45:02 +0100123 "f71889a",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100124 "f8000",
Jean Delvare383586b2011-03-26 10:45:02 +0100125 "f81865f",
Hans de Goede498be962009-01-07 16:37:28 +0100126};
127
Jean Delvare2740c602011-03-26 10:45:01 +0100128static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
129 [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
Hans de Goede629c58b2011-05-25 20:43:32 +0200130 [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
Jean Delvare2740c602011-03-26 10:45:01 +0100131 [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
132 [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
133 [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
134 [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
135 [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
136 [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Hans de Goedea66c1082011-03-26 10:45:02 +0100137 [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Jean Delvare2740c602011-03-26 10:45:01 +0100138 [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
Jean Delvare383586b2011-03-26 10:45:02 +0100139 [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 },
Hans de Goede0bae6402011-03-09 20:57:10 +0100140};
141
Jean Delvare2740c602011-03-26 10:45:01 +0100142static const char f71882fg_has_in1_alarm[] = {
143 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200144 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100145 [f71858fg] = 0,
146 [f71862fg] = 0,
147 [f71869] = 0,
148 [f71882fg] = 1,
149 [f71889fg] = 1,
150 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100151 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100152 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100153 [f81865f] = 1,
Hans de Goede0bae6402011-03-09 20:57:10 +0100154};
155
Hans de Goede4d538112011-05-25 20:43:32 +0200156static const char f71882fg_fan_has_beep[] = {
Jean Delvare2740c602011-03-26 10:45:01 +0100157 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200158 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100159 [f71858fg] = 0,
160 [f71862fg] = 1,
161 [f71869] = 1,
162 [f71882fg] = 1,
163 [f71889fg] = 1,
164 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100165 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100166 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100167 [f81865f] = 1,
Hans de Goede78aa4f72011-03-09 20:57:12 +0100168};
169
Jean Delvaref27def02011-03-26 10:45:01 +0100170static const char f71882fg_nr_fans[] = {
171 [f71808e] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200172 [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */
Jean Delvaref27def02011-03-26 10:45:01 +0100173 [f71858fg] = 3,
174 [f71862fg] = 3,
175 [f71869] = 3,
176 [f71882fg] = 4,
177 [f71889fg] = 3,
178 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100179 [f71889a] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200180 [f8000] = 3, /* +1 fan which is monitor only */
Jean Delvare383586b2011-03-26 10:45:02 +0100181 [f81865f] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100182};
183
Hans de Goede4d538112011-05-25 20:43:32 +0200184static const char f71882fg_temp_has_beep[] = {
185 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200186 [f71808a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200187 [f71858fg] = 0,
188 [f71862fg] = 1,
189 [f71869] = 1,
190 [f71882fg] = 1,
191 [f71889fg] = 1,
192 [f71889ed] = 1,
193 [f71889a] = 1,
194 [f8000] = 0,
195 [f81865f] = 1,
196};
197
Jean Delvaref27def02011-03-26 10:45:01 +0100198static const char f71882fg_nr_temps[] = {
199 [f71808e] = 2,
Hans de Goede629c58b2011-05-25 20:43:32 +0200200 [f71808a] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100201 [f71858fg] = 3,
202 [f71862fg] = 3,
203 [f71869] = 3,
204 [f71882fg] = 3,
205 [f71889fg] = 3,
206 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100207 [f71889a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100208 [f8000] = 3,
Jean Delvare383586b2011-03-26 10:45:02 +0100209 [f81865f] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100210};
211
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100212static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200213
214/* Super-I/O Function prototypes */
215static inline int superio_inb(int base, int reg);
216static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400217static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200218static inline void superio_select(int base, int ld);
219static inline void superio_exit(int base);
220
Hans de Goede498be962009-01-07 16:37:28 +0100221struct f71882fg_sio_data {
222 enum chips type;
223};
224
Hans de Goede45fb3662007-07-13 14:34:19 +0200225struct f71882fg_data {
226 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100227 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700228 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200229
230 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200231 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200232 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100233 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200234 unsigned long last_updated; /* In jiffies */
235 unsigned long last_limits; /* In jiffies */
236
237 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100238 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200239 u8 in1_max;
240 u8 in_status;
241 u8 in_beep;
242 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100243 u16 fan_target[4];
244 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200245 u8 fan_status;
246 u8 fan_beep;
Hans de Goedee5e713c2011-03-10 08:54:02 +0100247 /* Note: all models have max 3 temperature channels, but on some
Hans de Goede7567a042009-01-07 16:37:28 +0100248 they are addressed as 0-2 and on others as 1-3, so for coding
249 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200250 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100251 u8 temp_ovt[4];
252 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100253 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100254 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200255 u8 temp_status;
256 u8 temp_beep;
257 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200258 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100259 u8 pwm[4];
260 u8 pwm_enable;
261 u8 pwm_auto_point_hyst[2];
262 u8 pwm_auto_point_mapping[4];
263 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100264 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200265};
266
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100267/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200268static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
269 char *buf);
270static ssize_t show_in_max(struct device *dev, struct device_attribute
271 *devattr, char *buf);
272static ssize_t store_in_max(struct device *dev, struct device_attribute
273 *devattr, const char *buf, size_t count);
274static ssize_t show_in_beep(struct device *dev, struct device_attribute
275 *devattr, char *buf);
276static ssize_t store_in_beep(struct device *dev, struct device_attribute
277 *devattr, const char *buf, size_t count);
278static ssize_t show_in_alarm(struct device *dev, struct device_attribute
279 *devattr, char *buf);
280/* Sysfs Fan */
281static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
282 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100283static ssize_t show_fan_full_speed(struct device *dev,
284 struct device_attribute *devattr, char *buf);
285static ssize_t store_fan_full_speed(struct device *dev,
286 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200287static ssize_t show_fan_beep(struct device *dev, struct device_attribute
288 *devattr, char *buf);
289static ssize_t store_fan_beep(struct device *dev, struct device_attribute
290 *devattr, const char *buf, size_t count);
291static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
292 *devattr, char *buf);
293/* Sysfs Temp */
294static ssize_t show_temp(struct device *dev, struct device_attribute
295 *devattr, char *buf);
296static ssize_t show_temp_max(struct device *dev, struct device_attribute
297 *devattr, char *buf);
298static ssize_t store_temp_max(struct device *dev, struct device_attribute
299 *devattr, const char *buf, size_t count);
300static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
301 *devattr, char *buf);
302static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
303 *devattr, const char *buf, size_t count);
304static ssize_t show_temp_crit(struct device *dev, struct device_attribute
305 *devattr, char *buf);
306static ssize_t store_temp_crit(struct device *dev, struct device_attribute
307 *devattr, const char *buf, size_t count);
308static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
309 *devattr, char *buf);
310static ssize_t show_temp_type(struct device *dev, struct device_attribute
311 *devattr, char *buf);
312static ssize_t show_temp_beep(struct device *dev, struct device_attribute
313 *devattr, char *buf);
314static ssize_t store_temp_beep(struct device *dev, struct device_attribute
315 *devattr, const char *buf, size_t count);
316static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
317 *devattr, char *buf);
318static ssize_t show_temp_fault(struct device *dev, struct device_attribute
319 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100320/* PWM and Auto point control */
321static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
322 char *buf);
323static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
324 const char *buf, size_t count);
Hans de Goede629c58b2011-05-25 20:43:32 +0200325static ssize_t show_simple_pwm(struct device *dev,
326 struct device_attribute *devattr, char *buf);
327static ssize_t store_simple_pwm(struct device *dev,
328 struct device_attribute *devattr, const char *buf, size_t count);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100329static ssize_t show_pwm_enable(struct device *dev,
330 struct device_attribute *devattr, char *buf);
331static ssize_t store_pwm_enable(struct device *dev,
332 struct device_attribute *devattr, const char *buf, size_t count);
333static ssize_t show_pwm_interpolate(struct device *dev,
334 struct device_attribute *devattr, char *buf);
335static ssize_t store_pwm_interpolate(struct device *dev,
336 struct device_attribute *devattr, const char *buf, size_t count);
337static ssize_t show_pwm_auto_point_channel(struct device *dev,
338 struct device_attribute *devattr, char *buf);
339static ssize_t store_pwm_auto_point_channel(struct device *dev,
340 struct device_attribute *devattr, const char *buf, size_t count);
341static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
342 struct device_attribute *devattr, char *buf);
343static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
344 struct device_attribute *devattr, const char *buf, size_t count);
345static ssize_t show_pwm_auto_point_pwm(struct device *dev,
346 struct device_attribute *devattr, char *buf);
347static ssize_t store_pwm_auto_point_pwm(struct device *dev,
348 struct device_attribute *devattr, const char *buf, size_t count);
349static ssize_t show_pwm_auto_point_temp(struct device *dev,
350 struct device_attribute *devattr, char *buf);
351static ssize_t store_pwm_auto_point_temp(struct device *dev,
352 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200353/* Sysfs misc */
354static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
355 char *buf);
356
357static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100358static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200359
360static struct platform_driver f71882fg_driver = {
361 .driver = {
362 .owner = THIS_MODULE,
363 .name = DRVNAME,
364 },
365 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200366 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200367};
368
Hans de Goedec13548c2009-01-07 16:37:27 +0100369static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200370
Hans de Goede0bae6402011-03-09 20:57:10 +0100371/* Temp attr for the f71858fg, the f71858fg is special as it has its
372 temperature indexes start at 0 (the others start at 1) */
373static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200374 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
375 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
376 store_temp_max, 0, 0),
377 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
378 store_temp_max_hyst, 0, 0),
379 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
380 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
381 store_temp_crit, 0, 0),
382 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
383 0, 0),
384 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
385 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
386 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
387 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
388 store_temp_max, 0, 1),
389 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
390 store_temp_max_hyst, 0, 1),
391 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
392 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
393 store_temp_crit, 0, 1),
394 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
395 0, 1),
396 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200397 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
398 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
399 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
400 store_temp_max, 0, 2),
401 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
402 store_temp_max_hyst, 0, 2),
403 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
404 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
405 store_temp_crit, 0, 2),
406 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
407 0, 2),
408 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
409 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
410};
411
Hans de Goede0bae6402011-03-09 20:57:10 +0100412/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100413static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100414 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100415 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100416 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100417 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100418 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100419 /* Should really be temp1_max_alarm, but older versions did not handle
420 the max and crit alarms separately and lm_sensors v2 depends on the
421 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
422 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100423 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100424 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100425 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100427 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100428 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100429 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100430}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100431 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
432 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100433 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100434 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100435 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100436 /* Should be temp2_max_alarm, see temp1_alarm note */
437 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100438 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100439 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100440 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100441 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100442 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100443 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100444 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100445}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100446 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
447 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
448 store_temp_max, 0, 3),
449 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
450 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100451 /* Should be temp3_max_alarm, see temp1_alarm note */
452 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100453 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
454 store_temp_crit, 0, 3),
455 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
456 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100457 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100458 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100459 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100460} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200461
Hans de Goede78aa4f72011-03-09 20:57:12 +0100462/* Temp attr for models which can beep on temp alarm */
463static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
464 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
465 store_temp_beep, 0, 1),
466 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
467 store_temp_beep, 0, 5),
468}, {
469 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
470 store_temp_beep, 0, 2),
471 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
472 store_temp_beep, 0, 6),
473}, {
474 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
475 store_temp_beep, 0, 3),
476 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
477 store_temp_beep, 0, 7),
478} };
479
Hans de Goede0bae6402011-03-09 20:57:10 +0100480/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100481 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
482 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100483 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100484 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100485static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100486 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
487 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
488 store_temp_crit, 0, 0),
489 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
490 store_temp_max, 0, 0),
491 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200492 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100493 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
494 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
495 store_temp_crit, 0, 1),
496 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
497 store_temp_max, 0, 1),
498 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200499 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100500 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
501 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
502 store_temp_crit, 0, 2),
503 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
504 store_temp_max, 0, 2),
505 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200506 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100507};
508
Hans de Goede0bae6402011-03-09 20:57:10 +0100509/* in attr for all models */
510static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
511 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
512 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
513 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
514 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
515 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
516 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
517 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
518 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
519 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
520};
521
522/* For models with in1 alarm capability */
523static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
524 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
525 0, 1),
526 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
527 0, 1),
528 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
529};
530
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100531/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100532static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100533 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100534 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
535 show_fan_full_speed,
536 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100537 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100538 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
539 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
540 store_pwm_enable, 0, 0),
541 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
542 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100543}, {
544 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
545 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
546 show_fan_full_speed,
547 store_fan_full_speed, 0, 1),
548 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100549 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
550 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
551 store_pwm_enable, 0, 1),
552 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
553 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100554}, {
555 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
556 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
557 show_fan_full_speed,
558 store_fan_full_speed, 0, 2),
559 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200560 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
561 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
562 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100563 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
564 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100565}, {
566 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
567 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
568 show_fan_full_speed,
569 store_fan_full_speed, 0, 3),
570 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
571 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
572 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
573 store_pwm_enable, 0, 3),
574 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
575 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
576} };
Hans de Goede498be962009-01-07 16:37:28 +0100577
Hans de Goede629c58b2011-05-25 20:43:32 +0200578/* Attr for the third fan of the f71808a, which only has manual pwm */
579static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
580 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
581 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
582 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
583 show_simple_pwm, store_simple_pwm, 0, 2),
584};
585
Hans de Goede66344aa2009-12-09 20:35:59 +0100586/* Attr for models which can beep on Fan alarm */
587static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100588 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
589 store_fan_beep, 0, 0),
590 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
591 store_fan_beep, 0, 1),
592 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
593 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100594 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
595 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100596};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100597
Hans de Goede66344aa2009-12-09 20:35:59 +0100598/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100599 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100600static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
601 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
602 show_pwm_auto_point_channel,
603 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100604 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
605 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
606 1, 0),
607 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
608 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
609 4, 0),
610 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
611 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
612 0, 0),
613 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
614 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
615 3, 0),
616 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
617 show_pwm_auto_point_temp_hyst,
618 store_pwm_auto_point_temp_hyst,
619 0, 0),
620 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
621 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
622
Hans de Goede66344aa2009-12-09 20:35:59 +0100623 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
624 show_pwm_auto_point_channel,
625 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100626 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
627 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
628 1, 1),
629 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
630 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
631 4, 1),
632 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
633 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
634 0, 1),
635 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
636 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
637 3, 1),
638 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
639 show_pwm_auto_point_temp_hyst,
640 store_pwm_auto_point_temp_hyst,
641 0, 1),
642 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
643 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100644
Hans de Goede66344aa2009-12-09 20:35:59 +0100645 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
646 show_pwm_auto_point_channel,
647 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100648 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
649 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
650 1, 2),
651 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
652 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
653 4, 2),
654 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
656 0, 2),
657 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
659 3, 2),
660 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_temp_hyst,
662 store_pwm_auto_point_temp_hyst,
663 0, 2),
664 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
665 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100666};
667
Hans de Goedee5e713c2011-03-10 08:54:02 +0100668/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
Hans de Goedec11bb992011-03-09 20:57:15 +0100669 pwm setting when the temperature is above the pwmX_auto_point1_temp can be
670 programmed instead of being hardcoded to 0xff */
671static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
672 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
673 show_pwm_auto_point_channel,
674 store_pwm_auto_point_channel, 0, 0),
675 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
676 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
677 0, 0),
678 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
680 1, 0),
681 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 4, 0),
684 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
686 0, 0),
687 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
689 3, 0),
690 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp_hyst,
692 store_pwm_auto_point_temp_hyst,
693 0, 0),
694 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
695 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
696
697 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
698 show_pwm_auto_point_channel,
699 store_pwm_auto_point_channel, 0, 1),
700 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
701 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
702 0, 1),
703 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
704 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
705 1, 1),
706 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
707 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
708 4, 1),
709 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
710 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
711 0, 1),
712 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
713 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
714 3, 1),
715 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
716 show_pwm_auto_point_temp_hyst,
717 store_pwm_auto_point_temp_hyst,
718 0, 1),
719 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
720 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
721
722 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_channel,
724 store_pwm_auto_point_channel, 0, 2),
725 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
727 0, 2),
728 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
729 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
730 1, 2),
731 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
732 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
733 4, 2),
734 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
735 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
736 0, 2),
737 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
738 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
739 3, 2),
740 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
741 show_pwm_auto_point_temp_hyst,
742 store_pwm_auto_point_temp_hyst,
743 0, 2),
744 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
745 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
746};
747
Hans de Goede3cad4022011-03-09 20:57:14 +0100748/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100749static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100750 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_channel,
752 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100753 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
754 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
755 0, 0),
756 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
757 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
758 1, 0),
759 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
760 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
761 2, 0),
762 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
763 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
764 3, 0),
765 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
766 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
767 4, 0),
768 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
769 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
770 0, 0),
771 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
772 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
773 1, 0),
774 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
776 2, 0),
777 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
778 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
779 3, 0),
780 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
781 show_pwm_auto_point_temp_hyst,
782 store_pwm_auto_point_temp_hyst,
783 0, 0),
784 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
785 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
786 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
787 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
788 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
789 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100790}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100791 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_channel,
793 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100794 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
796 0, 1),
797 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
799 1, 1),
800 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
802 2, 1),
803 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
804 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
805 3, 1),
806 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
807 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
808 4, 1),
809 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
811 0, 1),
812 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
814 1, 1),
815 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
817 2, 1),
818 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
819 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
820 3, 1),
821 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
822 show_pwm_auto_point_temp_hyst,
823 store_pwm_auto_point_temp_hyst,
824 0, 1),
825 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
826 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
827 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
828 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
829 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
830 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100831}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100832 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_channel,
834 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100835 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
837 0, 2),
838 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
840 1, 2),
841 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
843 2, 2),
844 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
845 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
846 3, 2),
847 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
848 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
849 4, 2),
850 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
851 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
852 0, 2),
853 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
854 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
855 1, 2),
856 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
857 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
858 2, 2),
859 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
860 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
861 3, 2),
862 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
863 show_pwm_auto_point_temp_hyst,
864 store_pwm_auto_point_temp_hyst,
865 0, 2),
866 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
867 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
868 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
869 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
870 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
871 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100872}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100873 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_channel,
875 store_pwm_auto_point_channel, 0, 3),
876 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
877 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
878 0, 3),
879 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
880 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
881 1, 3),
882 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
883 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
884 2, 3),
885 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
886 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
887 3, 3),
888 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
889 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
890 4, 3),
891 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
892 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
893 0, 3),
894 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
895 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
896 1, 3),
897 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
898 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
899 2, 3),
900 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
901 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
902 3, 3),
903 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
904 show_pwm_auto_point_temp_hyst,
905 store_pwm_auto_point_temp_hyst,
906 0, 3),
907 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
908 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
909 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
910 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
911 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
912 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100913} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200914
Hans de Goede66344aa2009-12-09 20:35:59 +0100915/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100916static struct sensor_device_attribute_2 f8000_fan_attr[] = {
917 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100918};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100919
Hans de Goede66344aa2009-12-09 20:35:59 +0100920/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
921 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
922 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
923static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
924 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
925 show_pwm_auto_point_channel,
926 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100927 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
928 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
929 0, 2),
930 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
931 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
932 1, 2),
933 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
934 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
935 2, 2),
936 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
937 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
938 3, 2),
939 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
940 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
941 4, 2),
942 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
943 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
944 0, 2),
945 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
946 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
947 1, 2),
948 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
949 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
950 2, 2),
951 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
952 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
953 3, 2),
954 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
955 show_pwm_auto_point_temp_hyst,
956 store_pwm_auto_point_temp_hyst,
957 0, 2),
958 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
959 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
960 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
961 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
962 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
963 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
964
Hans de Goede66344aa2009-12-09 20:35:59 +0100965 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
966 show_pwm_auto_point_channel,
967 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100968 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
969 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
970 0, 0),
971 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
972 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
973 1, 0),
974 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
975 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
976 2, 0),
977 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
978 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
979 3, 0),
980 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
981 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
982 4, 0),
983 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
984 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
985 0, 0),
986 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
987 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
988 1, 0),
989 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
990 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
991 2, 0),
992 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
993 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
994 3, 0),
995 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
996 show_pwm_auto_point_temp_hyst,
997 store_pwm_auto_point_temp_hyst,
998 0, 0),
999 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
1000 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
1001 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
1002 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
1003 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
1004 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
1005
Hans de Goede66344aa2009-12-09 20:35:59 +01001006 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
1007 show_pwm_auto_point_channel,
1008 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001009 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
1010 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1011 0, 1),
1012 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
1013 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1014 1, 1),
1015 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
1016 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1017 2, 1),
1018 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
1019 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1020 3, 1),
1021 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
1022 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1023 4, 1),
1024 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
1025 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1026 0, 1),
1027 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
1028 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1029 1, 1),
1030 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
1031 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1032 2, 1),
1033 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
1034 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1035 3, 1),
1036 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1037 show_pwm_auto_point_temp_hyst,
1038 store_pwm_auto_point_temp_hyst,
1039 0, 1),
1040 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
1041 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
1042 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
1043 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
1044 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
1045 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
1046};
Hans de Goede45fb3662007-07-13 14:34:19 +02001047
1048/* Super I/O functions */
1049static inline int superio_inb(int base, int reg)
1050{
1051 outb(reg, base);
1052 return inb(base + 1);
1053}
1054
1055static int superio_inw(int base, int reg)
1056{
1057 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001058 val = superio_inb(base, reg) << 8;
1059 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001060 return val;
1061}
1062
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001063static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +02001064{
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001065 /* Don't step on other drivers' I/O space by accident */
1066 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +00001067 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001068 return -EBUSY;
1069 }
1070
Hans de Goede45fb3662007-07-13 14:34:19 +02001071 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001072 outb(SIO_UNLOCK_KEY, base);
1073 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001074
1075 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001076}
1077
Giel van Schijndel162bb592010-05-27 19:58:40 +02001078static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001079{
1080 outb(SIO_REG_LDSEL, base);
1081 outb(ld, base + 1);
1082}
1083
1084static inline void superio_exit(int base)
1085{
1086 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001087 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001088}
1089
Hans de Goede2f650632009-01-07 16:37:31 +01001090static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001091{
1092 return reg ? (1500000 / reg) : 0;
1093}
1094
Hans de Goede2f650632009-01-07 16:37:31 +01001095static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001096{
1097 return fan ? (1500000 / fan) : 0;
1098}
1099
Hans de Goede45fb3662007-07-13 14:34:19 +02001100static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1101{
1102 u8 val;
1103
1104 outb(reg, data->addr + ADDR_REG_OFFSET);
1105 val = inb(data->addr + DATA_REG_OFFSET);
1106
1107 return val;
1108}
1109
1110static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1111{
1112 u16 val;
1113
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001114 val = f71882fg_read8(data, reg) << 8;
1115 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001116
1117 return val;
1118}
1119
1120static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1121{
1122 outb(reg, data->addr + ADDR_REG_OFFSET);
1123 outb(val, data->addr + DATA_REG_OFFSET);
1124}
1125
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001126static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1127{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001128 f71882fg_write8(data, reg, val >> 8);
1129 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001130}
1131
Hans de Goede09475d32009-06-15 18:39:52 +02001132static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1133{
1134 if (data->type == f71858fg)
1135 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1136 else
1137 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1138}
1139
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001140static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001141{
1142 struct f71882fg_data *data = dev_get_drvdata(dev);
Jean Delvaref27def02011-03-26 10:45:01 +01001143 int nr_fans = f71882fg_nr_fans[data->type];
1144 int nr_temps = f71882fg_nr_temps[data->type];
Hans de Goedee5e713c2011-03-10 08:54:02 +01001145 int nr, reg, point;
Hans de Goede45fb3662007-07-13 14:34:19 +02001146
1147 mutex_lock(&data->update_lock);
1148
1149 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001150 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001151 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001152 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001153 data->in1_max =
1154 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1155 data->in_beep =
1156 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1157 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001158
1159 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001160 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1161 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001162 data->temp_ovt[nr] = f71882fg_read8(data,
1163 F71882FG_REG_TEMP_OVT(nr));
1164 data->temp_high[nr] = f71882fg_read8(data,
1165 F71882FG_REG_TEMP_HIGH(nr));
1166 }
1167
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001168 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001169 data->temp_hyst[0] = f71882fg_read8(data,
1170 F71882FG_REG_TEMP_HYST(0));
1171 data->temp_hyst[1] = f71882fg_read8(data,
1172 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001173 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001174 /* All but the f71858fg / f8000 have this register */
1175 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001176 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001177 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001178 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1179 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1180 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001181
Hans de Goede4d538112011-05-25 20:43:32 +02001182 if (f71882fg_fan_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001183 data->fan_beep = f71882fg_read8(data,
1184 F71882FG_REG_FAN_BEEP);
Hans de Goede4d538112011-05-25 20:43:32 +02001185
1186 if (f71882fg_temp_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001187 data->temp_beep = f71882fg_read8(data,
1188 F71882FG_REG_TEMP_BEEP);
Hans de Goede78aa4f72011-03-09 20:57:12 +01001189
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001190 data->pwm_enable = f71882fg_read8(data,
1191 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001192 data->pwm_auto_point_hyst[0] =
1193 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1194 data->pwm_auto_point_hyst[1] =
1195 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1196
Hans de Goede498be962009-01-07 16:37:28 +01001197 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001198 data->pwm_auto_point_mapping[nr] =
1199 f71882fg_read8(data,
1200 F71882FG_REG_POINT_MAPPING(nr));
1201
Hans de Goedee5e713c2011-03-10 08:54:02 +01001202 switch (data->type) {
1203 default:
Hans de Goede498be962009-01-07 16:37:28 +01001204 for (point = 0; point < 5; point++) {
1205 data->pwm_auto_point_pwm[nr][point] =
1206 f71882fg_read8(data,
1207 F71882FG_REG_POINT_PWM
1208 (nr, point));
1209 }
1210 for (point = 0; point < 4; point++) {
1211 data->pwm_auto_point_temp[nr][point] =
1212 f71882fg_read8(data,
1213 F71882FG_REG_POINT_TEMP
1214 (nr, point));
1215 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001216 break;
1217 case f71808e:
1218 case f71869:
1219 data->pwm_auto_point_pwm[nr][0] =
1220 f71882fg_read8(data,
1221 F71882FG_REG_POINT_PWM(nr, 0));
1222 /* Fall through */
1223 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001224 data->pwm_auto_point_pwm[nr][1] =
1225 f71882fg_read8(data,
1226 F71882FG_REG_POINT_PWM
1227 (nr, 1));
1228 data->pwm_auto_point_pwm[nr][4] =
1229 f71882fg_read8(data,
1230 F71882FG_REG_POINT_PWM
1231 (nr, 4));
1232 data->pwm_auto_point_temp[nr][0] =
1233 f71882fg_read8(data,
1234 F71882FG_REG_POINT_TEMP
1235 (nr, 0));
1236 data->pwm_auto_point_temp[nr][3] =
1237 f71882fg_read8(data,
1238 F71882FG_REG_POINT_TEMP
1239 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001240 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001241 }
1242 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001243 data->last_limits = jiffies;
1244 }
1245
1246 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001247 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001248 data->temp_status = f71882fg_read8(data,
1249 F71882FG_REG_TEMP_STATUS);
1250 data->temp_diode_open = f71882fg_read8(data,
1251 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001252 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1253 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001254 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001255
1256 data->fan_status = f71882fg_read8(data,
1257 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001258 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001259 data->fan[nr] = f71882fg_read16(data,
1260 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001261 data->fan_target[nr] =
1262 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1263 data->fan_full_speed[nr] =
1264 f71882fg_read16(data,
1265 F71882FG_REG_FAN_FULL_SPEED(nr));
1266 data->pwm[nr] =
1267 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1268 }
Hans de Goede629c58b2011-05-25 20:43:32 +02001269 /* Some models have 1 more fan with limited capabilities */
1270 if (data->type == f71808a) {
1271 data->fan[2] = f71882fg_read16(data,
1272 F71882FG_REG_FAN(2));
1273 data->pwm[2] = f71882fg_read8(data,
1274 F71882FG_REG_PWM(2));
1275 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001276 if (data->type == f8000)
1277 data->fan[3] = f71882fg_read16(data,
1278 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001279
1280 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001281 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001282 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001283 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1284 if (f71882fg_has_in[data->type][nr])
1285 data->in[nr] = f71882fg_read8(data,
1286 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001287
1288 data->last_updated = jiffies;
1289 data->valid = 1;
1290 }
1291
1292 mutex_unlock(&data->update_lock);
1293
1294 return data;
1295}
1296
1297/* Sysfs Interface */
1298static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1299 char *buf)
1300{
1301 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001302 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001303 int speed = fan_from_reg(data->fan[nr]);
1304
1305 if (speed == FAN_MIN_DETECT)
1306 speed = 0;
1307
1308 return sprintf(buf, "%d\n", speed);
1309}
1310
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001311static ssize_t show_fan_full_speed(struct device *dev,
1312 struct device_attribute *devattr, char *buf)
1313{
1314 struct f71882fg_data *data = f71882fg_update_device(dev);
1315 int nr = to_sensor_dev_attr_2(devattr)->index;
1316 int speed = fan_from_reg(data->fan_full_speed[nr]);
1317 return sprintf(buf, "%d\n", speed);
1318}
1319
1320static ssize_t store_fan_full_speed(struct device *dev,
1321 struct device_attribute *devattr,
1322 const char *buf, size_t count)
1323{
1324 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001325 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1326 long val;
1327
1328 err = strict_strtol(buf, 10, &val);
1329 if (err)
1330 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001331
1332 val = SENSORS_LIMIT(val, 23, 1500000);
1333 val = fan_to_reg(val);
1334
1335 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001336 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1337 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001338 mutex_unlock(&data->update_lock);
1339
1340 return count;
1341}
1342
Hans de Goede45fb3662007-07-13 14:34:19 +02001343static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1344 *devattr, char *buf)
1345{
1346 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001347 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001348
1349 if (data->fan_beep & (1 << nr))
1350 return sprintf(buf, "1\n");
1351 else
1352 return sprintf(buf, "0\n");
1353}
1354
1355static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1356 *devattr, const char *buf, size_t count)
1357{
1358 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001359 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1360 unsigned long val;
1361
1362 err = strict_strtoul(buf, 10, &val);
1363 if (err)
1364 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001365
1366 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001367 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001368 if (val)
1369 data->fan_beep |= 1 << nr;
1370 else
1371 data->fan_beep &= ~(1 << nr);
1372
1373 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1374 mutex_unlock(&data->update_lock);
1375
1376 return count;
1377}
1378
1379static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1380 *devattr, char *buf)
1381{
1382 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001383 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001384
1385 if (data->fan_status & (1 << nr))
1386 return sprintf(buf, "1\n");
1387 else
1388 return sprintf(buf, "0\n");
1389}
1390
1391static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1392 char *buf)
1393{
1394 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001395 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001396
1397 return sprintf(buf, "%d\n", data->in[nr] * 8);
1398}
1399
1400static ssize_t show_in_max(struct device *dev, struct device_attribute
1401 *devattr, char *buf)
1402{
1403 struct f71882fg_data *data = f71882fg_update_device(dev);
1404
1405 return sprintf(buf, "%d\n", data->in1_max * 8);
1406}
1407
1408static ssize_t store_in_max(struct device *dev, struct device_attribute
1409 *devattr, const char *buf, size_t count)
1410{
1411 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001412 int err;
1413 long val;
1414
1415 err = strict_strtol(buf, 10, &val);
1416 if (err)
1417 return err;
1418
1419 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001420 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001421
1422 mutex_lock(&data->update_lock);
1423 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1424 data->in1_max = val;
1425 mutex_unlock(&data->update_lock);
1426
1427 return count;
1428}
1429
1430static ssize_t show_in_beep(struct device *dev, struct device_attribute
1431 *devattr, char *buf)
1432{
1433 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001434 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001435
1436 if (data->in_beep & (1 << nr))
1437 return sprintf(buf, "1\n");
1438 else
1439 return sprintf(buf, "0\n");
1440}
1441
1442static ssize_t store_in_beep(struct device *dev, struct device_attribute
1443 *devattr, const char *buf, size_t count)
1444{
1445 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001446 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1447 unsigned long val;
1448
1449 err = strict_strtoul(buf, 10, &val);
1450 if (err)
1451 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001452
1453 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001454 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001455 if (val)
1456 data->in_beep |= 1 << nr;
1457 else
1458 data->in_beep &= ~(1 << nr);
1459
1460 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1461 mutex_unlock(&data->update_lock);
1462
1463 return count;
1464}
1465
1466static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1467 *devattr, char *buf)
1468{
1469 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001470 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001471
1472 if (data->in_status & (1 << nr))
1473 return sprintf(buf, "1\n");
1474 else
1475 return sprintf(buf, "0\n");
1476}
1477
1478static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1479 char *buf)
1480{
1481 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001482 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001483 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001484
Hans de Goede09475d32009-06-15 18:39:52 +02001485 if (data->type == f71858fg) {
1486 /* TEMP_TABLE_SEL 1 or 3 ? */
1487 if (data->temp_config & 1) {
1488 sign = data->temp[nr] & 0x0001;
1489 temp = (data->temp[nr] >> 5) & 0x7ff;
1490 } else {
1491 sign = data->temp[nr] & 0x8000;
1492 temp = (data->temp[nr] >> 5) & 0x3ff;
1493 }
1494 temp *= 125;
1495 if (sign)
1496 temp -= 128000;
1497 } else
1498 temp = data->temp[nr] * 1000;
1499
1500 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001501}
1502
1503static ssize_t show_temp_max(struct device *dev, struct device_attribute
1504 *devattr, char *buf)
1505{
1506 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001507 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001508
1509 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1510}
1511
1512static ssize_t store_temp_max(struct device *dev, struct device_attribute
1513 *devattr, const char *buf, size_t count)
1514{
1515 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001516 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1517 long val;
1518
1519 err = strict_strtol(buf, 10, &val);
1520 if (err)
1521 return err;
1522
1523 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001524 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001525
1526 mutex_lock(&data->update_lock);
1527 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1528 data->temp_high[nr] = val;
1529 mutex_unlock(&data->update_lock);
1530
1531 return count;
1532}
1533
1534static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1535 *devattr, char *buf)
1536{
1537 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001538 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001539 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001540
Hans de Goedece0bfa52009-01-07 16:37:28 +01001541 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001542 if (nr & 1)
1543 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1544 else
1545 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1546 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001547 mutex_unlock(&data->update_lock);
1548
1549 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001550}
1551
1552static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1553 *devattr, const char *buf, size_t count)
1554{
1555 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001556 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001557 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001558 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001559 long val;
1560
1561 err = strict_strtol(buf, 10, &val);
1562 if (err)
1563 return err;
1564
1565 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001566
1567 mutex_lock(&data->update_lock);
1568
1569 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001570 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1571 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1572 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001573 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001574
1575 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001576 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1577 if (nr & 1)
1578 reg = (reg & 0x0f) | (val << 4);
1579 else
1580 reg = (reg & 0xf0) | val;
1581 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1582 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001583
Hans de Goede45fb3662007-07-13 14:34:19 +02001584 mutex_unlock(&data->update_lock);
1585 return ret;
1586}
1587
1588static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1589 *devattr, char *buf)
1590{
1591 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001592 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001593
1594 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1595}
1596
1597static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1598 *devattr, const char *buf, size_t count)
1599{
1600 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001601 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1602 long val;
1603
1604 err = strict_strtol(buf, 10, &val);
1605 if (err)
1606 return err;
1607
1608 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001609 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001610
1611 mutex_lock(&data->update_lock);
1612 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1613 data->temp_ovt[nr] = val;
1614 mutex_unlock(&data->update_lock);
1615
1616 return count;
1617}
1618
1619static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1620 *devattr, char *buf)
1621{
1622 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001623 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001624 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001625
Hans de Goedece0bfa52009-01-07 16:37:28 +01001626 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001627 if (nr & 1)
1628 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1629 else
1630 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1631 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001632 mutex_unlock(&data->update_lock);
1633
1634 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001635}
1636
1637static ssize_t show_temp_type(struct device *dev, struct device_attribute
1638 *devattr, char *buf)
1639{
1640 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001641 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001642
1643 return sprintf(buf, "%d\n", data->temp_type[nr]);
1644}
1645
1646static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1647 *devattr, char *buf)
1648{
1649 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001650 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001651
Hans de Goede7567a042009-01-07 16:37:28 +01001652 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001653 return sprintf(buf, "1\n");
1654 else
1655 return sprintf(buf, "0\n");
1656}
1657
1658static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1659 *devattr, const char *buf, size_t count)
1660{
1661 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001662 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1663 unsigned long val;
1664
1665 err = strict_strtoul(buf, 10, &val);
1666 if (err)
1667 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001668
1669 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001670 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001671 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001672 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001673 else
Hans de Goede7567a042009-01-07 16:37:28 +01001674 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001675
1676 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1677 mutex_unlock(&data->update_lock);
1678
1679 return count;
1680}
1681
1682static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1683 *devattr, char *buf)
1684{
1685 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001686 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001687
Hans de Goede7567a042009-01-07 16:37:28 +01001688 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001689 return sprintf(buf, "1\n");
1690 else
1691 return sprintf(buf, "0\n");
1692}
1693
1694static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1695 *devattr, char *buf)
1696{
1697 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001698 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001699
Hans de Goede7567a042009-01-07 16:37:28 +01001700 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001701 return sprintf(buf, "1\n");
1702 else
1703 return sprintf(buf, "0\n");
1704}
1705
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001706static ssize_t show_pwm(struct device *dev,
1707 struct device_attribute *devattr, char *buf)
1708{
1709 struct f71882fg_data *data = f71882fg_update_device(dev);
1710 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001711 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001712 if (data->pwm_enable & (1 << (2 * nr)))
1713 /* PWM mode */
1714 val = data->pwm[nr];
1715 else {
1716 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001717 val = 255 * fan_from_reg(data->fan_target[nr])
1718 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001719 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001720 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001721 return sprintf(buf, "%d\n", val);
1722}
1723
1724static ssize_t store_pwm(struct device *dev,
1725 struct device_attribute *devattr, const char *buf,
1726 size_t count)
1727{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001728 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001729 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1730 long val;
1731
1732 err = strict_strtol(buf, 10, &val);
1733 if (err)
1734 return err;
1735
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001736 val = SENSORS_LIMIT(val, 0, 255);
1737
1738 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001739 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001740 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1741 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1742 count = -EROFS;
1743 goto leave;
1744 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001745 if (data->pwm_enable & (1 << (2 * nr))) {
1746 /* PWM mode */
1747 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1748 data->pwm[nr] = val;
1749 } else {
1750 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001751 int target, full_speed;
1752 full_speed = f71882fg_read16(data,
1753 F71882FG_REG_FAN_FULL_SPEED(nr));
1754 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1755 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1756 data->fan_target[nr] = target;
1757 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001758 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001759leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001760 mutex_unlock(&data->update_lock);
1761
1762 return count;
1763}
1764
Hans de Goede629c58b2011-05-25 20:43:32 +02001765static ssize_t show_simple_pwm(struct device *dev,
1766 struct device_attribute *devattr, char *buf)
1767{
1768 struct f71882fg_data *data = f71882fg_update_device(dev);
1769 int val, nr = to_sensor_dev_attr_2(devattr)->index;
1770
1771 val = data->pwm[nr];
1772 return sprintf(buf, "%d\n", val);
1773}
1774
1775static ssize_t store_simple_pwm(struct device *dev,
1776 struct device_attribute *devattr,
1777 const char *buf, size_t count)
1778{
1779 struct f71882fg_data *data = dev_get_drvdata(dev);
1780 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1781 long val;
1782
1783 err = strict_strtol(buf, 10, &val);
1784 if (err)
1785 return err;
1786
1787 val = SENSORS_LIMIT(val, 0, 255);
1788
1789 mutex_lock(&data->update_lock);
1790 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1791 data->pwm[nr] = val;
1792 mutex_unlock(&data->update_lock);
1793
1794 return count;
1795}
1796
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001797static ssize_t show_pwm_enable(struct device *dev,
1798 struct device_attribute *devattr, char *buf)
1799{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001800 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001801 struct f71882fg_data *data = f71882fg_update_device(dev);
1802 int nr = to_sensor_dev_attr_2(devattr)->index;
1803
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001804 switch ((data->pwm_enable >> 2 * nr) & 3) {
1805 case 0:
1806 case 1:
1807 result = 2; /* Normal auto mode */
1808 break;
1809 case 2:
1810 result = 1; /* Manual mode */
1811 break;
1812 case 3:
1813 if (data->type == f8000)
1814 result = 3; /* Thermostat mode */
1815 else
1816 result = 1; /* Manual mode */
1817 break;
1818 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001819
1820 return sprintf(buf, "%d\n", result);
1821}
1822
1823static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1824 *devattr, const char *buf, size_t count)
1825{
1826 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001827 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1828 long val;
1829
1830 err = strict_strtol(buf, 10, &val);
1831 if (err)
1832 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001833
Hans de Goede3fc78382009-06-15 18:39:50 +02001834 /* Special case for F8000 pwm channel 3 which only does auto mode */
1835 if (data->type == f8000 && nr == 2 && val != 2)
1836 return -EINVAL;
1837
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001838 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001839 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001840 /* Special case for F8000 auto PWM mode / Thermostat mode */
1841 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1842 switch (val) {
1843 case 2:
1844 data->pwm_enable &= ~(2 << (2 * nr));
1845 break; /* Normal auto mode */
1846 case 3:
1847 data->pwm_enable |= 2 << (2 * nr);
1848 break; /* Thermostat mode */
1849 default:
1850 count = -EINVAL;
1851 goto leave;
1852 }
1853 } else {
1854 switch (val) {
1855 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001856 /* The f71858fg does not support manual RPM mode */
1857 if (data->type == f71858fg &&
1858 ((data->pwm_enable >> (2 * nr)) & 1)) {
1859 count = -EINVAL;
1860 goto leave;
1861 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001862 data->pwm_enable |= 2 << (2 * nr);
1863 break; /* Manual */
1864 case 2:
1865 data->pwm_enable &= ~(2 << (2 * nr));
1866 break; /* Normal auto mode */
1867 default:
1868 count = -EINVAL;
1869 goto leave;
1870 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001871 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001872 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001873leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001874 mutex_unlock(&data->update_lock);
1875
1876 return count;
1877}
1878
1879static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1880 struct device_attribute *devattr,
1881 char *buf)
1882{
1883 int result;
1884 struct f71882fg_data *data = f71882fg_update_device(dev);
1885 int pwm = to_sensor_dev_attr_2(devattr)->index;
1886 int point = to_sensor_dev_attr_2(devattr)->nr;
1887
Hans de Goedece0bfa52009-01-07 16:37:28 +01001888 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001889 if (data->pwm_enable & (1 << (2 * pwm))) {
1890 /* PWM mode */
1891 result = data->pwm_auto_point_pwm[pwm][point];
1892 } else {
1893 /* RPM mode */
1894 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1895 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001896 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001897
1898 return sprintf(buf, "%d\n", result);
1899}
1900
1901static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1902 struct device_attribute *devattr,
1903 const char *buf, size_t count)
1904{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001905 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001906 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001907 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001908 long val;
1909
1910 err = strict_strtol(buf, 10, &val);
1911 if (err)
1912 return err;
1913
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001914 val = SENSORS_LIMIT(val, 0, 255);
1915
1916 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001917 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001918 if (data->pwm_enable & (1 << (2 * pwm))) {
1919 /* PWM mode */
1920 } else {
1921 /* RPM mode */
1922 if (val < 29) /* Prevent negative numbers */
1923 val = 255;
1924 else
1925 val = (255 - val) * 32 / val;
1926 }
1927 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1928 data->pwm_auto_point_pwm[pwm][point] = val;
1929 mutex_unlock(&data->update_lock);
1930
1931 return count;
1932}
1933
1934static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1935 struct device_attribute *devattr,
1936 char *buf)
1937{
1938 int result = 0;
1939 struct f71882fg_data *data = f71882fg_update_device(dev);
1940 int nr = to_sensor_dev_attr_2(devattr)->index;
1941 int point = to_sensor_dev_attr_2(devattr)->nr;
1942
1943 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001944 if (nr & 1)
1945 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1946 else
1947 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001948 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1949 mutex_unlock(&data->update_lock);
1950
1951 return sprintf(buf, "%d\n", result);
1952}
1953
1954static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1955 struct device_attribute *devattr,
1956 const char *buf, size_t count)
1957{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001958 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001959 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001960 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001961 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001962 long val;
1963
1964 err = strict_strtol(buf, 10, &val);
1965 if (err)
1966 return err;
1967
1968 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001969
1970 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001971 data->pwm_auto_point_temp[nr][point] =
1972 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001973 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1974 data->pwm_auto_point_temp[nr][point]);
1975 val = data->pwm_auto_point_temp[nr][point] - val;
1976
Hans de Goedebc274902009-01-07 16:37:29 +01001977 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1978 if (nr & 1)
1979 reg = (reg & 0x0f) | (val << 4);
1980 else
1981 reg = (reg & 0xf0) | val;
1982
1983 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1984 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001985 mutex_unlock(&data->update_lock);
1986
1987 return count;
1988}
1989
1990static ssize_t show_pwm_interpolate(struct device *dev,
1991 struct device_attribute *devattr, char *buf)
1992{
1993 int result;
1994 struct f71882fg_data *data = f71882fg_update_device(dev);
1995 int nr = to_sensor_dev_attr_2(devattr)->index;
1996
1997 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
1998
1999 return sprintf(buf, "%d\n", result);
2000}
2001
2002static ssize_t store_pwm_interpolate(struct device *dev,
2003 struct device_attribute *devattr,
2004 const char *buf, size_t count)
2005{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002006 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002007 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2008 unsigned long val;
2009
2010 err = strict_strtoul(buf, 10, &val);
2011 if (err)
2012 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01002013
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002014 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002015 data->pwm_auto_point_mapping[nr] =
2016 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002017 if (val)
2018 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
2019 else
2020 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
2021 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2022 data->pwm_auto_point_mapping[nr] = val;
2023 mutex_unlock(&data->update_lock);
2024
2025 return count;
2026}
2027
2028static ssize_t show_pwm_auto_point_channel(struct device *dev,
2029 struct device_attribute *devattr,
2030 char *buf)
2031{
2032 int result;
2033 struct f71882fg_data *data = f71882fg_update_device(dev);
2034 int nr = to_sensor_dev_attr_2(devattr)->index;
2035
Hans de Goede09475d32009-06-15 18:39:52 +02002036 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
2037 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002038
2039 return sprintf(buf, "%d\n", result);
2040}
2041
2042static ssize_t store_pwm_auto_point_channel(struct device *dev,
2043 struct device_attribute *devattr,
2044 const char *buf, size_t count)
2045{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002046 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002047 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2048 long val;
2049
2050 err = strict_strtol(buf, 10, &val);
2051 if (err)
2052 return err;
Hans de Goede30453012009-01-07 16:37:30 +01002053
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002054 switch (val) {
2055 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01002056 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002057 break;
2058 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01002059 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002060 break;
2061 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01002062 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002063 break;
2064 default:
2065 return -EINVAL;
2066 }
Hans de Goede09475d32009-06-15 18:39:52 +02002067 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002068 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002069 data->pwm_auto_point_mapping[nr] =
2070 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002071 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
2072 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2073 data->pwm_auto_point_mapping[nr] = val;
2074 mutex_unlock(&data->update_lock);
2075
2076 return count;
2077}
2078
2079static ssize_t show_pwm_auto_point_temp(struct device *dev,
2080 struct device_attribute *devattr,
2081 char *buf)
2082{
2083 int result;
2084 struct f71882fg_data *data = f71882fg_update_device(dev);
2085 int pwm = to_sensor_dev_attr_2(devattr)->index;
2086 int point = to_sensor_dev_attr_2(devattr)->nr;
2087
2088 result = data->pwm_auto_point_temp[pwm][point];
2089 return sprintf(buf, "%d\n", 1000 * result);
2090}
2091
2092static ssize_t store_pwm_auto_point_temp(struct device *dev,
2093 struct device_attribute *devattr,
2094 const char *buf, size_t count)
2095{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002096 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002097 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002098 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002099 long val;
2100
2101 err = strict_strtol(buf, 10, &val);
2102 if (err)
2103 return err;
2104
2105 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01002106
Hans de Goede98f7ba12011-03-09 20:57:09 +01002107 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01002108 val = SENSORS_LIMIT(val, -128, 127);
2109 else
2110 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002111
2112 mutex_lock(&data->update_lock);
2113 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2114 data->pwm_auto_point_temp[pwm][point] = val;
2115 mutex_unlock(&data->update_lock);
2116
2117 return count;
2118}
2119
Hans de Goede45fb3662007-07-13 14:34:19 +02002120static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2121 char *buf)
2122{
Hans de Goede498be962009-01-07 16:37:28 +01002123 struct f71882fg_data *data = dev_get_drvdata(dev);
2124 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002125}
2126
Hans de Goedec13548c2009-01-07 16:37:27 +01002127static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
2128 struct sensor_device_attribute_2 *attr, int count)
2129{
2130 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002131
Hans de Goedec13548c2009-01-07 16:37:27 +01002132 for (i = 0; i < count; i++) {
2133 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2134 if (err)
2135 return err;
2136 }
2137 return 0;
2138}
2139
Hans de Goedefc16c562009-12-09 20:36:01 +01002140static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2141 struct sensor_device_attribute_2 *attr, int count)
2142{
2143 int i;
2144
2145 for (i = 0; i < count; i++)
2146 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2147}
2148
Hans de Goedec13548c2009-01-07 16:37:27 +01002149static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002150{
2151 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01002152 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Jean Delvaref27def02011-03-26 10:45:01 +01002153 int nr_fans = f71882fg_nr_fans[sio_data->type];
2154 int nr_temps = f71882fg_nr_temps[sio_data->type];
2155 int err, i;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002156 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002157
Hans de Goedec13548c2009-01-07 16:37:27 +01002158 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
2159 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002160 return -ENOMEM;
2161
2162 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002163 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002164 data->temp_start =
2165 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002166 mutex_init(&data->update_lock);
2167 platform_set_drvdata(pdev, data);
2168
Hans de Goede3cc74752009-01-07 16:37:28 +01002169 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002170 if (start_reg & 0x04) {
2171 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
2172 err = -ENODEV;
2173 goto exit_free;
2174 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002175 if (!(start_reg & 0x03)) {
2176 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
2177 err = -ENODEV;
2178 goto exit_free;
2179 }
2180
Hans de Goede45fb3662007-07-13 14:34:19 +02002181 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002182 err = device_create_file(&pdev->dev, &dev_attr_name);
2183 if (err)
2184 goto exit_unregister_sysfs;
2185
Hans de Goedec13548c2009-01-07 16:37:27 +01002186 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002187 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002188 case f71858fg:
2189 data->temp_config =
2190 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2191 if (data->temp_config & 0x10)
2192 /* The f71858fg temperature alarms behave as
2193 the f8000 alarms in this mode */
2194 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002195 f8000_temp_attr,
2196 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002197 else
2198 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002199 f71858fg_temp_attr,
2200 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002201 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002202 case f8000:
2203 err = f71882fg_create_sysfs_files(pdev,
2204 f8000_temp_attr,
2205 ARRAY_SIZE(f8000_temp_attr));
2206 break;
2207 default:
2208 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002209 &fxxxx_temp_attr[0][0],
2210 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002211 }
2212 if (err)
2213 goto exit_unregister_sysfs;
2214
Hans de Goede4d538112011-05-25 20:43:32 +02002215 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002216 err = f71882fg_create_sysfs_files(pdev,
2217 &fxxxx_temp_beep_attr[0][0],
2218 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2219 * nr_temps);
2220 if (err)
2221 goto exit_unregister_sysfs;
2222 }
2223
Hans de Goede0bae6402011-03-09 20:57:10 +01002224 for (i = 0; i < F71882FG_MAX_INS; i++) {
2225 if (f71882fg_has_in[data->type][i]) {
2226 err = device_create_file(&pdev->dev,
2227 &fxxxx_in_attr[i].dev_attr);
2228 if (err)
2229 goto exit_unregister_sysfs;
2230 }
2231 }
2232 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002233 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002234 fxxxx_in1_alarm_attr,
2235 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002236 if (err)
2237 goto exit_unregister_sysfs;
2238 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002239 }
2240
Hans de Goede45fb3662007-07-13 14:34:19 +02002241 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002242 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002243 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002244 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002245 case f71869:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002246 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002247 data->auto_point_temp_signed = 1;
2248 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002249 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002250 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002251 case f71889a:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002252 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2253 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2254 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002255 /* Ensure banked pwm registers point to right bank */
2256 reg &= ~F71882FG_FAN_PROG_SEL;
2257 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002258 break;
2259 default:
2260 break;
2261 }
2262
Hans de Goede996cadb2009-06-15 18:39:51 +02002263 data->pwm_enable =
2264 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2265
2266 /* Sanity check the pwm settings */
2267 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002268 case f71858fg:
2269 err = 0;
2270 for (i = 0; i < nr_fans; i++)
2271 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2272 err = 1;
2273 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002274 case f71862fg:
2275 err = (data->pwm_enable & 0x15) != 0x15;
2276 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002277 case f8000:
2278 err = data->pwm_enable & 0x20;
2279 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002280 default:
2281 err = 0;
2282 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002283 }
2284 if (err) {
2285 dev_err(&pdev->dev,
2286 "Invalid (reserved) pwm settings: 0x%02x\n",
2287 (unsigned int)data->pwm_enable);
2288 err = -ENODEV;
2289 goto exit_unregister_sysfs;
2290 }
2291
Hans de Goedeb69b0392009-12-09 20:36:00 +01002292 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2293 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002294 if (err)
2295 goto exit_unregister_sysfs;
2296
Hans de Goede4d538112011-05-25 20:43:32 +02002297 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002298 err = f71882fg_create_sysfs_files(pdev,
2299 fxxxx_fan_beep_attr, nr_fans);
2300 if (err)
2301 goto exit_unregister_sysfs;
2302 }
2303
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002304 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002305 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002306 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002307 case f71869:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002308 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002309 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002310 case f71889a:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002311 for (i = 0; i < nr_fans; i++) {
2312 data->pwm_auto_point_mapping[i] =
2313 f71882fg_read8(data,
2314 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002315 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2316 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002317 break;
2318 }
2319 if (i != nr_fans) {
2320 dev_warn(&pdev->dev,
2321 "Auto pwm controlled by raw digital "
2322 "data, disabling pwm auto_point "
2323 "sysfs attributes\n");
2324 goto no_pwm_auto_point;
2325 }
2326 break;
2327 default:
2328 break;
2329 }
2330
2331 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002332 case f71808a:
2333 err = f71882fg_create_sysfs_files(pdev,
2334 &fxxxx_auto_pwm_attr[0][0],
2335 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2336 if (err)
2337 goto exit_unregister_sysfs;
2338 err = f71882fg_create_sysfs_files(pdev,
2339 f71808a_fan3_attr,
2340 ARRAY_SIZE(f71808a_fan3_attr));
2341 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002342 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002343 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002344 f71862fg_auto_pwm_attr,
2345 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002346 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002347 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002348 case f71869:
2349 err = f71882fg_create_sysfs_files(pdev,
2350 f71869_auto_pwm_attr,
2351 ARRAY_SIZE(f71869_auto_pwm_attr));
2352 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002353 case f8000:
2354 err = f71882fg_create_sysfs_files(pdev,
2355 f8000_fan_attr,
2356 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002357 if (err)
2358 goto exit_unregister_sysfs;
2359 err = f71882fg_create_sysfs_files(pdev,
2360 f8000_auto_pwm_attr,
2361 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002362 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002363 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002364 err = f71882fg_create_sysfs_files(pdev,
2365 &fxxxx_auto_pwm_attr[0][0],
2366 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002367 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002368 if (err)
2369 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002370
Hans de Goedee48a7f12011-03-09 20:57:13 +01002371no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002372 for (i = 0; i < nr_fans; i++)
2373 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2374 (data->pwm_enable & (1 << 2 * i)) ?
2375 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002376 }
2377
Tony Jones1beeffe2007-08-20 13:46:20 -07002378 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2379 if (IS_ERR(data->hwmon_dev)) {
2380 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002381 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002382 goto exit_unregister_sysfs;
2383 }
2384
2385 return 0;
2386
2387exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002388 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002389 return err; /* f71882fg_remove() also frees our data */
2390exit_free:
2391 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002392 return err;
2393}
2394
Hans de Goedec13548c2009-01-07 16:37:27 +01002395static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002396{
Hans de Goede45fb3662007-07-13 14:34:19 +02002397 struct f71882fg_data *data = platform_get_drvdata(pdev);
Jean Delvaref27def02011-03-26 10:45:01 +01002398 int nr_fans = f71882fg_nr_fans[data->type];
2399 int nr_temps = f71882fg_nr_temps[data->type];
2400 int i;
Hans de Goedefc16c562009-12-09 20:36:01 +01002401 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002402
Hans de Goedec13548c2009-01-07 16:37:27 +01002403 if (data->hwmon_dev)
2404 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002405
Hans de Goedec13548c2009-01-07 16:37:27 +01002406 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002407
Hans de Goedefc16c562009-12-09 20:36:01 +01002408 if (start_reg & 0x01) {
2409 switch (data->type) {
2410 case f71858fg:
2411 if (data->temp_config & 0x10)
2412 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002413 f8000_temp_attr,
2414 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002415 else
2416 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002417 f71858fg_temp_attr,
2418 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002419 break;
2420 case f8000:
2421 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002422 f8000_temp_attr,
2423 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002424 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002425 default:
2426 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002427 &fxxxx_temp_attr[0][0],
2428 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002429 }
Hans de Goede4d538112011-05-25 20:43:32 +02002430 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002431 f71882fg_remove_sysfs_files(pdev,
2432 &fxxxx_temp_beep_attr[0][0],
2433 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2434 }
2435
Hans de Goede0bae6402011-03-09 20:57:10 +01002436 for (i = 0; i < F71882FG_MAX_INS; i++) {
2437 if (f71882fg_has_in[data->type][i]) {
2438 device_remove_file(&pdev->dev,
2439 &fxxxx_in_attr[i].dev_attr);
2440 }
2441 }
2442 if (f71882fg_has_in1_alarm[data->type]) {
2443 f71882fg_remove_sysfs_files(pdev,
2444 fxxxx_in1_alarm_attr,
2445 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002446 }
2447 }
Hans de Goede498be962009-01-07 16:37:28 +01002448
Hans de Goedefc16c562009-12-09 20:36:01 +01002449 if (start_reg & 0x02) {
2450 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2451 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002452
Hans de Goede4d538112011-05-25 20:43:32 +02002453 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002454 f71882fg_remove_sysfs_files(pdev,
2455 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002456 }
Hans de Goede498be962009-01-07 16:37:28 +01002457
Hans de Goedefc16c562009-12-09 20:36:01 +01002458 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002459 case f71808a:
2460 f71882fg_remove_sysfs_files(pdev,
2461 &fxxxx_auto_pwm_attr[0][0],
2462 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2463 f71882fg_remove_sysfs_files(pdev,
2464 f71808a_fan3_attr,
2465 ARRAY_SIZE(f71808a_fan3_attr));
2466 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002467 case f71862fg:
2468 f71882fg_remove_sysfs_files(pdev,
2469 f71862fg_auto_pwm_attr,
2470 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2471 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002472 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002473 case f71869:
2474 f71882fg_remove_sysfs_files(pdev,
2475 f71869_auto_pwm_attr,
2476 ARRAY_SIZE(f71869_auto_pwm_attr));
2477 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002478 case f8000:
2479 f71882fg_remove_sysfs_files(pdev,
2480 f8000_fan_attr,
2481 ARRAY_SIZE(f8000_fan_attr));
2482 f71882fg_remove_sysfs_files(pdev,
2483 f8000_auto_pwm_attr,
2484 ARRAY_SIZE(f8000_auto_pwm_attr));
2485 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002486 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002487 f71882fg_remove_sysfs_files(pdev,
2488 &fxxxx_auto_pwm_attr[0][0],
2489 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2490 }
2491 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002492
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002493 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002494 kfree(data);
2495
2496 return 0;
2497}
2498
Hans de Goede498be962009-01-07 16:37:28 +01002499static int __init f71882fg_find(int sioaddr, unsigned short *address,
2500 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002501{
Hans de Goede45fb3662007-07-13 14:34:19 +02002502 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002503 int err = superio_enter(sioaddr);
2504 if (err)
2505 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002506
2507 devid = superio_inw(sioaddr, SIO_REG_MANID);
2508 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002509 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002510 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002511 goto exit;
2512 }
2513
Jean Delvare67b671b2007-12-06 23:13:42 +01002514 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002515 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002516 case SIO_F71808E_ID:
2517 sio_data->type = f71808e;
2518 break;
Hans de Goede629c58b2011-05-25 20:43:32 +02002519 case SIO_F71808A_ID:
2520 sio_data->type = f71808a;
2521 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002522 case SIO_F71858_ID:
2523 sio_data->type = f71858fg;
2524 break;
Hans de Goede498be962009-01-07 16:37:28 +01002525 case SIO_F71862_ID:
2526 sio_data->type = f71862fg;
2527 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002528 case SIO_F71869_ID:
2529 sio_data->type = f71869;
2530 break;
Hans de Goede498be962009-01-07 16:37:28 +01002531 case SIO_F71882_ID:
2532 sio_data->type = f71882fg;
2533 break;
Hans de Goede76698962009-12-09 20:36:01 +01002534 case SIO_F71889_ID:
2535 sio_data->type = f71889fg;
2536 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002537 case SIO_F71889E_ID:
2538 sio_data->type = f71889ed;
2539 break;
Hans de Goedea66c1082011-03-26 10:45:02 +01002540 case SIO_F71889A_ID:
2541 sio_data->type = f71889a;
2542 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002543 case SIO_F8000_ID:
2544 sio_data->type = f8000;
2545 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002546 case SIO_F81865_ID:
2547 sio_data->type = f81865f;
2548 break;
Hans de Goede498be962009-01-07 16:37:28 +01002549 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002550 pr_info("Unsupported Fintek device: %04x\n",
2551 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002552 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002553 goto exit;
2554 }
2555
Hans de Goede09475d32009-06-15 18:39:52 +02002556 if (sio_data->type == f71858fg)
2557 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2558 else
2559 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2560
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002561 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002562 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002563 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002564 goto exit;
2565 }
2566
2567 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002568 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002569 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002570 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002571 goto exit;
2572 }
2573 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2574
Hans de Goede45fb3662007-07-13 14:34:19 +02002575 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002576 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002577 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002578 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2579exit:
2580 superio_exit(sioaddr);
2581 return err;
2582}
2583
Hans de Goede498be962009-01-07 16:37:28 +01002584static int __init f71882fg_device_add(unsigned short address,
2585 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002586{
2587 struct resource res = {
2588 .start = address,
2589 .end = address + REGION_LENGTH - 1,
2590 .flags = IORESOURCE_IO,
2591 };
2592 int err;
2593
2594 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002595 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002596 return -ENOMEM;
2597
2598 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002599 err = acpi_check_resource_conflict(&res);
2600 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002601 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002602
Hans de Goede45fb3662007-07-13 14:34:19 +02002603 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002604 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002605 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002606 goto exit_device_put;
2607 }
2608
Hans de Goede498be962009-01-07 16:37:28 +01002609 err = platform_device_add_data(f71882fg_pdev, sio_data,
2610 sizeof(struct f71882fg_sio_data));
2611 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002612 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002613 goto exit_device_put;
2614 }
2615
Hans de Goede45fb3662007-07-13 14:34:19 +02002616 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002617 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002618 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002619 goto exit_device_put;
2620 }
2621
2622 return 0;
2623
2624exit_device_put:
2625 platform_device_put(f71882fg_pdev);
2626
2627 return err;
2628}
2629
2630static int __init f71882fg_init(void)
2631{
2632 int err = -ENODEV;
2633 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002634 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002635
Hans de Goede498be962009-01-07 16:37:28 +01002636 memset(&sio_data, 0, sizeof(sio_data));
2637
2638 if (f71882fg_find(0x2e, &address, &sio_data) &&
2639 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002640 goto exit;
2641
Hans de Goedec13548c2009-01-07 16:37:27 +01002642 err = platform_driver_register(&f71882fg_driver);
2643 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002644 goto exit;
2645
Hans de Goede498be962009-01-07 16:37:28 +01002646 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002647 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002648 goto exit_driver;
2649
2650 return 0;
2651
2652exit_driver:
2653 platform_driver_unregister(&f71882fg_driver);
2654exit:
2655 return err;
2656}
2657
2658static void __exit f71882fg_exit(void)
2659{
2660 platform_device_unregister(f71882fg_pdev);
2661 platform_driver_unregister(&f71882fg_driver);
2662}
2663
2664MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goede7958e3b2011-07-03 13:32:53 +02002665MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
Hans de Goede45fb3662007-07-13 14:34:19 +02002666MODULE_LICENSE("GPL");
2667
2668module_init(f71882fg_init);
2669module_exit(f71882fg_exit);