blob: 2d96ed2bf8edadb8647afe035ba2a531c53edace [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 Goede5da556e2011-07-03 13:32:53 +020055#define SIO_F71869A_ID 0x1007 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020056#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010057#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010058#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedea66c1082011-03-26 10:45:02 +010059#define SIO_F71889A_ID 0x1005 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010060#define SIO_F8000_ID 0x0581 /* Chipset ID */
Jean Delvare383586b2011-03-26 10:45:02 +010061#define SIO_F81865_ID 0x0704 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020062
63#define REGION_LENGTH 8
64#define ADDR_REG_OFFSET 5
65#define DATA_REG_OFFSET 6
66
Hans de Goede3cad4022011-03-09 20:57:14 +010067#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
68#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020069#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010070#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020071
72#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010073#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
74#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020075#define F71882FG_REG_FAN_STATUS 0x92
76#define F71882FG_REG_FAN_BEEP 0x93
77
Hans de Goede7567a042009-01-07 16:37:28 +010078#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
79#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
80#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020081#define F71882FG_REG_TEMP_STATUS 0x62
82#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020083#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010084#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020085#define F71882FG_REG_TEMP_TYPE 0x6B
86#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
87
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010088#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
89#define F71882FG_REG_PWM_TYPE 0x94
90#define F71882FG_REG_PWM_ENABLE 0x96
91
Hans de Goedebc274902009-01-07 16:37:29 +010092#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010093
Hans de Goede98f7ba12011-03-09 20:57:09 +010094#define F71882FG_REG_FAN_FAULT_T 0x9F
95#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010096#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010097
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010098#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
99#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
100#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
101
Hans de Goede45fb3662007-07-13 14:34:19 +0200102#define F71882FG_REG_START 0x01
103
Hans de Goede0bae6402011-03-09 20:57:10 +0100104#define F71882FG_MAX_INS 9
105
Hans de Goede45fb3662007-07-13 14:34:19 +0200106#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
107
Jean Delvare67b671b2007-12-06 23:13:42 +0100108static unsigned short force_id;
109module_param(force_id, ushort, 0);
110MODULE_PARM_DESC(force_id, "Override the detected device ID");
111
Hans de Goede5da556e2011-07-03 13:32:53 +0200112enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71869a, f71882fg,
113 f71889fg, f71889ed, f71889a, f8000, f81865f };
Hans de Goede498be962009-01-07 16:37:28 +0100114
115static const char *f71882fg_names[] = {
Hans de Goedee5e713c2011-03-10 08:54:02 +0100116 "f71808e",
Hans de Goede629c58b2011-05-25 20:43:32 +0200117 "f71808a",
Hans de Goede09475d32009-06-15 18:39:52 +0200118 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100119 "f71862fg",
Hans de Goedec11bb992011-03-09 20:57:15 +0100120 "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
Hans de Goede5da556e2011-07-03 13:32:53 +0200121 "f71869a",
Hans de Goede498be962009-01-07 16:37:28 +0100122 "f71882fg",
Jean Delvare5d7f77b2011-03-26 10:45:02 +0100123 "f71889fg", /* f81801u too, same id */
Hans de Goede3cad4022011-03-09 20:57:14 +0100124 "f71889ed",
Hans de Goedea66c1082011-03-26 10:45:02 +0100125 "f71889a",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100126 "f8000",
Jean Delvare383586b2011-03-26 10:45:02 +0100127 "f81865f",
Hans de Goede498be962009-01-07 16:37:28 +0100128};
129
Jean Delvare2740c602011-03-26 10:45:01 +0100130static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
131 [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
Hans de Goede629c58b2011-05-25 20:43:32 +0200132 [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
Jean Delvare2740c602011-03-26 10:45:01 +0100133 [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
134 [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
135 [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Hans de Goede5da556e2011-07-03 13:32:53 +0200136 [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Jean Delvare2740c602011-03-26 10:45:01 +0100137 [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
138 [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
139 [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Hans de Goedea66c1082011-03-26 10:45:02 +0100140 [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
Jean Delvare2740c602011-03-26 10:45:01 +0100141 [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
Jean Delvare383586b2011-03-26 10:45:02 +0100142 [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0 },
Hans de Goede0bae6402011-03-09 20:57:10 +0100143};
144
Jean Delvare2740c602011-03-26 10:45:01 +0100145static const char f71882fg_has_in1_alarm[] = {
146 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200147 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100148 [f71858fg] = 0,
149 [f71862fg] = 0,
150 [f71869] = 0,
Hans de Goede5da556e2011-07-03 13:32:53 +0200151 [f71869a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100152 [f71882fg] = 1,
153 [f71889fg] = 1,
154 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100155 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100156 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100157 [f81865f] = 1,
Hans de Goede0bae6402011-03-09 20:57:10 +0100158};
159
Hans de Goede4d538112011-05-25 20:43:32 +0200160static const char f71882fg_fan_has_beep[] = {
Jean Delvare2740c602011-03-26 10:45:01 +0100161 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200162 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100163 [f71858fg] = 0,
164 [f71862fg] = 1,
165 [f71869] = 1,
Hans de Goede5da556e2011-07-03 13:32:53 +0200166 [f71869a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100167 [f71882fg] = 1,
168 [f71889fg] = 1,
169 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100170 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100171 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100172 [f81865f] = 1,
Hans de Goede78aa4f72011-03-09 20:57:12 +0100173};
174
Jean Delvaref27def02011-03-26 10:45:01 +0100175static const char f71882fg_nr_fans[] = {
176 [f71808e] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200177 [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */
Jean Delvaref27def02011-03-26 10:45:01 +0100178 [f71858fg] = 3,
179 [f71862fg] = 3,
180 [f71869] = 3,
Hans de Goede5da556e2011-07-03 13:32:53 +0200181 [f71869a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100182 [f71882fg] = 4,
183 [f71889fg] = 3,
184 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100185 [f71889a] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200186 [f8000] = 3, /* +1 fan which is monitor only */
Jean Delvare383586b2011-03-26 10:45:02 +0100187 [f81865f] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100188};
189
Hans de Goede4d538112011-05-25 20:43:32 +0200190static const char f71882fg_temp_has_beep[] = {
191 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200192 [f71808a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200193 [f71858fg] = 0,
194 [f71862fg] = 1,
195 [f71869] = 1,
Hans de Goede5da556e2011-07-03 13:32:53 +0200196 [f71869a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200197 [f71882fg] = 1,
198 [f71889fg] = 1,
199 [f71889ed] = 1,
200 [f71889a] = 1,
201 [f8000] = 0,
202 [f81865f] = 1,
203};
204
Jean Delvaref27def02011-03-26 10:45:01 +0100205static const char f71882fg_nr_temps[] = {
206 [f71808e] = 2,
Hans de Goede629c58b2011-05-25 20:43:32 +0200207 [f71808a] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100208 [f71858fg] = 3,
209 [f71862fg] = 3,
210 [f71869] = 3,
Hans de Goede5da556e2011-07-03 13:32:53 +0200211 [f71869a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100212 [f71882fg] = 3,
213 [f71889fg] = 3,
214 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100215 [f71889a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100216 [f8000] = 3,
Jean Delvare383586b2011-03-26 10:45:02 +0100217 [f81865f] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100218};
219
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100220static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200221
222/* Super-I/O Function prototypes */
223static inline int superio_inb(int base, int reg);
224static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400225static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200226static inline void superio_select(int base, int ld);
227static inline void superio_exit(int base);
228
Hans de Goede498be962009-01-07 16:37:28 +0100229struct f71882fg_sio_data {
230 enum chips type;
231};
232
Hans de Goede45fb3662007-07-13 14:34:19 +0200233struct f71882fg_data {
234 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100235 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700236 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200237
238 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200239 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200240 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100241 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200242 unsigned long last_updated; /* In jiffies */
243 unsigned long last_limits; /* In jiffies */
244
245 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100246 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200247 u8 in1_max;
248 u8 in_status;
249 u8 in_beep;
250 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100251 u16 fan_target[4];
252 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200253 u8 fan_status;
254 u8 fan_beep;
Hans de Goedee5e713c2011-03-10 08:54:02 +0100255 /* Note: all models have max 3 temperature channels, but on some
Hans de Goede7567a042009-01-07 16:37:28 +0100256 they are addressed as 0-2 and on others as 1-3, so for coding
257 convenience we reserve space for 4 channels */
Hans de Goede09475d32009-06-15 18:39:52 +0200258 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100259 u8 temp_ovt[4];
260 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100261 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100262 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200263 u8 temp_status;
264 u8 temp_beep;
265 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200266 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100267 u8 pwm[4];
268 u8 pwm_enable;
269 u8 pwm_auto_point_hyst[2];
270 u8 pwm_auto_point_mapping[4];
271 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100272 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200273};
274
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100275/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200276static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
277 char *buf);
278static ssize_t show_in_max(struct device *dev, struct device_attribute
279 *devattr, char *buf);
280static ssize_t store_in_max(struct device *dev, struct device_attribute
281 *devattr, const char *buf, size_t count);
282static ssize_t show_in_beep(struct device *dev, struct device_attribute
283 *devattr, char *buf);
284static ssize_t store_in_beep(struct device *dev, struct device_attribute
285 *devattr, const char *buf, size_t count);
286static ssize_t show_in_alarm(struct device *dev, struct device_attribute
287 *devattr, char *buf);
288/* Sysfs Fan */
289static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
290 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100291static ssize_t show_fan_full_speed(struct device *dev,
292 struct device_attribute *devattr, char *buf);
293static ssize_t store_fan_full_speed(struct device *dev,
294 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200295static ssize_t show_fan_beep(struct device *dev, struct device_attribute
296 *devattr, char *buf);
297static ssize_t store_fan_beep(struct device *dev, struct device_attribute
298 *devattr, const char *buf, size_t count);
299static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
300 *devattr, char *buf);
301/* Sysfs Temp */
302static ssize_t show_temp(struct device *dev, struct device_attribute
303 *devattr, char *buf);
304static ssize_t show_temp_max(struct device *dev, struct device_attribute
305 *devattr, char *buf);
306static ssize_t store_temp_max(struct device *dev, struct device_attribute
307 *devattr, const char *buf, size_t count);
308static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
309 *devattr, char *buf);
310static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
311 *devattr, const char *buf, size_t count);
312static ssize_t show_temp_crit(struct device *dev, struct device_attribute
313 *devattr, char *buf);
314static ssize_t store_temp_crit(struct device *dev, struct device_attribute
315 *devattr, const char *buf, size_t count);
316static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
317 *devattr, char *buf);
318static ssize_t show_temp_type(struct device *dev, struct device_attribute
319 *devattr, char *buf);
320static ssize_t show_temp_beep(struct device *dev, struct device_attribute
321 *devattr, char *buf);
322static ssize_t store_temp_beep(struct device *dev, struct device_attribute
323 *devattr, const char *buf, size_t count);
324static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
325 *devattr, char *buf);
326static ssize_t show_temp_fault(struct device *dev, struct device_attribute
327 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100328/* PWM and Auto point control */
329static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
330 char *buf);
331static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
332 const char *buf, size_t count);
Hans de Goede629c58b2011-05-25 20:43:32 +0200333static ssize_t show_simple_pwm(struct device *dev,
334 struct device_attribute *devattr, char *buf);
335static ssize_t store_simple_pwm(struct device *dev,
336 struct device_attribute *devattr, const char *buf, size_t count);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100337static ssize_t show_pwm_enable(struct device *dev,
338 struct device_attribute *devattr, char *buf);
339static ssize_t store_pwm_enable(struct device *dev,
340 struct device_attribute *devattr, const char *buf, size_t count);
341static ssize_t show_pwm_interpolate(struct device *dev,
342 struct device_attribute *devattr, char *buf);
343static ssize_t store_pwm_interpolate(struct device *dev,
344 struct device_attribute *devattr, const char *buf, size_t count);
345static ssize_t show_pwm_auto_point_channel(struct device *dev,
346 struct device_attribute *devattr, char *buf);
347static ssize_t store_pwm_auto_point_channel(struct device *dev,
348 struct device_attribute *devattr, const char *buf, size_t count);
349static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
350 struct device_attribute *devattr, char *buf);
351static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
352 struct device_attribute *devattr, const char *buf, size_t count);
353static ssize_t show_pwm_auto_point_pwm(struct device *dev,
354 struct device_attribute *devattr, char *buf);
355static ssize_t store_pwm_auto_point_pwm(struct device *dev,
356 struct device_attribute *devattr, const char *buf, size_t count);
357static ssize_t show_pwm_auto_point_temp(struct device *dev,
358 struct device_attribute *devattr, char *buf);
359static ssize_t store_pwm_auto_point_temp(struct device *dev,
360 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200361/* Sysfs misc */
362static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
363 char *buf);
364
365static int __devinit f71882fg_probe(struct platform_device * pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100366static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200367
368static struct platform_driver f71882fg_driver = {
369 .driver = {
370 .owner = THIS_MODULE,
371 .name = DRVNAME,
372 },
373 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200374 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200375};
376
Hans de Goedec13548c2009-01-07 16:37:27 +0100377static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200378
Hans de Goede0bae6402011-03-09 20:57:10 +0100379/* Temp attr for the f71858fg, the f71858fg is special as it has its
380 temperature indexes start at 0 (the others start at 1) */
381static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200382 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
383 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
384 store_temp_max, 0, 0),
385 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
386 store_temp_max_hyst, 0, 0),
387 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
388 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
389 store_temp_crit, 0, 0),
390 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
391 0, 0),
392 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
393 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
394 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
395 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
396 store_temp_max, 0, 1),
397 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
398 store_temp_max_hyst, 0, 1),
399 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
400 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
401 store_temp_crit, 0, 1),
402 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
403 0, 1),
404 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200405 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
406 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
407 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
408 store_temp_max, 0, 2),
409 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
410 store_temp_max_hyst, 0, 2),
411 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
412 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
413 store_temp_crit, 0, 2),
414 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
415 0, 2),
416 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
417 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
418};
419
Hans de Goede0bae6402011-03-09 20:57:10 +0100420/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100421static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100422 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100423 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100424 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100425 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100426 store_temp_max_hyst, 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100427 /* Should really be temp1_max_alarm, but older versions did not handle
428 the max and crit alarms separately and lm_sensors v2 depends on the
429 presence of temp#_alarm files. The same goes for temp2/3 _alarm. */
430 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100431 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100432 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100433 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100434 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100435 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100436 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100437 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100438}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100439 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
440 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100441 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100442 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100443 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100444 /* Should be temp2_max_alarm, see temp1_alarm note */
445 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100446 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100447 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100448 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100449 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100450 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100451 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100452 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100453}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100454 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
455 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
456 store_temp_max, 0, 3),
457 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
458 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100459 /* Should be temp3_max_alarm, see temp1_alarm note */
460 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100461 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
462 store_temp_crit, 0, 3),
463 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
464 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100465 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100466 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100467 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100468} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200469
Hans de Goede78aa4f72011-03-09 20:57:12 +0100470/* Temp attr for models which can beep on temp alarm */
471static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
472 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
473 store_temp_beep, 0, 1),
474 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
475 store_temp_beep, 0, 5),
476}, {
477 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
478 store_temp_beep, 0, 2),
479 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
480 store_temp_beep, 0, 6),
481}, {
482 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
483 store_temp_beep, 0, 3),
484 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
485 store_temp_beep, 0, 7),
486} };
487
Hans de Goede0bae6402011-03-09 20:57:10 +0100488/* Temp attr for the f8000
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100489 Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
490 is used as hysteresis value to clear alarms
Hans de Goede66344aa2009-12-09 20:35:59 +0100491 Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100492 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100493static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100494 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
495 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
496 store_temp_crit, 0, 0),
497 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
498 store_temp_max, 0, 0),
499 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200500 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100501 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
502 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
503 store_temp_crit, 0, 1),
504 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
505 store_temp_max, 0, 1),
506 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200507 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100508 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
509 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
510 store_temp_crit, 0, 2),
511 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
512 store_temp_max, 0, 2),
513 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200514 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100515};
516
Hans de Goede0bae6402011-03-09 20:57:10 +0100517/* in attr for all models */
518static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
519 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
520 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
521 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
522 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
523 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
524 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
525 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
526 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
527 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
528};
529
530/* For models with in1 alarm capability */
531static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
532 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
533 0, 1),
534 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
535 0, 1),
536 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
537};
538
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100539/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100540static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100541 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100542 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
543 show_fan_full_speed,
544 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100545 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100546 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
547 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
548 store_pwm_enable, 0, 0),
549 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
550 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100551}, {
552 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
553 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
554 show_fan_full_speed,
555 store_fan_full_speed, 0, 1),
556 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100557 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
558 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
559 store_pwm_enable, 0, 1),
560 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
561 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100562}, {
563 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
564 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
565 show_fan_full_speed,
566 store_fan_full_speed, 0, 2),
567 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200568 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
569 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
570 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100571 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
572 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100573}, {
574 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
575 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
576 show_fan_full_speed,
577 store_fan_full_speed, 0, 3),
578 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
579 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
580 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
581 store_pwm_enable, 0, 3),
582 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
583 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
584} };
Hans de Goede498be962009-01-07 16:37:28 +0100585
Hans de Goede629c58b2011-05-25 20:43:32 +0200586/* Attr for the third fan of the f71808a, which only has manual pwm */
587static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
588 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
589 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
590 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
591 show_simple_pwm, store_simple_pwm, 0, 2),
592};
593
Hans de Goede66344aa2009-12-09 20:35:59 +0100594/* Attr for models which can beep on Fan alarm */
595static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100596 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
597 store_fan_beep, 0, 0),
598 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
599 store_fan_beep, 0, 1),
600 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
601 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100602 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
603 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100604};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100605
Hans de Goede66344aa2009-12-09 20:35:59 +0100606/* PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
Hans de Goede3cad4022011-03-09 20:57:14 +0100607 standard models */
Hans de Goede66344aa2009-12-09 20:35:59 +0100608static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[] = {
609 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
610 show_pwm_auto_point_channel,
611 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100612 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
613 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
614 1, 0),
615 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
616 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
617 4, 0),
618 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
619 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
620 0, 0),
621 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
622 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
623 3, 0),
624 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
625 show_pwm_auto_point_temp_hyst,
626 store_pwm_auto_point_temp_hyst,
627 0, 0),
628 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
629 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
630
Hans de Goede66344aa2009-12-09 20:35:59 +0100631 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
632 show_pwm_auto_point_channel,
633 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100634 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
636 1, 1),
637 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 4, 1),
640 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
642 0, 1),
643 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
645 3, 1),
646 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_temp_hyst,
648 store_pwm_auto_point_temp_hyst,
649 0, 1),
650 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
651 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede49010622009-01-07 16:37:30 +0100652
Hans de Goede66344aa2009-12-09 20:35:59 +0100653 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
654 show_pwm_auto_point_channel,
655 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100656 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
658 1, 2),
659 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
661 4, 2),
662 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
664 0, 2),
665 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
667 3, 2),
668 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_temp_hyst,
670 store_pwm_auto_point_temp_hyst,
671 0, 2),
672 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
673 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100674};
675
Hans de Goedee5e713c2011-03-10 08:54:02 +0100676/* PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
Hans de Goedec11bb992011-03-09 20:57:15 +0100677 pwm setting when the temperature is above the pwmX_auto_point1_temp can be
678 programmed instead of being hardcoded to 0xff */
679static struct sensor_device_attribute_2 f71869_auto_pwm_attr[] = {
680 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
681 show_pwm_auto_point_channel,
682 store_pwm_auto_point_channel, 0, 0),
683 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
684 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
685 0, 0),
686 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
687 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
688 1, 0),
689 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
690 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
691 4, 0),
692 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
693 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
694 0, 0),
695 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
697 3, 0),
698 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_temp_hyst,
700 store_pwm_auto_point_temp_hyst,
701 0, 0),
702 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
703 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
704
705 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
706 show_pwm_auto_point_channel,
707 store_pwm_auto_point_channel, 0, 1),
708 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
709 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
710 0, 1),
711 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
712 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
713 1, 1),
714 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
715 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
716 4, 1),
717 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
718 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
719 0, 1),
720 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
721 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
722 3, 1),
723 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
724 show_pwm_auto_point_temp_hyst,
725 store_pwm_auto_point_temp_hyst,
726 0, 1),
727 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
728 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
729
730 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
731 show_pwm_auto_point_channel,
732 store_pwm_auto_point_channel, 0, 2),
733 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
734 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
735 0, 2),
736 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
737 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
738 1, 2),
739 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
740 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
741 4, 2),
742 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
743 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
744 0, 2),
745 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
746 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
747 3, 2),
748 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
749 show_pwm_auto_point_temp_hyst,
750 store_pwm_auto_point_temp_hyst,
751 0, 2),
752 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
753 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
754};
755
Hans de Goede3cad4022011-03-09 20:57:14 +0100756/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100757static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100758 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
759 show_pwm_auto_point_channel,
760 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100761 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
762 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
763 0, 0),
764 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
766 1, 0),
767 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
769 2, 0),
770 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
771 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
772 3, 0),
773 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
774 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
775 4, 0),
776 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
777 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
778 0, 0),
779 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
780 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
781 1, 0),
782 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
783 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
784 2, 0),
785 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
787 3, 0),
788 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_temp_hyst,
790 store_pwm_auto_point_temp_hyst,
791 0, 0),
792 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
793 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
794 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
795 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
796 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
797 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100798}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100799 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
800 show_pwm_auto_point_channel,
801 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100802 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
803 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
804 0, 1),
805 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
807 1, 1),
808 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
810 2, 1),
811 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
813 3, 1),
814 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 4, 1),
817 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
819 0, 1),
820 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
822 1, 1),
823 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
825 2, 1),
826 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
828 3, 1),
829 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp_hyst,
831 store_pwm_auto_point_temp_hyst,
832 0, 1),
833 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
834 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
835 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
836 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
837 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
838 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100839}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100840 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
841 show_pwm_auto_point_channel,
842 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100843 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
844 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
845 0, 2),
846 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
847 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
848 1, 2),
849 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
851 2, 2),
852 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
854 3, 2),
855 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
857 4, 2),
858 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
860 0, 2),
861 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
863 1, 2),
864 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
866 2, 2),
867 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
869 3, 2),
870 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_temp_hyst,
872 store_pwm_auto_point_temp_hyst,
873 0, 2),
874 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
875 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
876 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
877 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
878 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
879 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100880}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100881 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
882 show_pwm_auto_point_channel,
883 store_pwm_auto_point_channel, 0, 3),
884 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
885 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
886 0, 3),
887 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
888 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
889 1, 3),
890 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
891 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
892 2, 3),
893 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
894 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
895 3, 3),
896 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
897 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
898 4, 3),
899 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
900 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
901 0, 3),
902 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
903 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
904 1, 3),
905 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
906 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
907 2, 3),
908 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
909 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
910 3, 3),
911 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
912 show_pwm_auto_point_temp_hyst,
913 store_pwm_auto_point_temp_hyst,
914 0, 3),
915 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
916 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
917 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
918 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
919 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
920 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100921} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200922
Hans de Goede66344aa2009-12-09 20:35:59 +0100923/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100924static struct sensor_device_attribute_2 f8000_fan_attr[] = {
925 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100926};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100927
Hans de Goede66344aa2009-12-09 20:35:59 +0100928/* PWM attr for the f8000, zones mapped to temp instead of to pwm!
929 Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
930 F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0 */
931static struct sensor_device_attribute_2 f8000_auto_pwm_attr[] = {
932 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
933 show_pwm_auto_point_channel,
934 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100935 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
936 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
937 0, 2),
938 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
939 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
940 1, 2),
941 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
942 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
943 2, 2),
944 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
945 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
946 3, 2),
947 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
948 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
949 4, 2),
950 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
951 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
952 0, 2),
953 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
954 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
955 1, 2),
956 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
957 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
958 2, 2),
959 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
960 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
961 3, 2),
962 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
963 show_pwm_auto_point_temp_hyst,
964 store_pwm_auto_point_temp_hyst,
965 0, 2),
966 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
967 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
968 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
969 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
970 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
971 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
972
Hans de Goede66344aa2009-12-09 20:35:59 +0100973 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
974 show_pwm_auto_point_channel,
975 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100976 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
977 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
978 0, 0),
979 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
980 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
981 1, 0),
982 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
983 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
984 2, 0),
985 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
986 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
987 3, 0),
988 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
989 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
990 4, 0),
991 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
992 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
993 0, 0),
994 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
995 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
996 1, 0),
997 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
998 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
999 2, 0),
1000 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
1001 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1002 3, 0),
1003 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1004 show_pwm_auto_point_temp_hyst,
1005 store_pwm_auto_point_temp_hyst,
1006 0, 0),
1007 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
1008 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
1009 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
1010 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
1011 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
1012 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
1013
Hans de Goede66344aa2009-12-09 20:35:59 +01001014 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
1015 show_pwm_auto_point_channel,
1016 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001017 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
1018 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1019 0, 1),
1020 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
1021 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1022 1, 1),
1023 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
1024 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1025 2, 1),
1026 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
1027 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1028 3, 1),
1029 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
1030 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1031 4, 1),
1032 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
1033 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1034 0, 1),
1035 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
1036 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1037 1, 1),
1038 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
1039 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1040 2, 1),
1041 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
1042 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1043 3, 1),
1044 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1045 show_pwm_auto_point_temp_hyst,
1046 store_pwm_auto_point_temp_hyst,
1047 0, 1),
1048 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
1049 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
1050 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
1051 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
1052 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
1053 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
1054};
Hans de Goede45fb3662007-07-13 14:34:19 +02001055
1056/* Super I/O functions */
1057static inline int superio_inb(int base, int reg)
1058{
1059 outb(reg, base);
1060 return inb(base + 1);
1061}
1062
1063static int superio_inw(int base, int reg)
1064{
1065 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001066 val = superio_inb(base, reg) << 8;
1067 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001068 return val;
1069}
1070
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001071static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +02001072{
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001073 /* Don't step on other drivers' I/O space by accident */
1074 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +00001075 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001076 return -EBUSY;
1077 }
1078
Hans de Goede45fb3662007-07-13 14:34:19 +02001079 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001080 outb(SIO_UNLOCK_KEY, base);
1081 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001082
1083 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001084}
1085
Giel van Schijndel162bb592010-05-27 19:58:40 +02001086static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001087{
1088 outb(SIO_REG_LDSEL, base);
1089 outb(ld, base + 1);
1090}
1091
1092static inline void superio_exit(int base)
1093{
1094 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001095 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001096}
1097
Hans de Goede2f650632009-01-07 16:37:31 +01001098static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001099{
1100 return reg ? (1500000 / reg) : 0;
1101}
1102
Hans de Goede2f650632009-01-07 16:37:31 +01001103static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001104{
1105 return fan ? (1500000 / fan) : 0;
1106}
1107
Hans de Goede45fb3662007-07-13 14:34:19 +02001108static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1109{
1110 u8 val;
1111
1112 outb(reg, data->addr + ADDR_REG_OFFSET);
1113 val = inb(data->addr + DATA_REG_OFFSET);
1114
1115 return val;
1116}
1117
1118static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1119{
1120 u16 val;
1121
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001122 val = f71882fg_read8(data, reg) << 8;
1123 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001124
1125 return val;
1126}
1127
1128static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1129{
1130 outb(reg, data->addr + ADDR_REG_OFFSET);
1131 outb(val, data->addr + DATA_REG_OFFSET);
1132}
1133
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001134static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1135{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001136 f71882fg_write8(data, reg, val >> 8);
1137 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001138}
1139
Hans de Goede09475d32009-06-15 18:39:52 +02001140static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1141{
1142 if (data->type == f71858fg)
1143 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1144 else
1145 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1146}
1147
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001148static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001149{
1150 struct f71882fg_data *data = dev_get_drvdata(dev);
Jean Delvaref27def02011-03-26 10:45:01 +01001151 int nr_fans = f71882fg_nr_fans[data->type];
1152 int nr_temps = f71882fg_nr_temps[data->type];
Hans de Goedee5e713c2011-03-10 08:54:02 +01001153 int nr, reg, point;
Hans de Goede45fb3662007-07-13 14:34:19 +02001154
1155 mutex_lock(&data->update_lock);
1156
1157 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001158 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001159 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001160 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001161 data->in1_max =
1162 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1163 data->in_beep =
1164 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1165 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001166
1167 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001168 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1169 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001170 data->temp_ovt[nr] = f71882fg_read8(data,
1171 F71882FG_REG_TEMP_OVT(nr));
1172 data->temp_high[nr] = f71882fg_read8(data,
1173 F71882FG_REG_TEMP_HIGH(nr));
1174 }
1175
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001176 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001177 data->temp_hyst[0] = f71882fg_read8(data,
1178 F71882FG_REG_TEMP_HYST(0));
1179 data->temp_hyst[1] = f71882fg_read8(data,
1180 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001181 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001182 /* All but the f71858fg / f8000 have this register */
1183 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001184 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001185 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001186 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1187 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1188 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001189
Hans de Goede4d538112011-05-25 20:43:32 +02001190 if (f71882fg_fan_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001191 data->fan_beep = f71882fg_read8(data,
1192 F71882FG_REG_FAN_BEEP);
Hans de Goede4d538112011-05-25 20:43:32 +02001193
1194 if (f71882fg_temp_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001195 data->temp_beep = f71882fg_read8(data,
1196 F71882FG_REG_TEMP_BEEP);
Hans de Goede78aa4f72011-03-09 20:57:12 +01001197
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001198 data->pwm_enable = f71882fg_read8(data,
1199 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001200 data->pwm_auto_point_hyst[0] =
1201 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1202 data->pwm_auto_point_hyst[1] =
1203 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1204
Hans de Goede498be962009-01-07 16:37:28 +01001205 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001206 data->pwm_auto_point_mapping[nr] =
1207 f71882fg_read8(data,
1208 F71882FG_REG_POINT_MAPPING(nr));
1209
Hans de Goedee5e713c2011-03-10 08:54:02 +01001210 switch (data->type) {
1211 default:
Hans de Goede498be962009-01-07 16:37:28 +01001212 for (point = 0; point < 5; point++) {
1213 data->pwm_auto_point_pwm[nr][point] =
1214 f71882fg_read8(data,
1215 F71882FG_REG_POINT_PWM
1216 (nr, point));
1217 }
1218 for (point = 0; point < 4; point++) {
1219 data->pwm_auto_point_temp[nr][point] =
1220 f71882fg_read8(data,
1221 F71882FG_REG_POINT_TEMP
1222 (nr, point));
1223 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001224 break;
1225 case f71808e:
1226 case f71869:
1227 data->pwm_auto_point_pwm[nr][0] =
1228 f71882fg_read8(data,
1229 F71882FG_REG_POINT_PWM(nr, 0));
1230 /* Fall through */
1231 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001232 data->pwm_auto_point_pwm[nr][1] =
1233 f71882fg_read8(data,
1234 F71882FG_REG_POINT_PWM
1235 (nr, 1));
1236 data->pwm_auto_point_pwm[nr][4] =
1237 f71882fg_read8(data,
1238 F71882FG_REG_POINT_PWM
1239 (nr, 4));
1240 data->pwm_auto_point_temp[nr][0] =
1241 f71882fg_read8(data,
1242 F71882FG_REG_POINT_TEMP
1243 (nr, 0));
1244 data->pwm_auto_point_temp[nr][3] =
1245 f71882fg_read8(data,
1246 F71882FG_REG_POINT_TEMP
1247 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001248 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001249 }
1250 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001251 data->last_limits = jiffies;
1252 }
1253
1254 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001255 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001256 data->temp_status = f71882fg_read8(data,
1257 F71882FG_REG_TEMP_STATUS);
1258 data->temp_diode_open = f71882fg_read8(data,
1259 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001260 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1261 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001262 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001263
1264 data->fan_status = f71882fg_read8(data,
1265 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001266 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001267 data->fan[nr] = f71882fg_read16(data,
1268 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001269 data->fan_target[nr] =
1270 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1271 data->fan_full_speed[nr] =
1272 f71882fg_read16(data,
1273 F71882FG_REG_FAN_FULL_SPEED(nr));
1274 data->pwm[nr] =
1275 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1276 }
Hans de Goede629c58b2011-05-25 20:43:32 +02001277 /* Some models have 1 more fan with limited capabilities */
1278 if (data->type == f71808a) {
1279 data->fan[2] = f71882fg_read16(data,
1280 F71882FG_REG_FAN(2));
1281 data->pwm[2] = f71882fg_read8(data,
1282 F71882FG_REG_PWM(2));
1283 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001284 if (data->type == f8000)
1285 data->fan[3] = f71882fg_read16(data,
1286 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001287
1288 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001289 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001290 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001291 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1292 if (f71882fg_has_in[data->type][nr])
1293 data->in[nr] = f71882fg_read8(data,
1294 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001295
1296 data->last_updated = jiffies;
1297 data->valid = 1;
1298 }
1299
1300 mutex_unlock(&data->update_lock);
1301
1302 return data;
1303}
1304
1305/* Sysfs Interface */
1306static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1307 char *buf)
1308{
1309 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001310 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001311 int speed = fan_from_reg(data->fan[nr]);
1312
1313 if (speed == FAN_MIN_DETECT)
1314 speed = 0;
1315
1316 return sprintf(buf, "%d\n", speed);
1317}
1318
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001319static ssize_t show_fan_full_speed(struct device *dev,
1320 struct device_attribute *devattr, char *buf)
1321{
1322 struct f71882fg_data *data = f71882fg_update_device(dev);
1323 int nr = to_sensor_dev_attr_2(devattr)->index;
1324 int speed = fan_from_reg(data->fan_full_speed[nr]);
1325 return sprintf(buf, "%d\n", speed);
1326}
1327
1328static ssize_t store_fan_full_speed(struct device *dev,
1329 struct device_attribute *devattr,
1330 const char *buf, size_t count)
1331{
1332 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001333 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1334 long val;
1335
1336 err = strict_strtol(buf, 10, &val);
1337 if (err)
1338 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001339
1340 val = SENSORS_LIMIT(val, 23, 1500000);
1341 val = fan_to_reg(val);
1342
1343 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001344 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1345 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001346 mutex_unlock(&data->update_lock);
1347
1348 return count;
1349}
1350
Hans de Goede45fb3662007-07-13 14:34:19 +02001351static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1352 *devattr, char *buf)
1353{
1354 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001355 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001356
1357 if (data->fan_beep & (1 << nr))
1358 return sprintf(buf, "1\n");
1359 else
1360 return sprintf(buf, "0\n");
1361}
1362
1363static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1364 *devattr, const char *buf, size_t count)
1365{
1366 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001367 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1368 unsigned long val;
1369
1370 err = strict_strtoul(buf, 10, &val);
1371 if (err)
1372 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001373
1374 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001375 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001376 if (val)
1377 data->fan_beep |= 1 << nr;
1378 else
1379 data->fan_beep &= ~(1 << nr);
1380
1381 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1382 mutex_unlock(&data->update_lock);
1383
1384 return count;
1385}
1386
1387static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1388 *devattr, char *buf)
1389{
1390 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001391 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001392
1393 if (data->fan_status & (1 << nr))
1394 return sprintf(buf, "1\n");
1395 else
1396 return sprintf(buf, "0\n");
1397}
1398
1399static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1400 char *buf)
1401{
1402 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001403 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001404
1405 return sprintf(buf, "%d\n", data->in[nr] * 8);
1406}
1407
1408static ssize_t show_in_max(struct device *dev, struct device_attribute
1409 *devattr, char *buf)
1410{
1411 struct f71882fg_data *data = f71882fg_update_device(dev);
1412
1413 return sprintf(buf, "%d\n", data->in1_max * 8);
1414}
1415
1416static ssize_t store_in_max(struct device *dev, struct device_attribute
1417 *devattr, const char *buf, size_t count)
1418{
1419 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001420 int err;
1421 long val;
1422
1423 err = strict_strtol(buf, 10, &val);
1424 if (err)
1425 return err;
1426
1427 val /= 8;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001428 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001429
1430 mutex_lock(&data->update_lock);
1431 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1432 data->in1_max = val;
1433 mutex_unlock(&data->update_lock);
1434
1435 return count;
1436}
1437
1438static ssize_t show_in_beep(struct device *dev, struct device_attribute
1439 *devattr, char *buf)
1440{
1441 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001442 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001443
1444 if (data->in_beep & (1 << nr))
1445 return sprintf(buf, "1\n");
1446 else
1447 return sprintf(buf, "0\n");
1448}
1449
1450static ssize_t store_in_beep(struct device *dev, struct device_attribute
1451 *devattr, const char *buf, size_t count)
1452{
1453 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001454 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1455 unsigned long val;
1456
1457 err = strict_strtoul(buf, 10, &val);
1458 if (err)
1459 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001460
1461 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001462 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001463 if (val)
1464 data->in_beep |= 1 << nr;
1465 else
1466 data->in_beep &= ~(1 << nr);
1467
1468 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1469 mutex_unlock(&data->update_lock);
1470
1471 return count;
1472}
1473
1474static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1475 *devattr, char *buf)
1476{
1477 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001478 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001479
1480 if (data->in_status & (1 << nr))
1481 return sprintf(buf, "1\n");
1482 else
1483 return sprintf(buf, "0\n");
1484}
1485
1486static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1487 char *buf)
1488{
1489 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001490 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001491 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001492
Hans de Goede09475d32009-06-15 18:39:52 +02001493 if (data->type == f71858fg) {
1494 /* TEMP_TABLE_SEL 1 or 3 ? */
1495 if (data->temp_config & 1) {
1496 sign = data->temp[nr] & 0x0001;
1497 temp = (data->temp[nr] >> 5) & 0x7ff;
1498 } else {
1499 sign = data->temp[nr] & 0x8000;
1500 temp = (data->temp[nr] >> 5) & 0x3ff;
1501 }
1502 temp *= 125;
1503 if (sign)
1504 temp -= 128000;
1505 } else
1506 temp = data->temp[nr] * 1000;
1507
1508 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001509}
1510
1511static ssize_t show_temp_max(struct device *dev, struct device_attribute
1512 *devattr, char *buf)
1513{
1514 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001515 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001516
1517 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1518}
1519
1520static ssize_t store_temp_max(struct device *dev, struct device_attribute
1521 *devattr, const char *buf, size_t count)
1522{
1523 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001524 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1525 long val;
1526
1527 err = strict_strtol(buf, 10, &val);
1528 if (err)
1529 return err;
1530
1531 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001532 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001533
1534 mutex_lock(&data->update_lock);
1535 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1536 data->temp_high[nr] = val;
1537 mutex_unlock(&data->update_lock);
1538
1539 return count;
1540}
1541
1542static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1543 *devattr, char *buf)
1544{
1545 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001546 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001547 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001548
Hans de Goedece0bfa52009-01-07 16:37:28 +01001549 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001550 if (nr & 1)
1551 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1552 else
1553 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1554 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001555 mutex_unlock(&data->update_lock);
1556
1557 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001558}
1559
1560static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1561 *devattr, const char *buf, size_t count)
1562{
1563 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001564 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001565 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001566 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001567 long val;
1568
1569 err = strict_strtol(buf, 10, &val);
1570 if (err)
1571 return err;
1572
1573 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001574
1575 mutex_lock(&data->update_lock);
1576
1577 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001578 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
1579 val = SENSORS_LIMIT(val, data->temp_high[nr] - 15,
1580 data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001581 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001582
1583 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001584 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1585 if (nr & 1)
1586 reg = (reg & 0x0f) | (val << 4);
1587 else
1588 reg = (reg & 0xf0) | val;
1589 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1590 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001591
Hans de Goede45fb3662007-07-13 14:34:19 +02001592 mutex_unlock(&data->update_lock);
1593 return ret;
1594}
1595
1596static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1597 *devattr, char *buf)
1598{
1599 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001600 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001601
1602 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1603}
1604
1605static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1606 *devattr, const char *buf, size_t count)
1607{
1608 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001609 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1610 long val;
1611
1612 err = strict_strtol(buf, 10, &val);
1613 if (err)
1614 return err;
1615
1616 val /= 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001617 val = SENSORS_LIMIT(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001618
1619 mutex_lock(&data->update_lock);
1620 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1621 data->temp_ovt[nr] = val;
1622 mutex_unlock(&data->update_lock);
1623
1624 return count;
1625}
1626
1627static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1628 *devattr, char *buf)
1629{
1630 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001631 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001632 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001633
Hans de Goedece0bfa52009-01-07 16:37:28 +01001634 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001635 if (nr & 1)
1636 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1637 else
1638 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1639 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001640 mutex_unlock(&data->update_lock);
1641
1642 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001643}
1644
1645static ssize_t show_temp_type(struct device *dev, struct device_attribute
1646 *devattr, char *buf)
1647{
1648 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001649 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001650
1651 return sprintf(buf, "%d\n", data->temp_type[nr]);
1652}
1653
1654static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1655 *devattr, char *buf)
1656{
1657 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001658 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001659
Hans de Goede7567a042009-01-07 16:37:28 +01001660 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001661 return sprintf(buf, "1\n");
1662 else
1663 return sprintf(buf, "0\n");
1664}
1665
1666static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1667 *devattr, const char *buf, size_t count)
1668{
1669 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001670 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1671 unsigned long val;
1672
1673 err = strict_strtoul(buf, 10, &val);
1674 if (err)
1675 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001676
1677 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001678 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001679 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001680 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001681 else
Hans de Goede7567a042009-01-07 16:37:28 +01001682 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001683
1684 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1685 mutex_unlock(&data->update_lock);
1686
1687 return count;
1688}
1689
1690static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1691 *devattr, char *buf)
1692{
1693 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001694 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001695
Hans de Goede7567a042009-01-07 16:37:28 +01001696 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001697 return sprintf(buf, "1\n");
1698 else
1699 return sprintf(buf, "0\n");
1700}
1701
1702static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1703 *devattr, char *buf)
1704{
1705 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001706 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001707
Hans de Goede7567a042009-01-07 16:37:28 +01001708 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001709 return sprintf(buf, "1\n");
1710 else
1711 return sprintf(buf, "0\n");
1712}
1713
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001714static ssize_t show_pwm(struct device *dev,
1715 struct device_attribute *devattr, char *buf)
1716{
1717 struct f71882fg_data *data = f71882fg_update_device(dev);
1718 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001719 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001720 if (data->pwm_enable & (1 << (2 * nr)))
1721 /* PWM mode */
1722 val = data->pwm[nr];
1723 else {
1724 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001725 val = 255 * fan_from_reg(data->fan_target[nr])
1726 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001727 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001728 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001729 return sprintf(buf, "%d\n", val);
1730}
1731
1732static ssize_t store_pwm(struct device *dev,
1733 struct device_attribute *devattr, const char *buf,
1734 size_t count)
1735{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001736 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001737 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1738 long val;
1739
1740 err = strict_strtol(buf, 10, &val);
1741 if (err)
1742 return err;
1743
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001744 val = SENSORS_LIMIT(val, 0, 255);
1745
1746 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001747 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001748 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1749 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1750 count = -EROFS;
1751 goto leave;
1752 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001753 if (data->pwm_enable & (1 << (2 * nr))) {
1754 /* PWM mode */
1755 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1756 data->pwm[nr] = val;
1757 } else {
1758 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001759 int target, full_speed;
1760 full_speed = f71882fg_read16(data,
1761 F71882FG_REG_FAN_FULL_SPEED(nr));
1762 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1763 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1764 data->fan_target[nr] = target;
1765 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001766 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001767leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001768 mutex_unlock(&data->update_lock);
1769
1770 return count;
1771}
1772
Hans de Goede629c58b2011-05-25 20:43:32 +02001773static ssize_t show_simple_pwm(struct device *dev,
1774 struct device_attribute *devattr, char *buf)
1775{
1776 struct f71882fg_data *data = f71882fg_update_device(dev);
1777 int val, nr = to_sensor_dev_attr_2(devattr)->index;
1778
1779 val = data->pwm[nr];
1780 return sprintf(buf, "%d\n", val);
1781}
1782
1783static ssize_t store_simple_pwm(struct device *dev,
1784 struct device_attribute *devattr,
1785 const char *buf, size_t count)
1786{
1787 struct f71882fg_data *data = dev_get_drvdata(dev);
1788 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1789 long val;
1790
1791 err = strict_strtol(buf, 10, &val);
1792 if (err)
1793 return err;
1794
1795 val = SENSORS_LIMIT(val, 0, 255);
1796
1797 mutex_lock(&data->update_lock);
1798 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1799 data->pwm[nr] = val;
1800 mutex_unlock(&data->update_lock);
1801
1802 return count;
1803}
1804
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001805static ssize_t show_pwm_enable(struct device *dev,
1806 struct device_attribute *devattr, char *buf)
1807{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001808 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001809 struct f71882fg_data *data = f71882fg_update_device(dev);
1810 int nr = to_sensor_dev_attr_2(devattr)->index;
1811
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001812 switch ((data->pwm_enable >> 2 * nr) & 3) {
1813 case 0:
1814 case 1:
1815 result = 2; /* Normal auto mode */
1816 break;
1817 case 2:
1818 result = 1; /* Manual mode */
1819 break;
1820 case 3:
1821 if (data->type == f8000)
1822 result = 3; /* Thermostat mode */
1823 else
1824 result = 1; /* Manual mode */
1825 break;
1826 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001827
1828 return sprintf(buf, "%d\n", result);
1829}
1830
1831static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1832 *devattr, const char *buf, size_t count)
1833{
1834 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001835 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1836 long val;
1837
1838 err = strict_strtol(buf, 10, &val);
1839 if (err)
1840 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001841
Hans de Goede3fc78382009-06-15 18:39:50 +02001842 /* Special case for F8000 pwm channel 3 which only does auto mode */
1843 if (data->type == f8000 && nr == 2 && val != 2)
1844 return -EINVAL;
1845
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001846 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001847 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001848 /* Special case for F8000 auto PWM mode / Thermostat mode */
1849 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1850 switch (val) {
1851 case 2:
1852 data->pwm_enable &= ~(2 << (2 * nr));
1853 break; /* Normal auto mode */
1854 case 3:
1855 data->pwm_enable |= 2 << (2 * nr);
1856 break; /* Thermostat mode */
1857 default:
1858 count = -EINVAL;
1859 goto leave;
1860 }
1861 } else {
1862 switch (val) {
1863 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001864 /* The f71858fg does not support manual RPM mode */
1865 if (data->type == f71858fg &&
1866 ((data->pwm_enable >> (2 * nr)) & 1)) {
1867 count = -EINVAL;
1868 goto leave;
1869 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001870 data->pwm_enable |= 2 << (2 * nr);
1871 break; /* Manual */
1872 case 2:
1873 data->pwm_enable &= ~(2 << (2 * nr));
1874 break; /* Normal auto mode */
1875 default:
1876 count = -EINVAL;
1877 goto leave;
1878 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001879 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001880 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001881leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001882 mutex_unlock(&data->update_lock);
1883
1884 return count;
1885}
1886
1887static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1888 struct device_attribute *devattr,
1889 char *buf)
1890{
1891 int result;
1892 struct f71882fg_data *data = f71882fg_update_device(dev);
1893 int pwm = to_sensor_dev_attr_2(devattr)->index;
1894 int point = to_sensor_dev_attr_2(devattr)->nr;
1895
Hans de Goedece0bfa52009-01-07 16:37:28 +01001896 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001897 if (data->pwm_enable & (1 << (2 * pwm))) {
1898 /* PWM mode */
1899 result = data->pwm_auto_point_pwm[pwm][point];
1900 } else {
1901 /* RPM mode */
1902 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1903 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001904 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001905
1906 return sprintf(buf, "%d\n", result);
1907}
1908
1909static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1910 struct device_attribute *devattr,
1911 const char *buf, size_t count)
1912{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001913 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001914 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001915 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001916 long val;
1917
1918 err = strict_strtol(buf, 10, &val);
1919 if (err)
1920 return err;
1921
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001922 val = SENSORS_LIMIT(val, 0, 255);
1923
1924 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001925 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001926 if (data->pwm_enable & (1 << (2 * pwm))) {
1927 /* PWM mode */
1928 } else {
1929 /* RPM mode */
1930 if (val < 29) /* Prevent negative numbers */
1931 val = 255;
1932 else
1933 val = (255 - val) * 32 / val;
1934 }
1935 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1936 data->pwm_auto_point_pwm[pwm][point] = val;
1937 mutex_unlock(&data->update_lock);
1938
1939 return count;
1940}
1941
1942static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1943 struct device_attribute *devattr,
1944 char *buf)
1945{
1946 int result = 0;
1947 struct f71882fg_data *data = f71882fg_update_device(dev);
1948 int nr = to_sensor_dev_attr_2(devattr)->index;
1949 int point = to_sensor_dev_attr_2(devattr)->nr;
1950
1951 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001952 if (nr & 1)
1953 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1954 else
1955 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001956 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1957 mutex_unlock(&data->update_lock);
1958
1959 return sprintf(buf, "%d\n", result);
1960}
1961
1962static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1963 struct device_attribute *devattr,
1964 const char *buf, size_t count)
1965{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001966 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001967 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001968 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001969 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001970 long val;
1971
1972 err = strict_strtol(buf, 10, &val);
1973 if (err)
1974 return err;
1975
1976 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001977
1978 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001979 data->pwm_auto_point_temp[nr][point] =
1980 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001981 val = SENSORS_LIMIT(val, data->pwm_auto_point_temp[nr][point] - 15,
1982 data->pwm_auto_point_temp[nr][point]);
1983 val = data->pwm_auto_point_temp[nr][point] - val;
1984
Hans de Goedebc274902009-01-07 16:37:29 +01001985 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
1986 if (nr & 1)
1987 reg = (reg & 0x0f) | (val << 4);
1988 else
1989 reg = (reg & 0xf0) | val;
1990
1991 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
1992 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001993 mutex_unlock(&data->update_lock);
1994
1995 return count;
1996}
1997
1998static ssize_t show_pwm_interpolate(struct device *dev,
1999 struct device_attribute *devattr, char *buf)
2000{
2001 int result;
2002 struct f71882fg_data *data = f71882fg_update_device(dev);
2003 int nr = to_sensor_dev_attr_2(devattr)->index;
2004
2005 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
2006
2007 return sprintf(buf, "%d\n", result);
2008}
2009
2010static ssize_t store_pwm_interpolate(struct device *dev,
2011 struct device_attribute *devattr,
2012 const char *buf, size_t count)
2013{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002014 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002015 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2016 unsigned long val;
2017
2018 err = strict_strtoul(buf, 10, &val);
2019 if (err)
2020 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01002021
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002022 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002023 data->pwm_auto_point_mapping[nr] =
2024 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002025 if (val)
2026 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
2027 else
2028 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
2029 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2030 data->pwm_auto_point_mapping[nr] = val;
2031 mutex_unlock(&data->update_lock);
2032
2033 return count;
2034}
2035
2036static ssize_t show_pwm_auto_point_channel(struct device *dev,
2037 struct device_attribute *devattr,
2038 char *buf)
2039{
2040 int result;
2041 struct f71882fg_data *data = f71882fg_update_device(dev);
2042 int nr = to_sensor_dev_attr_2(devattr)->index;
2043
Hans de Goede09475d32009-06-15 18:39:52 +02002044 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
2045 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002046
2047 return sprintf(buf, "%d\n", result);
2048}
2049
2050static ssize_t store_pwm_auto_point_channel(struct device *dev,
2051 struct device_attribute *devattr,
2052 const char *buf, size_t count)
2053{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002054 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002055 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2056 long val;
2057
2058 err = strict_strtol(buf, 10, &val);
2059 if (err)
2060 return err;
Hans de Goede30453012009-01-07 16:37:30 +01002061
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002062 switch (val) {
2063 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01002064 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002065 break;
2066 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01002067 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002068 break;
2069 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01002070 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002071 break;
2072 default:
2073 return -EINVAL;
2074 }
Hans de Goede09475d32009-06-15 18:39:52 +02002075 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002076 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002077 data->pwm_auto_point_mapping[nr] =
2078 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002079 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
2080 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2081 data->pwm_auto_point_mapping[nr] = val;
2082 mutex_unlock(&data->update_lock);
2083
2084 return count;
2085}
2086
2087static ssize_t show_pwm_auto_point_temp(struct device *dev,
2088 struct device_attribute *devattr,
2089 char *buf)
2090{
2091 int result;
2092 struct f71882fg_data *data = f71882fg_update_device(dev);
2093 int pwm = to_sensor_dev_attr_2(devattr)->index;
2094 int point = to_sensor_dev_attr_2(devattr)->nr;
2095
2096 result = data->pwm_auto_point_temp[pwm][point];
2097 return sprintf(buf, "%d\n", 1000 * result);
2098}
2099
2100static ssize_t store_pwm_auto_point_temp(struct device *dev,
2101 struct device_attribute *devattr,
2102 const char *buf, size_t count)
2103{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002104 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002105 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002106 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002107 long val;
2108
2109 err = strict_strtol(buf, 10, &val);
2110 if (err)
2111 return err;
2112
2113 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01002114
Hans de Goede98f7ba12011-03-09 20:57:09 +01002115 if (data->auto_point_temp_signed)
Hans de Goede76698962009-12-09 20:36:01 +01002116 val = SENSORS_LIMIT(val, -128, 127);
2117 else
2118 val = SENSORS_LIMIT(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002119
2120 mutex_lock(&data->update_lock);
2121 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2122 data->pwm_auto_point_temp[pwm][point] = val;
2123 mutex_unlock(&data->update_lock);
2124
2125 return count;
2126}
2127
Hans de Goede45fb3662007-07-13 14:34:19 +02002128static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2129 char *buf)
2130{
Hans de Goede498be962009-01-07 16:37:28 +01002131 struct f71882fg_data *data = dev_get_drvdata(dev);
2132 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002133}
2134
Hans de Goedec13548c2009-01-07 16:37:27 +01002135static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev,
2136 struct sensor_device_attribute_2 *attr, int count)
2137{
2138 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002139
Hans de Goedec13548c2009-01-07 16:37:27 +01002140 for (i = 0; i < count; i++) {
2141 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2142 if (err)
2143 return err;
2144 }
2145 return 0;
2146}
2147
Hans de Goedefc16c562009-12-09 20:36:01 +01002148static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2149 struct sensor_device_attribute_2 *attr, int count)
2150{
2151 int i;
2152
2153 for (i = 0; i < count; i++)
2154 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2155}
2156
Hans de Goedec13548c2009-01-07 16:37:27 +01002157static int __devinit f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002158{
2159 struct f71882fg_data *data;
Hans de Goede498be962009-01-07 16:37:28 +01002160 struct f71882fg_sio_data *sio_data = pdev->dev.platform_data;
Jean Delvaref27def02011-03-26 10:45:01 +01002161 int nr_fans = f71882fg_nr_fans[sio_data->type];
2162 int nr_temps = f71882fg_nr_temps[sio_data->type];
2163 int err, i;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002164 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002165
Hans de Goedec13548c2009-01-07 16:37:27 +01002166 data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
2167 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002168 return -ENOMEM;
2169
2170 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002171 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002172 data->temp_start =
2173 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002174 mutex_init(&data->update_lock);
2175 platform_set_drvdata(pdev, data);
2176
Hans de Goede3cc74752009-01-07 16:37:28 +01002177 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002178 if (start_reg & 0x04) {
2179 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
2180 err = -ENODEV;
2181 goto exit_free;
2182 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002183 if (!(start_reg & 0x03)) {
2184 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
2185 err = -ENODEV;
2186 goto exit_free;
2187 }
2188
Hans de Goede45fb3662007-07-13 14:34:19 +02002189 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002190 err = device_create_file(&pdev->dev, &dev_attr_name);
2191 if (err)
2192 goto exit_unregister_sysfs;
2193
Hans de Goedec13548c2009-01-07 16:37:27 +01002194 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002195 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002196 case f71858fg:
2197 data->temp_config =
2198 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2199 if (data->temp_config & 0x10)
2200 /* The f71858fg temperature alarms behave as
2201 the f8000 alarms in this mode */
2202 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002203 f8000_temp_attr,
2204 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002205 else
2206 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002207 f71858fg_temp_attr,
2208 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002209 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002210 case f8000:
2211 err = f71882fg_create_sysfs_files(pdev,
2212 f8000_temp_attr,
2213 ARRAY_SIZE(f8000_temp_attr));
2214 break;
2215 default:
2216 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002217 &fxxxx_temp_attr[0][0],
2218 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002219 }
2220 if (err)
2221 goto exit_unregister_sysfs;
2222
Hans de Goede4d538112011-05-25 20:43:32 +02002223 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002224 err = f71882fg_create_sysfs_files(pdev,
2225 &fxxxx_temp_beep_attr[0][0],
2226 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2227 * nr_temps);
2228 if (err)
2229 goto exit_unregister_sysfs;
2230 }
2231
Hans de Goede0bae6402011-03-09 20:57:10 +01002232 for (i = 0; i < F71882FG_MAX_INS; i++) {
2233 if (f71882fg_has_in[data->type][i]) {
2234 err = device_create_file(&pdev->dev,
2235 &fxxxx_in_attr[i].dev_attr);
2236 if (err)
2237 goto exit_unregister_sysfs;
2238 }
2239 }
2240 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002241 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002242 fxxxx_in1_alarm_attr,
2243 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002244 if (err)
2245 goto exit_unregister_sysfs;
2246 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002247 }
2248
Hans de Goede45fb3662007-07-13 14:34:19 +02002249 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002250 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002251 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002252 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002253 case f71869:
Hans de Goede5da556e2011-07-03 13:32:53 +02002254 case f71869a:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002255 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002256 data->auto_point_temp_signed = 1;
2257 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002258 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002259 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002260 case f71889a:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002261 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2262 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2263 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002264 /* Ensure banked pwm registers point to right bank */
2265 reg &= ~F71882FG_FAN_PROG_SEL;
2266 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002267 break;
2268 default:
2269 break;
2270 }
2271
Hans de Goede996cadb2009-06-15 18:39:51 +02002272 data->pwm_enable =
2273 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2274
2275 /* Sanity check the pwm settings */
2276 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002277 case f71858fg:
2278 err = 0;
2279 for (i = 0; i < nr_fans; i++)
2280 if (((data->pwm_enable >> (i * 2)) & 3) == 3)
2281 err = 1;
2282 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002283 case f71862fg:
2284 err = (data->pwm_enable & 0x15) != 0x15;
2285 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002286 case f8000:
2287 err = data->pwm_enable & 0x20;
2288 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002289 default:
2290 err = 0;
2291 break;
Hans de Goede996cadb2009-06-15 18:39:51 +02002292 }
2293 if (err) {
2294 dev_err(&pdev->dev,
2295 "Invalid (reserved) pwm settings: 0x%02x\n",
2296 (unsigned int)data->pwm_enable);
2297 err = -ENODEV;
2298 goto exit_unregister_sysfs;
2299 }
2300
Hans de Goedeb69b0392009-12-09 20:36:00 +01002301 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2302 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002303 if (err)
2304 goto exit_unregister_sysfs;
2305
Hans de Goede4d538112011-05-25 20:43:32 +02002306 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedeb69b0392009-12-09 20:36:00 +01002307 err = f71882fg_create_sysfs_files(pdev,
2308 fxxxx_fan_beep_attr, nr_fans);
2309 if (err)
2310 goto exit_unregister_sysfs;
2311 }
2312
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002313 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002314 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002315 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002316 case f71869:
Hans de Goede5da556e2011-07-03 13:32:53 +02002317 case f71869a:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002318 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002319 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002320 case f71889a:
Hans de Goedee48a7f12011-03-09 20:57:13 +01002321 for (i = 0; i < nr_fans; i++) {
2322 data->pwm_auto_point_mapping[i] =
2323 f71882fg_read8(data,
2324 F71882FG_REG_POINT_MAPPING(i));
Hans de Goede3cad4022011-03-09 20:57:14 +01002325 if ((data->pwm_auto_point_mapping[i] & 0x80) ||
2326 (data->pwm_auto_point_mapping[i] & 3) == 0)
Hans de Goedee48a7f12011-03-09 20:57:13 +01002327 break;
2328 }
2329 if (i != nr_fans) {
2330 dev_warn(&pdev->dev,
2331 "Auto pwm controlled by raw digital "
2332 "data, disabling pwm auto_point "
2333 "sysfs attributes\n");
2334 goto no_pwm_auto_point;
2335 }
2336 break;
2337 default:
2338 break;
2339 }
2340
2341 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002342 case f71808a:
2343 err = f71882fg_create_sysfs_files(pdev,
2344 &fxxxx_auto_pwm_attr[0][0],
2345 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2346 if (err)
2347 goto exit_unregister_sysfs;
2348 err = f71882fg_create_sysfs_files(pdev,
2349 f71808a_fan3_attr,
2350 ARRAY_SIZE(f71808a_fan3_attr));
2351 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002352 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01002353 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002354 f71862fg_auto_pwm_attr,
2355 ARRAY_SIZE(f71862fg_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002356 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002357 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002358 case f71869:
2359 err = f71882fg_create_sysfs_files(pdev,
2360 f71869_auto_pwm_attr,
2361 ARRAY_SIZE(f71869_auto_pwm_attr));
2362 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002363 case f8000:
2364 err = f71882fg_create_sysfs_files(pdev,
2365 f8000_fan_attr,
2366 ARRAY_SIZE(f8000_fan_attr));
Hans de Goede66344aa2009-12-09 20:35:59 +01002367 if (err)
2368 goto exit_unregister_sysfs;
2369 err = f71882fg_create_sysfs_files(pdev,
2370 f8000_auto_pwm_attr,
2371 ARRAY_SIZE(f8000_auto_pwm_attr));
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002372 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002373 default:
Hans de Goedeb69b0392009-12-09 20:36:00 +01002374 err = f71882fg_create_sysfs_files(pdev,
2375 &fxxxx_auto_pwm_attr[0][0],
2376 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
Hans de Goede498be962009-01-07 16:37:28 +01002377 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002378 if (err)
2379 goto exit_unregister_sysfs;
Hans de Goede28ba8582009-01-07 16:37:31 +01002380
Hans de Goedee48a7f12011-03-09 20:57:13 +01002381no_pwm_auto_point:
Hans de Goede28ba8582009-01-07 16:37:31 +01002382 for (i = 0; i < nr_fans; i++)
2383 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", i + 1,
2384 (data->pwm_enable & (1 << 2 * i)) ?
2385 "duty-cycle" : "RPM");
Hans de Goede45fb3662007-07-13 14:34:19 +02002386 }
2387
Tony Jones1beeffe2007-08-20 13:46:20 -07002388 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2389 if (IS_ERR(data->hwmon_dev)) {
2390 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002391 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002392 goto exit_unregister_sysfs;
2393 }
2394
2395 return 0;
2396
2397exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002398 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002399 return err; /* f71882fg_remove() also frees our data */
2400exit_free:
2401 kfree(data);
Hans de Goede45fb3662007-07-13 14:34:19 +02002402 return err;
2403}
2404
Hans de Goedec13548c2009-01-07 16:37:27 +01002405static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002406{
Hans de Goede45fb3662007-07-13 14:34:19 +02002407 struct f71882fg_data *data = platform_get_drvdata(pdev);
Jean Delvaref27def02011-03-26 10:45:01 +01002408 int nr_fans = f71882fg_nr_fans[data->type];
2409 int nr_temps = f71882fg_nr_temps[data->type];
2410 int i;
Hans de Goedefc16c562009-12-09 20:36:01 +01002411 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002412
Hans de Goedec13548c2009-01-07 16:37:27 +01002413 if (data->hwmon_dev)
2414 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002415
Hans de Goedec13548c2009-01-07 16:37:27 +01002416 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002417
Hans de Goedefc16c562009-12-09 20:36:01 +01002418 if (start_reg & 0x01) {
2419 switch (data->type) {
2420 case f71858fg:
2421 if (data->temp_config & 0x10)
2422 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002423 f8000_temp_attr,
2424 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002425 else
2426 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002427 f71858fg_temp_attr,
2428 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002429 break;
2430 case f8000:
2431 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002432 f8000_temp_attr,
2433 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002434 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002435 default:
2436 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002437 &fxxxx_temp_attr[0][0],
2438 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002439 }
Hans de Goede4d538112011-05-25 20:43:32 +02002440 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002441 f71882fg_remove_sysfs_files(pdev,
2442 &fxxxx_temp_beep_attr[0][0],
2443 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2444 }
2445
Hans de Goede0bae6402011-03-09 20:57:10 +01002446 for (i = 0; i < F71882FG_MAX_INS; i++) {
2447 if (f71882fg_has_in[data->type][i]) {
2448 device_remove_file(&pdev->dev,
2449 &fxxxx_in_attr[i].dev_attr);
2450 }
2451 }
2452 if (f71882fg_has_in1_alarm[data->type]) {
2453 f71882fg_remove_sysfs_files(pdev,
2454 fxxxx_in1_alarm_attr,
2455 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002456 }
2457 }
Hans de Goede498be962009-01-07 16:37:28 +01002458
Hans de Goedefc16c562009-12-09 20:36:01 +01002459 if (start_reg & 0x02) {
2460 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2461 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002462
Hans de Goede4d538112011-05-25 20:43:32 +02002463 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002464 f71882fg_remove_sysfs_files(pdev,
2465 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002466 }
Hans de Goede498be962009-01-07 16:37:28 +01002467
Hans de Goedefc16c562009-12-09 20:36:01 +01002468 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002469 case f71808a:
2470 f71882fg_remove_sysfs_files(pdev,
2471 &fxxxx_auto_pwm_attr[0][0],
2472 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2473 f71882fg_remove_sysfs_files(pdev,
2474 f71808a_fan3_attr,
2475 ARRAY_SIZE(f71808a_fan3_attr));
2476 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002477 case f71862fg:
2478 f71882fg_remove_sysfs_files(pdev,
2479 f71862fg_auto_pwm_attr,
2480 ARRAY_SIZE(f71862fg_auto_pwm_attr));
2481 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002482 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002483 case f71869:
2484 f71882fg_remove_sysfs_files(pdev,
2485 f71869_auto_pwm_attr,
2486 ARRAY_SIZE(f71869_auto_pwm_attr));
2487 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002488 case f8000:
2489 f71882fg_remove_sysfs_files(pdev,
2490 f8000_fan_attr,
2491 ARRAY_SIZE(f8000_fan_attr));
2492 f71882fg_remove_sysfs_files(pdev,
2493 f8000_auto_pwm_attr,
2494 ARRAY_SIZE(f8000_auto_pwm_attr));
2495 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002496 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002497 f71882fg_remove_sysfs_files(pdev,
2498 &fxxxx_auto_pwm_attr[0][0],
2499 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2500 }
2501 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002502
Hans de Goeded9ebaa42011-03-13 13:50:33 +01002503 platform_set_drvdata(pdev, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +02002504 kfree(data);
2505
2506 return 0;
2507}
2508
Hans de Goede498be962009-01-07 16:37:28 +01002509static int __init f71882fg_find(int sioaddr, unsigned short *address,
2510 struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002511{
Hans de Goede45fb3662007-07-13 14:34:19 +02002512 u16 devid;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002513 int err = superio_enter(sioaddr);
2514 if (err)
2515 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002516
2517 devid = superio_inw(sioaddr, SIO_REG_MANID);
2518 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002519 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002520 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002521 goto exit;
2522 }
2523
Jean Delvare67b671b2007-12-06 23:13:42 +01002524 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002525 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002526 case SIO_F71808E_ID:
2527 sio_data->type = f71808e;
2528 break;
Hans de Goede629c58b2011-05-25 20:43:32 +02002529 case SIO_F71808A_ID:
2530 sio_data->type = f71808a;
2531 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002532 case SIO_F71858_ID:
2533 sio_data->type = f71858fg;
2534 break;
Hans de Goede498be962009-01-07 16:37:28 +01002535 case SIO_F71862_ID:
2536 sio_data->type = f71862fg;
2537 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002538 case SIO_F71869_ID:
2539 sio_data->type = f71869;
2540 break;
Hans de Goede5da556e2011-07-03 13:32:53 +02002541 case SIO_F71869A_ID:
2542 sio_data->type = f71869a;
2543 break;
Hans de Goede498be962009-01-07 16:37:28 +01002544 case SIO_F71882_ID:
2545 sio_data->type = f71882fg;
2546 break;
Hans de Goede76698962009-12-09 20:36:01 +01002547 case SIO_F71889_ID:
2548 sio_data->type = f71889fg;
2549 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002550 case SIO_F71889E_ID:
2551 sio_data->type = f71889ed;
2552 break;
Hans de Goedea66c1082011-03-26 10:45:02 +01002553 case SIO_F71889A_ID:
2554 sio_data->type = f71889a;
2555 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002556 case SIO_F8000_ID:
2557 sio_data->type = f8000;
2558 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002559 case SIO_F81865_ID:
2560 sio_data->type = f81865f;
2561 break;
Hans de Goede498be962009-01-07 16:37:28 +01002562 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002563 pr_info("Unsupported Fintek device: %04x\n",
2564 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002565 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002566 goto exit;
2567 }
2568
Hans de Goede09475d32009-06-15 18:39:52 +02002569 if (sio_data->type == f71858fg)
2570 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2571 else
2572 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2573
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002574 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002575 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002576 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002577 goto exit;
2578 }
2579
2580 *address = superio_inw(sioaddr, SIO_REG_ADDR);
Giel van Schijndel162bb592010-05-27 19:58:40 +02002581 if (*address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002582 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002583 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002584 goto exit;
2585 }
2586 *address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
2587
Hans de Goede45fb3662007-07-13 14:34:19 +02002588 err = 0;
Joe Perches22d3b412010-10-20 06:51:34 +00002589 pr_info("Found %s chip at %#x, revision %d\n",
Hans de Goede498be962009-01-07 16:37:28 +01002590 f71882fg_names[sio_data->type], (unsigned int)*address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002591 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2592exit:
2593 superio_exit(sioaddr);
2594 return err;
2595}
2596
Hans de Goede498be962009-01-07 16:37:28 +01002597static int __init f71882fg_device_add(unsigned short address,
2598 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002599{
2600 struct resource res = {
2601 .start = address,
2602 .end = address + REGION_LENGTH - 1,
2603 .flags = IORESOURCE_IO,
2604 };
2605 int err;
2606
2607 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002608 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002609 return -ENOMEM;
2610
2611 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002612 err = acpi_check_resource_conflict(&res);
2613 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002614 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002615
Hans de Goede45fb3662007-07-13 14:34:19 +02002616 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002617 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002618 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002619 goto exit_device_put;
2620 }
2621
Hans de Goede498be962009-01-07 16:37:28 +01002622 err = platform_device_add_data(f71882fg_pdev, sio_data,
2623 sizeof(struct f71882fg_sio_data));
2624 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002625 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002626 goto exit_device_put;
2627 }
2628
Hans de Goede45fb3662007-07-13 14:34:19 +02002629 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002630 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002631 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002632 goto exit_device_put;
2633 }
2634
2635 return 0;
2636
2637exit_device_put:
2638 platform_device_put(f71882fg_pdev);
2639
2640 return err;
2641}
2642
2643static int __init f71882fg_init(void)
2644{
2645 int err = -ENODEV;
2646 unsigned short address;
Hans de Goede498be962009-01-07 16:37:28 +01002647 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002648
Hans de Goede498be962009-01-07 16:37:28 +01002649 memset(&sio_data, 0, sizeof(sio_data));
2650
2651 if (f71882fg_find(0x2e, &address, &sio_data) &&
2652 f71882fg_find(0x4e, &address, &sio_data))
Hans de Goede45fb3662007-07-13 14:34:19 +02002653 goto exit;
2654
Hans de Goedec13548c2009-01-07 16:37:27 +01002655 err = platform_driver_register(&f71882fg_driver);
2656 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002657 goto exit;
2658
Hans de Goede498be962009-01-07 16:37:28 +01002659 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002660 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002661 goto exit_driver;
2662
2663 return 0;
2664
2665exit_driver:
2666 platform_driver_unregister(&f71882fg_driver);
2667exit:
2668 return err;
2669}
2670
2671static void __exit f71882fg_exit(void)
2672{
2673 platform_device_unregister(f71882fg_pdev);
2674 platform_driver_unregister(&f71882fg_driver);
2675}
2676
2677MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goede7958e3b2011-07-03 13:32:53 +02002678MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
Hans de Goede45fb3662007-07-13 14:34:19 +02002679MODULE_LICENSE("GPL");
2680
2681module_init(f71882fg_init);
2682module_exit(f71882fg_exit);