blob: 79f1f50de4519a89e44b1a2b1ddf7ef497012704 [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 */
Peter Hung2725fe22015-07-07 16:22:36 +080054#define SIO_F71868_ID 0x1106 /* Chipset ID */
Hans de Goedec11bb992011-03-09 20:57:15 +010055#define SIO_F71869_ID 0x0814 /* Chipset ID */
Hans de Goede5da556e2011-07-03 13:32:53 +020056#define SIO_F71869A_ID 0x1007 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020057#define SIO_F71882_ID 0x0541 /* Chipset ID */
Hans de Goede76698962009-12-09 20:36:01 +010058#define SIO_F71889_ID 0x0723 /* Chipset ID */
Hans de Goede3cad4022011-03-09 20:57:14 +010059#define SIO_F71889E_ID 0x0909 /* Chipset ID */
Hans de Goedea66c1082011-03-26 10:45:02 +010060#define SIO_F71889A_ID 0x1005 /* Chipset ID */
Hans de Goedeed4f7c22009-01-07 16:37:30 +010061#define SIO_F8000_ID 0x0581 /* Chipset ID */
Jean Delvare383586b2011-03-26 10:45:02 +010062#define SIO_F81865_ID 0x0704 /* Chipset ID */
Peter Hung2725fe22015-07-07 16:22:36 +080063#define SIO_F81866_ID 0x1010 /* Chipset ID */
Hans de Goede45fb3662007-07-13 14:34:19 +020064
65#define REGION_LENGTH 8
66#define ADDR_REG_OFFSET 5
67#define DATA_REG_OFFSET 6
68
Hans de Goede3cad4022011-03-09 20:57:14 +010069#define F71882FG_REG_IN_STATUS 0x12 /* f7188x only */
70#define F71882FG_REG_IN_BEEP 0x13 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020071#define F71882FG_REG_IN(nr) (0x20 + (nr))
Hans de Goede3cad4022011-03-09 20:57:14 +010072#define F71882FG_REG_IN1_HIGH 0x32 /* f7188x only */
Hans de Goede45fb3662007-07-13 14:34:19 +020073
74#define F71882FG_REG_FAN(nr) (0xA0 + (16 * (nr)))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010075#define F71882FG_REG_FAN_TARGET(nr) (0xA2 + (16 * (nr)))
76#define F71882FG_REG_FAN_FULL_SPEED(nr) (0xA4 + (16 * (nr)))
Hans de Goede45fb3662007-07-13 14:34:19 +020077#define F71882FG_REG_FAN_STATUS 0x92
78#define F71882FG_REG_FAN_BEEP 0x93
79
Hans de Goede7567a042009-01-07 16:37:28 +010080#define F71882FG_REG_TEMP(nr) (0x70 + 2 * (nr))
81#define F71882FG_REG_TEMP_OVT(nr) (0x80 + 2 * (nr))
82#define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020083#define F71882FG_REG_TEMP_STATUS 0x62
84#define F71882FG_REG_TEMP_BEEP 0x63
Hans de Goede09475d32009-06-15 18:39:52 +020085#define F71882FG_REG_TEMP_CONFIG 0x69
Hans de Goedebc274902009-01-07 16:37:29 +010086#define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr))
Hans de Goede45fb3662007-07-13 14:34:19 +020087#define F71882FG_REG_TEMP_TYPE 0x6B
88#define F71882FG_REG_TEMP_DIODE_OPEN 0x6F
89
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010090#define F71882FG_REG_PWM(nr) (0xA3 + (16 * (nr)))
91#define F71882FG_REG_PWM_TYPE 0x94
92#define F71882FG_REG_PWM_ENABLE 0x96
93
Hans de Goedebc274902009-01-07 16:37:29 +010094#define F71882FG_REG_FAN_HYST(nr) (0x98 + (nr))
Mark van Doesburg9ab796e2009-01-07 16:37:27 +010095
Hans de Goede98f7ba12011-03-09 20:57:09 +010096#define F71882FG_REG_FAN_FAULT_T 0x9F
97#define F71882FG_FAN_NEG_TEMP_EN 0x20
Hans de Goede3cad4022011-03-09 20:57:14 +010098#define F71882FG_FAN_PROG_SEL 0x80
Hans de Goede98f7ba12011-03-09 20:57:09 +010099
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100100#define F71882FG_REG_POINT_PWM(pwm, point) (0xAA + (point) + (16 * (pwm)))
101#define F71882FG_REG_POINT_TEMP(pwm, point) (0xA6 + (point) + (16 * (pwm)))
102#define F71882FG_REG_POINT_MAPPING(nr) (0xAF + 16 * (nr))
103
Hans de Goede45fb3662007-07-13 14:34:19 +0200104#define F71882FG_REG_START 0x01
105
Peter Hung2725fe22015-07-07 16:22:36 +0800106#define F71882FG_MAX_INS 10
Hans de Goede0bae6402011-03-09 20:57:10 +0100107
Hans de Goede45fb3662007-07-13 14:34:19 +0200108#define FAN_MIN_DETECT 366 /* Lowest detectable fanspeed */
109
Jean Delvare67b671b2007-12-06 23:13:42 +0100110static unsigned short force_id;
111module_param(force_id, ushort, 0);
112MODULE_PARM_DESC(force_id, "Override the detected device ID");
113
Peter Hung2725fe22015-07-07 16:22:36 +0800114enum chips { f71808e, f71808a, f71858fg, f71862fg, f71868a, f71869, f71869a,
115 f71882fg, f71889fg, f71889ed, f71889a, f8000, f81865f, f81866a};
Hans de Goede498be962009-01-07 16:37:28 +0100116
Frans Meulenbroeks1dc37082012-01-08 19:34:10 +0100117static const char *const f71882fg_names[] = {
Hans de Goedee5e713c2011-03-10 08:54:02 +0100118 "f71808e",
Hans de Goede629c58b2011-05-25 20:43:32 +0200119 "f71808a",
Hans de Goede09475d32009-06-15 18:39:52 +0200120 "f71858fg",
Hans de Goede498be962009-01-07 16:37:28 +0100121 "f71862fg",
Peter Hung2725fe22015-07-07 16:22:36 +0800122 "f71868a",
Hans de Goedec11bb992011-03-09 20:57:15 +0100123 "f71869", /* Both f71869f and f71869e, reg. compatible and same id */
Hans de Goede5da556e2011-07-03 13:32:53 +0200124 "f71869a",
Hans de Goede498be962009-01-07 16:37:28 +0100125 "f71882fg",
Jean Delvare5d7f77b2011-03-26 10:45:02 +0100126 "f71889fg", /* f81801u too, same id */
Hans de Goede3cad4022011-03-09 20:57:14 +0100127 "f71889ed",
Hans de Goedea66c1082011-03-26 10:45:02 +0100128 "f71889a",
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100129 "f8000",
Jean Delvare383586b2011-03-26 10:45:02 +0100130 "f81865f",
Peter Hung2725fe22015-07-07 16:22:36 +0800131 "f81866a",
Hans de Goede498be962009-01-07 16:37:28 +0100132};
133
Jean Delvare2740c602011-03-26 10:45:01 +0100134static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
Peter Hung2725fe22015-07-07 16:22:36 +0800135 [f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1, 0 },
136 [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
137 [f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
138 [f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
139 [f71868a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
140 [f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
141 [f71869a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
142 [f71882fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
143 [f71889fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
144 [f71889ed] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
145 [f71889a] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
146 [f8000] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
147 [f81865f] = { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
148 [f81866a] = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
Hans de Goede0bae6402011-03-09 20:57:10 +0100149};
150
Jean Delvare2740c602011-03-26 10:45:01 +0100151static const char f71882fg_has_in1_alarm[] = {
152 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200153 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100154 [f71858fg] = 0,
155 [f71862fg] = 0,
Peter Hung2725fe22015-07-07 16:22:36 +0800156 [f71868a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100157 [f71869] = 0,
Hans de Goede5da556e2011-07-03 13:32:53 +0200158 [f71869a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100159 [f71882fg] = 1,
160 [f71889fg] = 1,
161 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100162 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100163 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100164 [f81865f] = 1,
Peter Hung2725fe22015-07-07 16:22:36 +0800165 [f81866a] = 1,
Hans de Goede0bae6402011-03-09 20:57:10 +0100166};
167
Hans de Goede4d538112011-05-25 20:43:32 +0200168static const char f71882fg_fan_has_beep[] = {
Jean Delvare2740c602011-03-26 10:45:01 +0100169 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200170 [f71808a] = 0,
Jean Delvare2740c602011-03-26 10:45:01 +0100171 [f71858fg] = 0,
172 [f71862fg] = 1,
Peter Hung2725fe22015-07-07 16:22:36 +0800173 [f71868a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100174 [f71869] = 1,
Hans de Goede5da556e2011-07-03 13:32:53 +0200175 [f71869a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100176 [f71882fg] = 1,
177 [f71889fg] = 1,
178 [f71889ed] = 1,
Hans de Goedea66c1082011-03-26 10:45:02 +0100179 [f71889a] = 1,
Jean Delvare2740c602011-03-26 10:45:01 +0100180 [f8000] = 0,
Jean Delvare383586b2011-03-26 10:45:02 +0100181 [f81865f] = 1,
Peter Hung2725fe22015-07-07 16:22:36 +0800182 [f81866a] = 1,
Hans de Goede78aa4f72011-03-09 20:57:12 +0100183};
184
Jean Delvaref27def02011-03-26 10:45:01 +0100185static const char f71882fg_nr_fans[] = {
186 [f71808e] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200187 [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */
Jean Delvaref27def02011-03-26 10:45:01 +0100188 [f71858fg] = 3,
189 [f71862fg] = 3,
Peter Hung2725fe22015-07-07 16:22:36 +0800190 [f71868a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100191 [f71869] = 3,
Hans de Goede5da556e2011-07-03 13:32:53 +0200192 [f71869a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100193 [f71882fg] = 4,
194 [f71889fg] = 3,
195 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100196 [f71889a] = 3,
Hans de Goede629c58b2011-05-25 20:43:32 +0200197 [f8000] = 3, /* +1 fan which is monitor only */
Jean Delvare383586b2011-03-26 10:45:02 +0100198 [f81865f] = 2,
Peter Hung2725fe22015-07-07 16:22:36 +0800199 [f81866a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100200};
201
Hans de Goede4d538112011-05-25 20:43:32 +0200202static const char f71882fg_temp_has_beep[] = {
203 [f71808e] = 0,
Hans de Goede629c58b2011-05-25 20:43:32 +0200204 [f71808a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200205 [f71858fg] = 0,
206 [f71862fg] = 1,
Peter Hung2725fe22015-07-07 16:22:36 +0800207 [f71868a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200208 [f71869] = 1,
Hans de Goede5da556e2011-07-03 13:32:53 +0200209 [f71869a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200210 [f71882fg] = 1,
211 [f71889fg] = 1,
212 [f71889ed] = 1,
213 [f71889a] = 1,
214 [f8000] = 0,
215 [f81865f] = 1,
Peter Hung2725fe22015-07-07 16:22:36 +0800216 [f81866a] = 1,
Hans de Goede4d538112011-05-25 20:43:32 +0200217};
218
Jean Delvaref27def02011-03-26 10:45:01 +0100219static const char f71882fg_nr_temps[] = {
220 [f71808e] = 2,
Hans de Goede629c58b2011-05-25 20:43:32 +0200221 [f71808a] = 2,
Jean Delvaref27def02011-03-26 10:45:01 +0100222 [f71858fg] = 3,
223 [f71862fg] = 3,
Peter Hung2725fe22015-07-07 16:22:36 +0800224 [f71868a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100225 [f71869] = 3,
Hans de Goede5da556e2011-07-03 13:32:53 +0200226 [f71869a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100227 [f71882fg] = 3,
228 [f71889fg] = 3,
229 [f71889ed] = 3,
Hans de Goedea66c1082011-03-26 10:45:02 +0100230 [f71889a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100231 [f8000] = 3,
Jean Delvare383586b2011-03-26 10:45:02 +0100232 [f81865f] = 2,
Peter Hung2725fe22015-07-07 16:22:36 +0800233 [f81866a] = 3,
Jean Delvaref27def02011-03-26 10:45:01 +0100234};
235
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100236static struct platform_device *f71882fg_pdev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200237
238/* Super-I/O Function prototypes */
239static inline int superio_inb(int base, int reg);
240static inline int superio_inw(int base, int reg);
Giel van Schijndelcadb8652010-10-03 08:09:49 -0400241static inline int superio_enter(int base);
Hans de Goede45fb3662007-07-13 14:34:19 +0200242static inline void superio_select(int base, int ld);
243static inline void superio_exit(int base);
244
Hans de Goede498be962009-01-07 16:37:28 +0100245struct f71882fg_sio_data {
246 enum chips type;
247};
248
Hans de Goede45fb3662007-07-13 14:34:19 +0200249struct f71882fg_data {
250 unsigned short addr;
Hans de Goede498be962009-01-07 16:37:28 +0100251 enum chips type;
Tony Jones1beeffe2007-08-20 13:46:20 -0700252 struct device *hwmon_dev;
Hans de Goede45fb3662007-07-13 14:34:19 +0200253
254 struct mutex update_lock;
Hans de Goede09475d32009-06-15 18:39:52 +0200255 int temp_start; /* temp numbering start (0 or 1) */
Hans de Goede45fb3662007-07-13 14:34:19 +0200256 char valid; /* !=0 if following fields are valid */
Hans de Goede98f7ba12011-03-09 20:57:09 +0100257 char auto_point_temp_signed;
Hans de Goede45fb3662007-07-13 14:34:19 +0200258 unsigned long last_updated; /* In jiffies */
259 unsigned long last_limits; /* In jiffies */
260
261 /* Register Values */
Hans de Goede0bae6402011-03-09 20:57:10 +0100262 u8 in[F71882FG_MAX_INS];
Hans de Goede45fb3662007-07-13 14:34:19 +0200263 u8 in1_max;
264 u8 in_status;
265 u8 in_beep;
266 u16 fan[4];
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100267 u16 fan_target[4];
268 u16 fan_full_speed[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200269 u8 fan_status;
270 u8 fan_beep;
Guenter Roeck20eaf722012-01-19 11:02:17 -0800271 /*
272 * Note: all models have max 3 temperature channels, but on some
273 * they are addressed as 0-2 and on others as 1-3, so for coding
274 * convenience we reserve space for 4 channels
275 */
Hans de Goede09475d32009-06-15 18:39:52 +0200276 u16 temp[4];
Hans de Goede7567a042009-01-07 16:37:28 +0100277 u8 temp_ovt[4];
278 u8 temp_high[4];
Hans de Goedebc274902009-01-07 16:37:29 +0100279 u8 temp_hyst[2]; /* 2 hysts stored per reg */
Hans de Goede7567a042009-01-07 16:37:28 +0100280 u8 temp_type[4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200281 u8 temp_status;
282 u8 temp_beep;
283 u8 temp_diode_open;
Hans de Goede09475d32009-06-15 18:39:52 +0200284 u8 temp_config;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100285 u8 pwm[4];
286 u8 pwm_enable;
287 u8 pwm_auto_point_hyst[2];
288 u8 pwm_auto_point_mapping[4];
289 u8 pwm_auto_point_pwm[4][5];
Hans de Goede76698962009-12-09 20:36:01 +0100290 s8 pwm_auto_point_temp[4][4];
Hans de Goede45fb3662007-07-13 14:34:19 +0200291};
292
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +0100293/* Sysfs in */
Hans de Goede45fb3662007-07-13 14:34:19 +0200294static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
295 char *buf);
296static ssize_t show_in_max(struct device *dev, struct device_attribute
297 *devattr, char *buf);
298static ssize_t store_in_max(struct device *dev, struct device_attribute
299 *devattr, const char *buf, size_t count);
300static ssize_t show_in_beep(struct device *dev, struct device_attribute
301 *devattr, char *buf);
302static ssize_t store_in_beep(struct device *dev, struct device_attribute
303 *devattr, const char *buf, size_t count);
304static ssize_t show_in_alarm(struct device *dev, struct device_attribute
305 *devattr, char *buf);
306/* Sysfs Fan */
307static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
308 char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100309static ssize_t show_fan_full_speed(struct device *dev,
310 struct device_attribute *devattr, char *buf);
311static ssize_t store_fan_full_speed(struct device *dev,
312 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200313static ssize_t show_fan_beep(struct device *dev, struct device_attribute
314 *devattr, char *buf);
315static ssize_t store_fan_beep(struct device *dev, struct device_attribute
316 *devattr, const char *buf, size_t count);
317static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
318 *devattr, char *buf);
319/* Sysfs Temp */
320static ssize_t show_temp(struct device *dev, struct device_attribute
321 *devattr, char *buf);
322static ssize_t show_temp_max(struct device *dev, struct device_attribute
323 *devattr, char *buf);
324static ssize_t store_temp_max(struct device *dev, struct device_attribute
325 *devattr, const char *buf, size_t count);
326static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
327 *devattr, char *buf);
328static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
329 *devattr, const char *buf, size_t count);
330static ssize_t show_temp_crit(struct device *dev, struct device_attribute
331 *devattr, char *buf);
332static ssize_t store_temp_crit(struct device *dev, struct device_attribute
333 *devattr, const char *buf, size_t count);
334static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
335 *devattr, char *buf);
336static ssize_t show_temp_type(struct device *dev, struct device_attribute
337 *devattr, char *buf);
338static ssize_t show_temp_beep(struct device *dev, struct device_attribute
339 *devattr, char *buf);
340static ssize_t store_temp_beep(struct device *dev, struct device_attribute
341 *devattr, const char *buf, size_t count);
342static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
343 *devattr, char *buf);
344static ssize_t show_temp_fault(struct device *dev, struct device_attribute
345 *devattr, char *buf);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100346/* PWM and Auto point control */
347static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
348 char *buf);
349static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
350 const char *buf, size_t count);
Hans de Goede629c58b2011-05-25 20:43:32 +0200351static ssize_t show_simple_pwm(struct device *dev,
352 struct device_attribute *devattr, char *buf);
353static ssize_t store_simple_pwm(struct device *dev,
354 struct device_attribute *devattr, const char *buf, size_t count);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100355static ssize_t show_pwm_enable(struct device *dev,
356 struct device_attribute *devattr, char *buf);
357static ssize_t store_pwm_enable(struct device *dev,
358 struct device_attribute *devattr, const char *buf, size_t count);
359static ssize_t show_pwm_interpolate(struct device *dev,
360 struct device_attribute *devattr, char *buf);
361static ssize_t store_pwm_interpolate(struct device *dev,
362 struct device_attribute *devattr, const char *buf, size_t count);
363static ssize_t show_pwm_auto_point_channel(struct device *dev,
364 struct device_attribute *devattr, char *buf);
365static ssize_t store_pwm_auto_point_channel(struct device *dev,
366 struct device_attribute *devattr, const char *buf, size_t count);
367static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
368 struct device_attribute *devattr, char *buf);
369static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
370 struct device_attribute *devattr, const char *buf, size_t count);
371static ssize_t show_pwm_auto_point_pwm(struct device *dev,
372 struct device_attribute *devattr, char *buf);
373static ssize_t store_pwm_auto_point_pwm(struct device *dev,
374 struct device_attribute *devattr, const char *buf, size_t count);
375static ssize_t show_pwm_auto_point_temp(struct device *dev,
376 struct device_attribute *devattr, char *buf);
377static ssize_t store_pwm_auto_point_temp(struct device *dev,
378 struct device_attribute *devattr, const char *buf, size_t count);
Hans de Goede45fb3662007-07-13 14:34:19 +0200379/* Sysfs misc */
380static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
381 char *buf);
382
Bill Pemberton6c931ae2012-11-19 13:22:35 -0500383static int f71882fg_probe(struct platform_device *pdev);
Hans de Goedec13548c2009-01-07 16:37:27 +0100384static int f71882fg_remove(struct platform_device *pdev);
Hans de Goede45fb3662007-07-13 14:34:19 +0200385
386static struct platform_driver f71882fg_driver = {
387 .driver = {
Hans de Goede45fb3662007-07-13 14:34:19 +0200388 .name = DRVNAME,
389 },
390 .probe = f71882fg_probe,
Jean Delvarecd659fd2009-06-15 18:39:45 +0200391 .remove = f71882fg_remove,
Hans de Goede45fb3662007-07-13 14:34:19 +0200392};
393
Hans de Goedec13548c2009-01-07 16:37:27 +0100394static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
Hans de Goede45fb3662007-07-13 14:34:19 +0200395
Guenter Roeck20eaf722012-01-19 11:02:17 -0800396/*
397 * Temp attr for the f71858fg, the f71858fg is special as it has its
398 * temperature indexes start at 0 (the others start at 1)
399 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100400static struct sensor_device_attribute_2 f71858fg_temp_attr[] = {
Hans de Goede09475d32009-06-15 18:39:52 +0200401 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
402 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
403 store_temp_max, 0, 0),
404 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
405 store_temp_max_hyst, 0, 0),
406 SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
407 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
408 store_temp_crit, 0, 0),
409 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
410 0, 0),
411 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
412 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
413 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
414 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
415 store_temp_max, 0, 1),
416 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
417 store_temp_max_hyst, 0, 1),
418 SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
419 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
420 store_temp_crit, 0, 1),
421 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
422 0, 1),
423 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede09475d32009-06-15 18:39:52 +0200424 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
425 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
426 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
427 store_temp_max, 0, 2),
428 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
429 store_temp_max_hyst, 0, 2),
430 SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
431 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
432 store_temp_crit, 0, 2),
433 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
434 0, 2),
435 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
436 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
437};
438
Hans de Goede0bae6402011-03-09 20:57:10 +0100439/* Temp attr for the standard models */
Hans de Goede78aa4f72011-03-09 20:57:12 +0100440static struct sensor_device_attribute_2 fxxxx_temp_attr[3][9] = { {
Hans de Goede7567a042009-01-07 16:37:28 +0100441 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 1),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100442 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100443 store_temp_max, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100444 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100445 store_temp_max_hyst, 0, 1),
Guenter Roeck20eaf722012-01-19 11:02:17 -0800446 /*
447 * Should really be temp1_max_alarm, but older versions did not handle
448 * the max and crit alarms separately and lm_sensors v2 depends on the
449 * presence of temp#_alarm files. The same goes for temp2/3 _alarm.
450 */
Hans de Goede754a5907b2009-01-07 16:37:29 +0100451 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100452 SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100453 store_temp_crit, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100454 SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100455 0, 1),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100456 SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goede7567a042009-01-07 16:37:28 +0100457 SENSOR_ATTR_2(temp1_type, S_IRUGO, show_temp_type, NULL, 0, 1),
Hans de Goede7567a042009-01-07 16:37:28 +0100458 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goede60d2b372011-03-09 20:57:11 +0100459}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100460 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 2),
461 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100462 store_temp_max, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100463 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100464 store_temp_max_hyst, 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100465 /* Should be temp2_max_alarm, see temp1_alarm note */
466 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100467 SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100468 store_temp_crit, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100469 SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100470 0, 2),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100471 SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goede7567a042009-01-07 16:37:28 +0100472 SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 2),
Hans de Goede7567a042009-01-07 16:37:28 +0100473 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goede60d2b372011-03-09 20:57:11 +0100474}, {
Hans de Goede7567a042009-01-07 16:37:28 +0100475 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 3),
476 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
477 store_temp_max, 0, 3),
478 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
479 store_temp_max_hyst, 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100480 /* Should be temp3_max_alarm, see temp1_alarm note */
481 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100482 SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
483 store_temp_crit, 0, 3),
484 SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
485 0, 3),
Hans de Goede754a5907b2009-01-07 16:37:29 +0100486 SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 7),
Hans de Goede7567a042009-01-07 16:37:28 +0100487 SENSOR_ATTR_2(temp3_type, S_IRUGO, show_temp_type, NULL, 0, 3),
Hans de Goede7567a042009-01-07 16:37:28 +0100488 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 3),
Hans de Goede60d2b372011-03-09 20:57:11 +0100489} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200490
Hans de Goede78aa4f72011-03-09 20:57:12 +0100491/* Temp attr for models which can beep on temp alarm */
492static struct sensor_device_attribute_2 fxxxx_temp_beep_attr[3][2] = { {
493 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
494 store_temp_beep, 0, 1),
495 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
496 store_temp_beep, 0, 5),
497}, {
498 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
499 store_temp_beep, 0, 2),
500 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
501 store_temp_beep, 0, 6),
502}, {
503 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
504 store_temp_beep, 0, 3),
505 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
506 store_temp_beep, 0, 7),
507} };
508
Peter Hungdcd956f2015-07-07 16:22:37 +0800509static struct sensor_device_attribute_2 f81866_temp_beep_attr[3][2] = { {
510 SENSOR_ATTR_2(temp1_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
511 store_temp_beep, 0, 0),
512 SENSOR_ATTR_2(temp1_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
513 store_temp_beep, 0, 4),
514}, {
515 SENSOR_ATTR_2(temp2_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
516 store_temp_beep, 0, 1),
517 SENSOR_ATTR_2(temp2_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
518 store_temp_beep, 0, 5),
519}, {
520 SENSOR_ATTR_2(temp3_max_beep, S_IRUGO|S_IWUSR, show_temp_beep,
521 store_temp_beep, 0, 2),
522 SENSOR_ATTR_2(temp3_crit_beep, S_IRUGO|S_IWUSR, show_temp_beep,
523 store_temp_beep, 0, 6),
524} };
525
Guenter Roeck20eaf722012-01-19 11:02:17 -0800526/*
527 * Temp attr for the f8000
528 * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
529 * is used as hysteresis value to clear alarms
530 * Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100531 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100532static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100533 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
534 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
535 store_temp_crit, 0, 0),
536 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
537 store_temp_max, 0, 0),
538 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200539 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100540 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
541 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
542 store_temp_crit, 0, 1),
543 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
544 store_temp_max, 0, 1),
545 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200546 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100547 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
548 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
549 store_temp_crit, 0, 2),
550 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
551 store_temp_max, 0, 2),
552 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200553 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100554};
555
Hans de Goede0bae6402011-03-09 20:57:10 +0100556/* in attr for all models */
557static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
558 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
559 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
560 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
561 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
562 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
563 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
564 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
565 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
566 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Peter Hung2725fe22015-07-07 16:22:36 +0800567 SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9),
Hans de Goede0bae6402011-03-09 20:57:10 +0100568};
569
570/* For models with in1 alarm capability */
571static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
572 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
573 0, 1),
574 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
575 0, 1),
576 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
577};
578
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100579/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100580static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100581 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100582 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
583 show_fan_full_speed,
584 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100585 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100586 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
587 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
588 store_pwm_enable, 0, 0),
589 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
590 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100591}, {
592 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
593 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
594 show_fan_full_speed,
595 store_fan_full_speed, 0, 1),
596 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100597 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
598 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
599 store_pwm_enable, 0, 1),
600 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
601 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100602}, {
603 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
604 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
605 show_fan_full_speed,
606 store_fan_full_speed, 0, 2),
607 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200608 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
609 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
610 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100611 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
612 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100613}, {
614 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
615 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
616 show_fan_full_speed,
617 store_fan_full_speed, 0, 3),
618 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
619 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
620 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
621 store_pwm_enable, 0, 3),
622 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
623 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
624} };
Hans de Goede498be962009-01-07 16:37:28 +0100625
Hans de Goede629c58b2011-05-25 20:43:32 +0200626/* Attr for the third fan of the f71808a, which only has manual pwm */
627static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
628 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
629 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
630 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
631 show_simple_pwm, store_simple_pwm, 0, 2),
632};
633
Hans de Goede66344aa2009-12-09 20:35:59 +0100634/* Attr for models which can beep on Fan alarm */
635static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100636 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
637 store_fan_beep, 0, 0),
638 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
639 store_fan_beep, 0, 1),
640 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
641 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100642 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
643 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100644};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100645
Guenter Roeck20eaf722012-01-19 11:02:17 -0800646/*
647 * PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
648 * standard models
649 */
Hans de Goede55840142011-09-09 12:12:33 +0200650static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100651 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
652 show_pwm_auto_point_channel,
653 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100654 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
655 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
656 1, 0),
657 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
658 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
659 4, 0),
660 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
661 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
662 0, 0),
663 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
664 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
665 3, 0),
666 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
667 show_pwm_auto_point_temp_hyst,
668 store_pwm_auto_point_temp_hyst,
669 0, 0),
670 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
671 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +0200672}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100673 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
674 show_pwm_auto_point_channel,
675 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100676 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
677 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
678 1, 1),
679 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
680 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
681 4, 1),
682 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
683 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
684 0, 1),
685 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
686 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
687 3, 1),
688 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
689 show_pwm_auto_point_temp_hyst,
690 store_pwm_auto_point_temp_hyst,
691 0, 1),
692 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
693 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +0200694}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100695 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
696 show_pwm_auto_point_channel,
697 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100698 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
699 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
700 1, 2),
701 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
702 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
703 4, 2),
704 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
705 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
706 0, 2),
707 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
708 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
709 3, 2),
710 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
711 show_pwm_auto_point_temp_hyst,
712 store_pwm_auto_point_temp_hyst,
713 0, 2),
714 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
715 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +0200716} };
Hans de Goede498be962009-01-07 16:37:28 +0100717
Guenter Roeck20eaf722012-01-19 11:02:17 -0800718/*
719 * PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
720 * pwm setting when the temperature is above the pwmX_auto_point1_temp can be
721 * programmed instead of being hardcoded to 0xff
722 */
Hans de Goede55840142011-09-09 12:12:33 +0200723static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { {
Hans de Goedec11bb992011-03-09 20:57:15 +0100724 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
725 show_pwm_auto_point_channel,
726 store_pwm_auto_point_channel, 0, 0),
727 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
728 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
729 0, 0),
730 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
731 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
732 1, 0),
733 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
734 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
735 4, 0),
736 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
737 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
738 0, 0),
739 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
740 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
741 3, 0),
742 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
743 show_pwm_auto_point_temp_hyst,
744 store_pwm_auto_point_temp_hyst,
745 0, 0),
746 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
747 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +0200748}, {
Hans de Goedec11bb992011-03-09 20:57:15 +0100749 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
750 show_pwm_auto_point_channel,
751 store_pwm_auto_point_channel, 0, 1),
752 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
753 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
754 0, 1),
755 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
756 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
757 1, 1),
758 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
759 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
760 4, 1),
761 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
762 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
763 0, 1),
764 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
765 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
766 3, 1),
767 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
768 show_pwm_auto_point_temp_hyst,
769 store_pwm_auto_point_temp_hyst,
770 0, 1),
771 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
772 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +0200773}, {
Hans de Goedec11bb992011-03-09 20:57:15 +0100774 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
775 show_pwm_auto_point_channel,
776 store_pwm_auto_point_channel, 0, 2),
777 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
778 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
779 0, 2),
780 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
781 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
782 1, 2),
783 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
784 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
785 4, 2),
786 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
787 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
788 0, 2),
789 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
790 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
791 3, 2),
792 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
793 show_pwm_auto_point_temp_hyst,
794 store_pwm_auto_point_temp_hyst,
795 0, 2),
796 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
797 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +0200798} };
Hans de Goedec11bb992011-03-09 20:57:15 +0100799
Hans de Goede3cad4022011-03-09 20:57:14 +0100800/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100801static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100802 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
803 show_pwm_auto_point_channel,
804 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100805 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
806 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
807 0, 0),
808 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
809 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
810 1, 0),
811 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
812 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
813 2, 0),
814 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
815 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
816 3, 0),
817 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
818 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
819 4, 0),
820 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
821 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
822 0, 0),
823 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
824 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
825 1, 0),
826 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
828 2, 0),
829 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
831 3, 0),
832 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_temp_hyst,
834 store_pwm_auto_point_temp_hyst,
835 0, 0),
836 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
837 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
838 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
839 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
840 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
841 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100842}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100843 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
844 show_pwm_auto_point_channel,
845 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100846 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
847 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
848 0, 1),
849 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
850 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
851 1, 1),
852 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
853 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
854 2, 1),
855 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
856 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
857 3, 1),
858 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
859 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
860 4, 1),
861 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
862 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
863 0, 1),
864 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
865 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
866 1, 1),
867 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
869 2, 1),
870 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
872 3, 1),
873 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_temp_hyst,
875 store_pwm_auto_point_temp_hyst,
876 0, 1),
877 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
878 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
879 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
880 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
881 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
882 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100883}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100884 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
885 show_pwm_auto_point_channel,
886 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100887 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
888 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
889 0, 2),
890 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
891 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
892 1, 2),
893 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
894 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
895 2, 2),
896 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
897 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
898 3, 2),
899 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
900 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
901 4, 2),
902 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
903 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
904 0, 2),
905 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
906 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
907 1, 2),
908 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
909 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
910 2, 2),
911 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
912 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
913 3, 2),
914 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
915 show_pwm_auto_point_temp_hyst,
916 store_pwm_auto_point_temp_hyst,
917 0, 2),
918 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
919 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
920 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
921 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
922 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
923 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100924}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100925 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
926 show_pwm_auto_point_channel,
927 store_pwm_auto_point_channel, 0, 3),
928 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
929 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
930 0, 3),
931 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
932 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
933 1, 3),
934 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
935 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
936 2, 3),
937 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
938 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
939 3, 3),
940 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
941 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
942 4, 3),
943 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
944 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
945 0, 3),
946 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
947 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
948 1, 3),
949 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
950 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
951 2, 3),
952 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
953 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
954 3, 3),
955 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
956 show_pwm_auto_point_temp_hyst,
957 store_pwm_auto_point_temp_hyst,
958 0, 3),
959 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
960 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
961 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
962 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
963 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
964 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100965} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200966
Hans de Goede66344aa2009-12-09 20:35:59 +0100967/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100968static struct sensor_device_attribute_2 f8000_fan_attr[] = {
969 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100970};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100971
Guenter Roeck20eaf722012-01-19 11:02:17 -0800972/*
973 * PWM attr for the f8000, zones mapped to temp instead of to pwm!
974 * Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
975 * F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0
976 */
Hans de Goede55840142011-09-09 12:12:33 +0200977static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100978 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
979 show_pwm_auto_point_channel,
980 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100981 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
982 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
983 0, 2),
984 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
985 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
986 1, 2),
987 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
988 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
989 2, 2),
990 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
991 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
992 3, 2),
993 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
994 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
995 4, 2),
996 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
997 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
998 0, 2),
999 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
1000 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1001 1, 2),
1002 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
1003 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1004 2, 2),
1005 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
1006 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1007 3, 2),
1008 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1009 show_pwm_auto_point_temp_hyst,
1010 store_pwm_auto_point_temp_hyst,
1011 0, 2),
1012 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
1013 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
1014 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
1015 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
1016 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
1017 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +02001018}, {
Hans de Goede66344aa2009-12-09 20:35:59 +01001019 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
1020 show_pwm_auto_point_channel,
1021 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001022 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
1023 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1024 0, 0),
1025 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
1026 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1027 1, 0),
1028 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
1029 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1030 2, 0),
1031 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
1032 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1033 3, 0),
1034 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
1035 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1036 4, 0),
1037 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
1038 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1039 0, 0),
1040 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
1041 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1042 1, 0),
1043 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
1044 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1045 2, 0),
1046 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
1047 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1048 3, 0),
1049 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1050 show_pwm_auto_point_temp_hyst,
1051 store_pwm_auto_point_temp_hyst,
1052 0, 0),
1053 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
1054 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
1055 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
1056 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
1057 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
1058 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +02001059}, {
Hans de Goede66344aa2009-12-09 20:35:59 +01001060 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
1061 show_pwm_auto_point_channel,
1062 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001063 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
1064 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1065 0, 1),
1066 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
1067 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1068 1, 1),
1069 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
1070 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1071 2, 1),
1072 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
1073 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1074 3, 1),
1075 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
1076 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1077 4, 1),
1078 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
1079 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1080 0, 1),
1081 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
1082 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1083 1, 1),
1084 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
1085 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1086 2, 1),
1087 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
1088 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1089 3, 1),
1090 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1091 show_pwm_auto_point_temp_hyst,
1092 store_pwm_auto_point_temp_hyst,
1093 0, 1),
1094 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
1095 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
1096 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
1097 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
1098 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
1099 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +02001100} };
Hans de Goede45fb3662007-07-13 14:34:19 +02001101
1102/* Super I/O functions */
1103static inline int superio_inb(int base, int reg)
1104{
1105 outb(reg, base);
1106 return inb(base + 1);
1107}
1108
1109static int superio_inw(int base, int reg)
1110{
1111 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001112 val = superio_inb(base, reg) << 8;
1113 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001114 return val;
1115}
1116
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001117static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +02001118{
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001119 /* Don't step on other drivers' I/O space by accident */
1120 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +00001121 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001122 return -EBUSY;
1123 }
1124
Hans de Goede45fb3662007-07-13 14:34:19 +02001125 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001126 outb(SIO_UNLOCK_KEY, base);
1127 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001128
1129 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001130}
1131
Giel van Schijndel162bb592010-05-27 19:58:40 +02001132static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001133{
1134 outb(SIO_REG_LDSEL, base);
1135 outb(ld, base + 1);
1136}
1137
1138static inline void superio_exit(int base)
1139{
1140 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001141 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001142}
1143
Hans de Goede2f650632009-01-07 16:37:31 +01001144static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001145{
1146 return reg ? (1500000 / reg) : 0;
1147}
1148
Hans de Goede2f650632009-01-07 16:37:31 +01001149static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001150{
1151 return fan ? (1500000 / fan) : 0;
1152}
1153
Hans de Goede45fb3662007-07-13 14:34:19 +02001154static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1155{
1156 u8 val;
1157
1158 outb(reg, data->addr + ADDR_REG_OFFSET);
1159 val = inb(data->addr + DATA_REG_OFFSET);
1160
1161 return val;
1162}
1163
1164static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1165{
1166 u16 val;
1167
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001168 val = f71882fg_read8(data, reg) << 8;
1169 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001170
1171 return val;
1172}
1173
1174static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1175{
1176 outb(reg, data->addr + ADDR_REG_OFFSET);
1177 outb(val, data->addr + DATA_REG_OFFSET);
1178}
1179
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001180static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1181{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001182 f71882fg_write8(data, reg, val >> 8);
1183 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001184}
1185
Hans de Goede09475d32009-06-15 18:39:52 +02001186static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1187{
1188 if (data->type == f71858fg)
1189 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1190 else
1191 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1192}
1193
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001194static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001195{
1196 struct f71882fg_data *data = dev_get_drvdata(dev);
Jean Delvaref27def02011-03-26 10:45:01 +01001197 int nr_fans = f71882fg_nr_fans[data->type];
1198 int nr_temps = f71882fg_nr_temps[data->type];
Hans de Goedee5e713c2011-03-10 08:54:02 +01001199 int nr, reg, point;
Hans de Goede45fb3662007-07-13 14:34:19 +02001200
1201 mutex_lock(&data->update_lock);
1202
1203 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001204 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001205 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001206 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001207 data->in1_max =
1208 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1209 data->in_beep =
1210 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1211 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001212
1213 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001214 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1215 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001216 data->temp_ovt[nr] = f71882fg_read8(data,
1217 F71882FG_REG_TEMP_OVT(nr));
1218 data->temp_high[nr] = f71882fg_read8(data,
1219 F71882FG_REG_TEMP_HIGH(nr));
1220 }
1221
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001222 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001223 data->temp_hyst[0] = f71882fg_read8(data,
1224 F71882FG_REG_TEMP_HYST(0));
1225 data->temp_hyst[1] = f71882fg_read8(data,
1226 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001227 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001228 /* All but the f71858fg / f8000 have this register */
1229 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001230 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001231 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001232 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1233 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1234 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001235
Hans de Goede4d538112011-05-25 20:43:32 +02001236 if (f71882fg_fan_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001237 data->fan_beep = f71882fg_read8(data,
1238 F71882FG_REG_FAN_BEEP);
Hans de Goede4d538112011-05-25 20:43:32 +02001239
1240 if (f71882fg_temp_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001241 data->temp_beep = f71882fg_read8(data,
1242 F71882FG_REG_TEMP_BEEP);
Hans de Goede78aa4f72011-03-09 20:57:12 +01001243
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001244 data->pwm_enable = f71882fg_read8(data,
1245 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001246 data->pwm_auto_point_hyst[0] =
1247 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1248 data->pwm_auto_point_hyst[1] =
1249 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1250
Hans de Goede498be962009-01-07 16:37:28 +01001251 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001252 data->pwm_auto_point_mapping[nr] =
1253 f71882fg_read8(data,
1254 F71882FG_REG_POINT_MAPPING(nr));
1255
Hans de Goedee5e713c2011-03-10 08:54:02 +01001256 switch (data->type) {
1257 default:
Hans de Goede498be962009-01-07 16:37:28 +01001258 for (point = 0; point < 5; point++) {
1259 data->pwm_auto_point_pwm[nr][point] =
1260 f71882fg_read8(data,
1261 F71882FG_REG_POINT_PWM
1262 (nr, point));
1263 }
1264 for (point = 0; point < 4; point++) {
1265 data->pwm_auto_point_temp[nr][point] =
1266 f71882fg_read8(data,
1267 F71882FG_REG_POINT_TEMP
1268 (nr, point));
1269 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001270 break;
1271 case f71808e:
1272 case f71869:
1273 data->pwm_auto_point_pwm[nr][0] =
1274 f71882fg_read8(data,
1275 F71882FG_REG_POINT_PWM(nr, 0));
1276 /* Fall through */
1277 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001278 data->pwm_auto_point_pwm[nr][1] =
1279 f71882fg_read8(data,
1280 F71882FG_REG_POINT_PWM
1281 (nr, 1));
1282 data->pwm_auto_point_pwm[nr][4] =
1283 f71882fg_read8(data,
1284 F71882FG_REG_POINT_PWM
1285 (nr, 4));
1286 data->pwm_auto_point_temp[nr][0] =
1287 f71882fg_read8(data,
1288 F71882FG_REG_POINT_TEMP
1289 (nr, 0));
1290 data->pwm_auto_point_temp[nr][3] =
1291 f71882fg_read8(data,
1292 F71882FG_REG_POINT_TEMP
1293 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001294 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001295 }
1296 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001297 data->last_limits = jiffies;
1298 }
1299
1300 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001301 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001302 data->temp_status = f71882fg_read8(data,
1303 F71882FG_REG_TEMP_STATUS);
1304 data->temp_diode_open = f71882fg_read8(data,
1305 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001306 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1307 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001308 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001309
1310 data->fan_status = f71882fg_read8(data,
1311 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001312 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001313 data->fan[nr] = f71882fg_read16(data,
1314 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001315 data->fan_target[nr] =
1316 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1317 data->fan_full_speed[nr] =
1318 f71882fg_read16(data,
1319 F71882FG_REG_FAN_FULL_SPEED(nr));
1320 data->pwm[nr] =
1321 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1322 }
Hans de Goede629c58b2011-05-25 20:43:32 +02001323 /* Some models have 1 more fan with limited capabilities */
1324 if (data->type == f71808a) {
1325 data->fan[2] = f71882fg_read16(data,
1326 F71882FG_REG_FAN(2));
1327 data->pwm[2] = f71882fg_read8(data,
1328 F71882FG_REG_PWM(2));
1329 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001330 if (data->type == f8000)
1331 data->fan[3] = f71882fg_read16(data,
1332 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001333
1334 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001335 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001336 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001337 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1338 if (f71882fg_has_in[data->type][nr])
1339 data->in[nr] = f71882fg_read8(data,
1340 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001341
1342 data->last_updated = jiffies;
1343 data->valid = 1;
1344 }
1345
1346 mutex_unlock(&data->update_lock);
1347
1348 return data;
1349}
1350
1351/* Sysfs Interface */
1352static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1353 char *buf)
1354{
1355 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001356 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001357 int speed = fan_from_reg(data->fan[nr]);
1358
1359 if (speed == FAN_MIN_DETECT)
1360 speed = 0;
1361
1362 return sprintf(buf, "%d\n", speed);
1363}
1364
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001365static ssize_t show_fan_full_speed(struct device *dev,
1366 struct device_attribute *devattr, char *buf)
1367{
1368 struct f71882fg_data *data = f71882fg_update_device(dev);
1369 int nr = to_sensor_dev_attr_2(devattr)->index;
1370 int speed = fan_from_reg(data->fan_full_speed[nr]);
1371 return sprintf(buf, "%d\n", speed);
1372}
1373
1374static ssize_t store_fan_full_speed(struct device *dev,
1375 struct device_attribute *devattr,
1376 const char *buf, size_t count)
1377{
1378 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001379 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1380 long val;
1381
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001382 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001383 if (err)
1384 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001385
Guenter Roeck2a844c12013-01-09 08:09:34 -08001386 val = clamp_val(val, 23, 1500000);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001387 val = fan_to_reg(val);
1388
1389 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001390 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1391 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001392 mutex_unlock(&data->update_lock);
1393
1394 return count;
1395}
1396
Hans de Goede45fb3662007-07-13 14:34:19 +02001397static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1398 *devattr, char *buf)
1399{
1400 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001401 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001402
1403 if (data->fan_beep & (1 << nr))
1404 return sprintf(buf, "1\n");
1405 else
1406 return sprintf(buf, "0\n");
1407}
1408
1409static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1410 *devattr, const char *buf, size_t count)
1411{
1412 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001413 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1414 unsigned long val;
1415
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001416 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001417 if (err)
1418 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001419
1420 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001421 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001422 if (val)
1423 data->fan_beep |= 1 << nr;
1424 else
1425 data->fan_beep &= ~(1 << nr);
1426
1427 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1428 mutex_unlock(&data->update_lock);
1429
1430 return count;
1431}
1432
1433static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1434 *devattr, char *buf)
1435{
1436 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001437 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001438
1439 if (data->fan_status & (1 << nr))
1440 return sprintf(buf, "1\n");
1441 else
1442 return sprintf(buf, "0\n");
1443}
1444
1445static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1446 char *buf)
1447{
1448 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001449 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001450
1451 return sprintf(buf, "%d\n", data->in[nr] * 8);
1452}
1453
1454static ssize_t show_in_max(struct device *dev, struct device_attribute
1455 *devattr, char *buf)
1456{
1457 struct f71882fg_data *data = f71882fg_update_device(dev);
1458
1459 return sprintf(buf, "%d\n", data->in1_max * 8);
1460}
1461
1462static ssize_t store_in_max(struct device *dev, struct device_attribute
1463 *devattr, const char *buf, size_t count)
1464{
1465 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001466 int err;
1467 long val;
1468
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001469 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001470 if (err)
1471 return err;
1472
1473 val /= 8;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001474 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001475
1476 mutex_lock(&data->update_lock);
1477 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1478 data->in1_max = val;
1479 mutex_unlock(&data->update_lock);
1480
1481 return count;
1482}
1483
1484static ssize_t show_in_beep(struct device *dev, struct device_attribute
1485 *devattr, char *buf)
1486{
1487 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001488 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001489
1490 if (data->in_beep & (1 << nr))
1491 return sprintf(buf, "1\n");
1492 else
1493 return sprintf(buf, "0\n");
1494}
1495
1496static ssize_t store_in_beep(struct device *dev, struct device_attribute
1497 *devattr, const char *buf, size_t count)
1498{
1499 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001500 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1501 unsigned long val;
1502
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001503 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001504 if (err)
1505 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001506
1507 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001508 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001509 if (val)
1510 data->in_beep |= 1 << nr;
1511 else
1512 data->in_beep &= ~(1 << nr);
1513
1514 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1515 mutex_unlock(&data->update_lock);
1516
1517 return count;
1518}
1519
1520static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1521 *devattr, char *buf)
1522{
1523 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001524 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001525
1526 if (data->in_status & (1 << nr))
1527 return sprintf(buf, "1\n");
1528 else
1529 return sprintf(buf, "0\n");
1530}
1531
1532static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1533 char *buf)
1534{
1535 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001536 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001537 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001538
Hans de Goede09475d32009-06-15 18:39:52 +02001539 if (data->type == f71858fg) {
1540 /* TEMP_TABLE_SEL 1 or 3 ? */
1541 if (data->temp_config & 1) {
1542 sign = data->temp[nr] & 0x0001;
1543 temp = (data->temp[nr] >> 5) & 0x7ff;
1544 } else {
1545 sign = data->temp[nr] & 0x8000;
1546 temp = (data->temp[nr] >> 5) & 0x3ff;
1547 }
1548 temp *= 125;
1549 if (sign)
1550 temp -= 128000;
1551 } else
1552 temp = data->temp[nr] * 1000;
1553
1554 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001555}
1556
1557static ssize_t show_temp_max(struct device *dev, struct device_attribute
1558 *devattr, char *buf)
1559{
1560 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001561 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001562
1563 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1564}
1565
1566static ssize_t store_temp_max(struct device *dev, struct device_attribute
1567 *devattr, const char *buf, size_t count)
1568{
1569 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001570 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1571 long val;
1572
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001573 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001574 if (err)
1575 return err;
1576
1577 val /= 1000;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001578 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001579
1580 mutex_lock(&data->update_lock);
1581 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1582 data->temp_high[nr] = val;
1583 mutex_unlock(&data->update_lock);
1584
1585 return count;
1586}
1587
1588static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1589 *devattr, char *buf)
1590{
1591 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001592 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001593 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001594
Hans de Goedece0bfa52009-01-07 16:37:28 +01001595 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001596 if (nr & 1)
1597 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1598 else
1599 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1600 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001601 mutex_unlock(&data->update_lock);
1602
1603 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001604}
1605
1606static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1607 *devattr, const char *buf, size_t count)
1608{
1609 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001610 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001611 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001612 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001613 long val;
1614
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001615 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001616 if (err)
1617 return err;
1618
1619 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001620
1621 mutex_lock(&data->update_lock);
1622
1623 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001624 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
Guenter Roeck2a844c12013-01-09 08:09:34 -08001625 val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001626 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001627
1628 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001629 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1630 if (nr & 1)
1631 reg = (reg & 0x0f) | (val << 4);
1632 else
1633 reg = (reg & 0xf0) | val;
1634 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1635 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001636
Hans de Goede45fb3662007-07-13 14:34:19 +02001637 mutex_unlock(&data->update_lock);
1638 return ret;
1639}
1640
1641static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1642 *devattr, char *buf)
1643{
1644 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001645 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001646
1647 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1648}
1649
1650static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1651 *devattr, const char *buf, size_t count)
1652{
1653 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001654 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1655 long val;
1656
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001657 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001658 if (err)
1659 return err;
1660
1661 val /= 1000;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001662 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001663
1664 mutex_lock(&data->update_lock);
1665 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1666 data->temp_ovt[nr] = val;
1667 mutex_unlock(&data->update_lock);
1668
1669 return count;
1670}
1671
1672static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1673 *devattr, char *buf)
1674{
1675 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001676 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001677 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001678
Hans de Goedece0bfa52009-01-07 16:37:28 +01001679 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001680 if (nr & 1)
1681 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1682 else
1683 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1684 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001685 mutex_unlock(&data->update_lock);
1686
1687 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001688}
1689
1690static ssize_t show_temp_type(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
1696 return sprintf(buf, "%d\n", data->temp_type[nr]);
1697}
1698
1699static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1700 *devattr, char *buf)
1701{
1702 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001703 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001704
Hans de Goede7567a042009-01-07 16:37:28 +01001705 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001706 return sprintf(buf, "1\n");
1707 else
1708 return sprintf(buf, "0\n");
1709}
1710
1711static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1712 *devattr, const char *buf, size_t count)
1713{
1714 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001715 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1716 unsigned long val;
1717
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001718 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001719 if (err)
1720 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001721
1722 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001723 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001724 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001725 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001726 else
Hans de Goede7567a042009-01-07 16:37:28 +01001727 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001728
1729 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1730 mutex_unlock(&data->update_lock);
1731
1732 return count;
1733}
1734
1735static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1736 *devattr, char *buf)
1737{
1738 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001739 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001740
Hans de Goede7567a042009-01-07 16:37:28 +01001741 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001742 return sprintf(buf, "1\n");
1743 else
1744 return sprintf(buf, "0\n");
1745}
1746
1747static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1748 *devattr, char *buf)
1749{
1750 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001751 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001752
Hans de Goede7567a042009-01-07 16:37:28 +01001753 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001754 return sprintf(buf, "1\n");
1755 else
1756 return sprintf(buf, "0\n");
1757}
1758
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001759static ssize_t show_pwm(struct device *dev,
1760 struct device_attribute *devattr, char *buf)
1761{
1762 struct f71882fg_data *data = f71882fg_update_device(dev);
1763 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001764 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001765 if (data->pwm_enable & (1 << (2 * nr)))
1766 /* PWM mode */
1767 val = data->pwm[nr];
1768 else {
1769 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001770 val = 255 * fan_from_reg(data->fan_target[nr])
1771 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001772 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001773 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001774 return sprintf(buf, "%d\n", val);
1775}
1776
1777static ssize_t store_pwm(struct device *dev,
1778 struct device_attribute *devattr, const char *buf,
1779 size_t count)
1780{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001781 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001782 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1783 long val;
1784
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001785 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001786 if (err)
1787 return err;
1788
Guenter Roeck2a844c12013-01-09 08:09:34 -08001789 val = clamp_val(val, 0, 255);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001790
1791 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001792 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001793 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1794 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1795 count = -EROFS;
1796 goto leave;
1797 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001798 if (data->pwm_enable & (1 << (2 * nr))) {
1799 /* PWM mode */
1800 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1801 data->pwm[nr] = val;
1802 } else {
1803 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001804 int target, full_speed;
1805 full_speed = f71882fg_read16(data,
1806 F71882FG_REG_FAN_FULL_SPEED(nr));
1807 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1808 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1809 data->fan_target[nr] = target;
1810 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001811 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001812leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001813 mutex_unlock(&data->update_lock);
1814
1815 return count;
1816}
1817
Hans de Goede629c58b2011-05-25 20:43:32 +02001818static ssize_t show_simple_pwm(struct device *dev,
1819 struct device_attribute *devattr, char *buf)
1820{
1821 struct f71882fg_data *data = f71882fg_update_device(dev);
1822 int val, nr = to_sensor_dev_attr_2(devattr)->index;
1823
1824 val = data->pwm[nr];
1825 return sprintf(buf, "%d\n", val);
1826}
1827
1828static ssize_t store_simple_pwm(struct device *dev,
1829 struct device_attribute *devattr,
1830 const char *buf, size_t count)
1831{
1832 struct f71882fg_data *data = dev_get_drvdata(dev);
1833 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1834 long val;
1835
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001836 err = kstrtol(buf, 10, &val);
Hans de Goede629c58b2011-05-25 20:43:32 +02001837 if (err)
1838 return err;
1839
Guenter Roeck2a844c12013-01-09 08:09:34 -08001840 val = clamp_val(val, 0, 255);
Hans de Goede629c58b2011-05-25 20:43:32 +02001841
1842 mutex_lock(&data->update_lock);
1843 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1844 data->pwm[nr] = val;
1845 mutex_unlock(&data->update_lock);
1846
1847 return count;
1848}
1849
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001850static ssize_t show_pwm_enable(struct device *dev,
1851 struct device_attribute *devattr, char *buf)
1852{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001853 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001854 struct f71882fg_data *data = f71882fg_update_device(dev);
1855 int nr = to_sensor_dev_attr_2(devattr)->index;
1856
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001857 switch ((data->pwm_enable >> 2 * nr) & 3) {
1858 case 0:
1859 case 1:
1860 result = 2; /* Normal auto mode */
1861 break;
1862 case 2:
1863 result = 1; /* Manual mode */
1864 break;
1865 case 3:
1866 if (data->type == f8000)
1867 result = 3; /* Thermostat mode */
1868 else
1869 result = 1; /* Manual mode */
1870 break;
1871 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001872
1873 return sprintf(buf, "%d\n", result);
1874}
1875
1876static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1877 *devattr, const char *buf, size_t count)
1878{
1879 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001880 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1881 long val;
1882
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001883 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001884 if (err)
1885 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001886
Hans de Goede3fc78382009-06-15 18:39:50 +02001887 /* Special case for F8000 pwm channel 3 which only does auto mode */
1888 if (data->type == f8000 && nr == 2 && val != 2)
1889 return -EINVAL;
1890
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001891 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001892 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001893 /* Special case for F8000 auto PWM mode / Thermostat mode */
1894 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1895 switch (val) {
1896 case 2:
1897 data->pwm_enable &= ~(2 << (2 * nr));
1898 break; /* Normal auto mode */
1899 case 3:
1900 data->pwm_enable |= 2 << (2 * nr);
1901 break; /* Thermostat mode */
1902 default:
1903 count = -EINVAL;
1904 goto leave;
1905 }
1906 } else {
1907 switch (val) {
1908 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001909 /* The f71858fg does not support manual RPM mode */
1910 if (data->type == f71858fg &&
1911 ((data->pwm_enable >> (2 * nr)) & 1)) {
1912 count = -EINVAL;
1913 goto leave;
1914 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001915 data->pwm_enable |= 2 << (2 * nr);
1916 break; /* Manual */
1917 case 2:
1918 data->pwm_enable &= ~(2 << (2 * nr));
1919 break; /* Normal auto mode */
1920 default:
1921 count = -EINVAL;
1922 goto leave;
1923 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001924 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001925 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001926leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001927 mutex_unlock(&data->update_lock);
1928
1929 return count;
1930}
1931
1932static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1933 struct device_attribute *devattr,
1934 char *buf)
1935{
1936 int result;
1937 struct f71882fg_data *data = f71882fg_update_device(dev);
1938 int pwm = to_sensor_dev_attr_2(devattr)->index;
1939 int point = to_sensor_dev_attr_2(devattr)->nr;
1940
Hans de Goedece0bfa52009-01-07 16:37:28 +01001941 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001942 if (data->pwm_enable & (1 << (2 * pwm))) {
1943 /* PWM mode */
1944 result = data->pwm_auto_point_pwm[pwm][point];
1945 } else {
1946 /* RPM mode */
1947 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1948 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001949 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001950
1951 return sprintf(buf, "%d\n", result);
1952}
1953
1954static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1955 struct device_attribute *devattr,
1956 const char *buf, size_t count)
1957{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001958 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001959 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001960 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001961 long val;
1962
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001963 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001964 if (err)
1965 return err;
1966
Guenter Roeck2a844c12013-01-09 08:09:34 -08001967 val = clamp_val(val, 0, 255);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001968
1969 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001970 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001971 if (data->pwm_enable & (1 << (2 * pwm))) {
1972 /* PWM mode */
1973 } else {
1974 /* RPM mode */
1975 if (val < 29) /* Prevent negative numbers */
1976 val = 255;
1977 else
1978 val = (255 - val) * 32 / val;
1979 }
1980 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1981 data->pwm_auto_point_pwm[pwm][point] = val;
1982 mutex_unlock(&data->update_lock);
1983
1984 return count;
1985}
1986
1987static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1988 struct device_attribute *devattr,
1989 char *buf)
1990{
1991 int result = 0;
1992 struct f71882fg_data *data = f71882fg_update_device(dev);
1993 int nr = to_sensor_dev_attr_2(devattr)->index;
1994 int point = to_sensor_dev_attr_2(devattr)->nr;
1995
1996 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001997 if (nr & 1)
1998 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1999 else
2000 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002001 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
2002 mutex_unlock(&data->update_lock);
2003
2004 return sprintf(buf, "%d\n", result);
2005}
2006
2007static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
2008 struct device_attribute *devattr,
2009 const char *buf, size_t count)
2010{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002011 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002012 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002013 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01002014 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002015 long val;
2016
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002017 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002018 if (err)
2019 return err;
2020
2021 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002022
2023 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002024 data->pwm_auto_point_temp[nr][point] =
2025 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Guenter Roeck2a844c12013-01-09 08:09:34 -08002026 val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
2027 data->pwm_auto_point_temp[nr][point]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002028 val = data->pwm_auto_point_temp[nr][point] - val;
2029
Hans de Goedebc274902009-01-07 16:37:29 +01002030 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
2031 if (nr & 1)
2032 reg = (reg & 0x0f) | (val << 4);
2033 else
2034 reg = (reg & 0xf0) | val;
2035
2036 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
2037 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002038 mutex_unlock(&data->update_lock);
2039
2040 return count;
2041}
2042
2043static ssize_t show_pwm_interpolate(struct device *dev,
2044 struct device_attribute *devattr, char *buf)
2045{
2046 int result;
2047 struct f71882fg_data *data = f71882fg_update_device(dev);
2048 int nr = to_sensor_dev_attr_2(devattr)->index;
2049
2050 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
2051
2052 return sprintf(buf, "%d\n", result);
2053}
2054
2055static ssize_t store_pwm_interpolate(struct device *dev,
2056 struct device_attribute *devattr,
2057 const char *buf, size_t count)
2058{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002059 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002060 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2061 unsigned long val;
2062
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002063 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002064 if (err)
2065 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01002066
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002067 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002068 data->pwm_auto_point_mapping[nr] =
2069 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002070 if (val)
2071 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
2072 else
2073 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
2074 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2075 data->pwm_auto_point_mapping[nr] = val;
2076 mutex_unlock(&data->update_lock);
2077
2078 return count;
2079}
2080
2081static ssize_t show_pwm_auto_point_channel(struct device *dev,
2082 struct device_attribute *devattr,
2083 char *buf)
2084{
2085 int result;
2086 struct f71882fg_data *data = f71882fg_update_device(dev);
2087 int nr = to_sensor_dev_attr_2(devattr)->index;
2088
Hans de Goede09475d32009-06-15 18:39:52 +02002089 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
2090 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002091
2092 return sprintf(buf, "%d\n", result);
2093}
2094
2095static ssize_t store_pwm_auto_point_channel(struct device *dev,
2096 struct device_attribute *devattr,
2097 const char *buf, size_t count)
2098{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002099 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002100 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2101 long val;
2102
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002103 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002104 if (err)
2105 return err;
Hans de Goede30453012009-01-07 16:37:30 +01002106
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002107 switch (val) {
2108 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01002109 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002110 break;
2111 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01002112 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002113 break;
2114 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01002115 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002116 break;
2117 default:
2118 return -EINVAL;
2119 }
Hans de Goede09475d32009-06-15 18:39:52 +02002120 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002121 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002122 data->pwm_auto_point_mapping[nr] =
2123 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002124 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
2125 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2126 data->pwm_auto_point_mapping[nr] = val;
2127 mutex_unlock(&data->update_lock);
2128
2129 return count;
2130}
2131
2132static ssize_t show_pwm_auto_point_temp(struct device *dev,
2133 struct device_attribute *devattr,
2134 char *buf)
2135{
2136 int result;
2137 struct f71882fg_data *data = f71882fg_update_device(dev);
2138 int pwm = to_sensor_dev_attr_2(devattr)->index;
2139 int point = to_sensor_dev_attr_2(devattr)->nr;
2140
2141 result = data->pwm_auto_point_temp[pwm][point];
2142 return sprintf(buf, "%d\n", 1000 * result);
2143}
2144
2145static ssize_t store_pwm_auto_point_temp(struct device *dev,
2146 struct device_attribute *devattr,
2147 const char *buf, size_t count)
2148{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002149 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002150 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002151 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002152 long val;
2153
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002154 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002155 if (err)
2156 return err;
2157
2158 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01002159
Hans de Goede98f7ba12011-03-09 20:57:09 +01002160 if (data->auto_point_temp_signed)
Guenter Roeck2a844c12013-01-09 08:09:34 -08002161 val = clamp_val(val, -128, 127);
Hans de Goede76698962009-12-09 20:36:01 +01002162 else
Guenter Roeck2a844c12013-01-09 08:09:34 -08002163 val = clamp_val(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002164
2165 mutex_lock(&data->update_lock);
2166 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2167 data->pwm_auto_point_temp[pwm][point] = val;
2168 mutex_unlock(&data->update_lock);
2169
2170 return count;
2171}
2172
Hans de Goede45fb3662007-07-13 14:34:19 +02002173static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2174 char *buf)
2175{
Hans de Goede498be962009-01-07 16:37:28 +01002176 struct f71882fg_data *data = dev_get_drvdata(dev);
2177 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002178}
2179
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002180static int f71882fg_create_sysfs_files(struct platform_device *pdev,
Hans de Goedec13548c2009-01-07 16:37:27 +01002181 struct sensor_device_attribute_2 *attr, int count)
2182{
2183 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002184
Hans de Goedec13548c2009-01-07 16:37:27 +01002185 for (i = 0; i < count; i++) {
2186 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2187 if (err)
2188 return err;
2189 }
2190 return 0;
2191}
2192
Hans de Goedefc16c562009-12-09 20:36:01 +01002193static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2194 struct sensor_device_attribute_2 *attr, int count)
2195{
2196 int i;
2197
2198 for (i = 0; i < count; i++)
2199 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2200}
2201
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002202static int f71882fg_create_fan_sysfs_files(
Hans de Goede65434392011-09-09 12:12:35 +02002203 struct platform_device *pdev, int idx)
Hans de Goede9af07942011-09-09 12:12:34 +02002204{
2205 struct f71882fg_data *data = platform_get_drvdata(pdev);
2206 int err;
2207
Hans de Goede65434392011-09-09 12:12:35 +02002208 /* Sanity check the pwm setting */
2209 err = 0;
2210 switch (data->type) {
2211 case f71858fg:
2212 if (((data->pwm_enable >> (idx * 2)) & 3) == 3)
2213 err = 1;
2214 break;
2215 case f71862fg:
2216 if (((data->pwm_enable >> (idx * 2)) & 1) != 1)
2217 err = 1;
2218 break;
2219 case f8000:
2220 if (idx == 2)
2221 err = data->pwm_enable & 0x20;
2222 break;
2223 default:
2224 break;
2225 }
2226 if (err) {
2227 dev_err(&pdev->dev,
2228 "Invalid (reserved) pwm settings: 0x%02x, "
2229 "skipping fan %d\n",
2230 (data->pwm_enable >> (idx * 2)) & 3, idx + 1);
2231 return 0; /* This is a non fatal condition */
2232 }
2233
Hans de Goede9af07942011-09-09 12:12:34 +02002234 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[idx][0],
2235 ARRAY_SIZE(fxxxx_fan_attr[0]));
2236 if (err)
2237 return err;
2238
2239 if (f71882fg_fan_has_beep[data->type]) {
2240 err = f71882fg_create_sysfs_files(pdev,
2241 &fxxxx_fan_beep_attr[idx],
2242 1);
2243 if (err)
2244 return err;
2245 }
2246
Hans de Goede65434392011-09-09 12:12:35 +02002247 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", idx + 1,
2248 (data->pwm_enable & (1 << (2 * idx))) ? "duty-cycle" : "RPM");
2249
2250 /* Check for unsupported auto pwm settings */
2251 switch (data->type) {
2252 case f71808e:
2253 case f71808a:
2254 case f71869:
2255 case f71869a:
2256 case f71889fg:
2257 case f71889ed:
2258 case f71889a:
2259 data->pwm_auto_point_mapping[idx] =
2260 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(idx));
2261 if ((data->pwm_auto_point_mapping[idx] & 0x80) ||
2262 (data->pwm_auto_point_mapping[idx] & 3) == 0) {
2263 dev_warn(&pdev->dev,
2264 "Auto pwm controlled by raw digital "
2265 "data, disabling pwm auto_point "
2266 "sysfs attributes for fan %d\n", idx + 1);
2267 return 0; /* This is a non fatal condition */
2268 }
2269 break;
2270 default:
2271 break;
2272 }
Hans de Goede9af07942011-09-09 12:12:34 +02002273
2274 switch (data->type) {
2275 case f71862fg:
2276 err = f71882fg_create_sysfs_files(pdev,
2277 &f71862fg_auto_pwm_attr[idx][0],
2278 ARRAY_SIZE(f71862fg_auto_pwm_attr[0]));
2279 break;
2280 case f71808e:
2281 case f71869:
2282 err = f71882fg_create_sysfs_files(pdev,
2283 &f71869_auto_pwm_attr[idx][0],
2284 ARRAY_SIZE(f71869_auto_pwm_attr[0]));
2285 break;
2286 case f8000:
2287 err = f71882fg_create_sysfs_files(pdev,
2288 &f8000_auto_pwm_attr[idx][0],
2289 ARRAY_SIZE(f8000_auto_pwm_attr[0]));
2290 break;
2291 default:
2292 err = f71882fg_create_sysfs_files(pdev,
2293 &fxxxx_auto_pwm_attr[idx][0],
2294 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]));
2295 }
2296
2297 return err;
2298}
2299
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002300static int f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002301{
2302 struct f71882fg_data *data;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09002303 struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
Jean Delvaref27def02011-03-26 10:45:01 +01002304 int nr_fans = f71882fg_nr_fans[sio_data->type];
2305 int nr_temps = f71882fg_nr_temps[sio_data->type];
2306 int err, i;
Peter Hungdcd956f2015-07-07 16:22:37 +08002307 int size;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002308 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002309
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002310 data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
2311 GFP_KERNEL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002312 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002313 return -ENOMEM;
2314
2315 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002316 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002317 data->temp_start =
Peter Hungdcd956f2015-07-07 16:22:37 +08002318 (data->type == f71858fg || data->type == f8000 ||
2319 data->type == f81866a) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002320 mutex_init(&data->update_lock);
2321 platform_set_drvdata(pdev, data);
2322
Hans de Goede3cc74752009-01-07 16:37:28 +01002323 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002324 if (start_reg & 0x04) {
2325 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002326 return -ENODEV;
Hans de Goede12d66e82009-01-07 16:37:29 +01002327 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002328 if (!(start_reg & 0x03)) {
2329 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002330 return -ENODEV;
Hans de Goede3cc74752009-01-07 16:37:28 +01002331 }
2332
Hans de Goede45fb3662007-07-13 14:34:19 +02002333 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002334 err = device_create_file(&pdev->dev, &dev_attr_name);
2335 if (err)
2336 goto exit_unregister_sysfs;
2337
Hans de Goedec13548c2009-01-07 16:37:27 +01002338 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002339 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002340 case f71858fg:
2341 data->temp_config =
2342 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2343 if (data->temp_config & 0x10)
Guenter Roeck20eaf722012-01-19 11:02:17 -08002344 /*
2345 * The f71858fg temperature alarms behave as
2346 * the f8000 alarms in this mode
2347 */
Hans de Goede09475d32009-06-15 18:39:52 +02002348 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002349 f8000_temp_attr,
2350 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002351 else
2352 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002353 f71858fg_temp_attr,
2354 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002355 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002356 case f8000:
2357 err = f71882fg_create_sysfs_files(pdev,
2358 f8000_temp_attr,
2359 ARRAY_SIZE(f8000_temp_attr));
2360 break;
Peter Hungdcd956f2015-07-07 16:22:37 +08002361 case f81866a:
2362 err = f71882fg_create_sysfs_files(pdev,
2363 f71858fg_temp_attr,
2364 ARRAY_SIZE(f71858fg_temp_attr));
2365 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002366 default:
2367 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002368 &fxxxx_temp_attr[0][0],
2369 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002370 }
2371 if (err)
2372 goto exit_unregister_sysfs;
2373
Hans de Goede4d538112011-05-25 20:43:32 +02002374 if (f71882fg_temp_has_beep[data->type]) {
Peter Hungdcd956f2015-07-07 16:22:37 +08002375 if (data->type == f81866a) {
2376 size = ARRAY_SIZE(f81866_temp_beep_attr[0]);
2377 err = f71882fg_create_sysfs_files(pdev,
2378 &f81866_temp_beep_attr[0][0],
2379 size * nr_temps);
2380
2381 } else {
2382 size = ARRAY_SIZE(fxxxx_temp_beep_attr[0]);
2383 err = f71882fg_create_sysfs_files(pdev,
2384 &fxxxx_temp_beep_attr[0][0],
2385 size * nr_temps);
2386 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01002387 if (err)
2388 goto exit_unregister_sysfs;
2389 }
2390
Hans de Goede0bae6402011-03-09 20:57:10 +01002391 for (i = 0; i < F71882FG_MAX_INS; i++) {
2392 if (f71882fg_has_in[data->type][i]) {
2393 err = device_create_file(&pdev->dev,
2394 &fxxxx_in_attr[i].dev_attr);
2395 if (err)
2396 goto exit_unregister_sysfs;
2397 }
2398 }
2399 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002400 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002401 fxxxx_in1_alarm_attr,
2402 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002403 if (err)
2404 goto exit_unregister_sysfs;
2405 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002406 }
2407
Hans de Goede45fb3662007-07-13 14:34:19 +02002408 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002409 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002410 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002411 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002412 case f71869:
Hans de Goede5da556e2011-07-03 13:32:53 +02002413 case f71869a:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002414 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002415 data->auto_point_temp_signed = 1;
2416 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002417 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002418 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002419 case f71889a:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002420 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2421 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2422 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002423 /* Ensure banked pwm registers point to right bank */
2424 reg &= ~F71882FG_FAN_PROG_SEL;
2425 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002426 break;
2427 default:
2428 break;
2429 }
2430
Hans de Goede996cadb2009-06-15 18:39:51 +02002431 data->pwm_enable =
2432 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2433
Hans de Goede9af07942011-09-09 12:12:34 +02002434 for (i = 0; i < nr_fans; i++) {
Hans de Goede65434392011-09-09 12:12:35 +02002435 err = f71882fg_create_fan_sysfs_files(pdev, i);
Hans de Goede9af07942011-09-09 12:12:34 +02002436 if (err)
2437 goto exit_unregister_sysfs;
Hans de Goede9af07942011-09-09 12:12:34 +02002438 }
2439
2440 /* Some types have 1 extra fan with limited functionality */
Hans de Goedee48a7f12011-03-09 20:57:13 +01002441 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002442 case f71808a:
2443 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede629c58b2011-05-25 20:43:32 +02002444 f71808a_fan3_attr,
2445 ARRAY_SIZE(f71808a_fan3_attr));
2446 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002447 case f8000:
2448 err = f71882fg_create_sysfs_files(pdev,
2449 f8000_fan_attr,
2450 ARRAY_SIZE(f8000_fan_attr));
2451 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002452 default:
Hans de Goede9af07942011-09-09 12:12:34 +02002453 break;
Hans de Goede498be962009-01-07 16:37:28 +01002454 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002455 if (err)
2456 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02002457 }
2458
Tony Jones1beeffe2007-08-20 13:46:20 -07002459 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2460 if (IS_ERR(data->hwmon_dev)) {
2461 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002462 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002463 goto exit_unregister_sysfs;
2464 }
2465
2466 return 0;
2467
2468exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002469 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002470 return err; /* f71882fg_remove() also frees our data */
Hans de Goede45fb3662007-07-13 14:34:19 +02002471}
2472
Hans de Goedec13548c2009-01-07 16:37:27 +01002473static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002474{
Hans de Goede45fb3662007-07-13 14:34:19 +02002475 struct f71882fg_data *data = platform_get_drvdata(pdev);
Jean Delvaref27def02011-03-26 10:45:01 +01002476 int nr_fans = f71882fg_nr_fans[data->type];
2477 int nr_temps = f71882fg_nr_temps[data->type];
2478 int i;
Hans de Goedefc16c562009-12-09 20:36:01 +01002479 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002480
Hans de Goedec13548c2009-01-07 16:37:27 +01002481 if (data->hwmon_dev)
2482 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002483
Hans de Goedec13548c2009-01-07 16:37:27 +01002484 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002485
Hans de Goedefc16c562009-12-09 20:36:01 +01002486 if (start_reg & 0x01) {
2487 switch (data->type) {
2488 case f71858fg:
2489 if (data->temp_config & 0x10)
2490 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002491 f8000_temp_attr,
2492 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002493 else
2494 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002495 f71858fg_temp_attr,
2496 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002497 break;
2498 case f8000:
2499 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002500 f8000_temp_attr,
2501 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002502 break;
Peter Hungdcd956f2015-07-07 16:22:37 +08002503 case f81866a:
2504 f71882fg_remove_sysfs_files(pdev,
2505 f71858fg_temp_attr,
2506 ARRAY_SIZE(f71858fg_temp_attr));
2507 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002508 default:
2509 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002510 &fxxxx_temp_attr[0][0],
2511 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002512 }
Hans de Goede4d538112011-05-25 20:43:32 +02002513 if (f71882fg_temp_has_beep[data->type]) {
Peter Hungdcd956f2015-07-07 16:22:37 +08002514 if (data->type == f81866a)
2515 f71882fg_remove_sysfs_files(pdev,
2516 &f81866_temp_beep_attr[0][0],
2517 ARRAY_SIZE(f81866_temp_beep_attr[0])
2518 * nr_temps);
2519 else
2520 f71882fg_remove_sysfs_files(pdev,
2521 &fxxxx_temp_beep_attr[0][0],
2522 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2523 * nr_temps);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002524 }
2525
Hans de Goede0bae6402011-03-09 20:57:10 +01002526 for (i = 0; i < F71882FG_MAX_INS; i++) {
2527 if (f71882fg_has_in[data->type][i]) {
2528 device_remove_file(&pdev->dev,
2529 &fxxxx_in_attr[i].dev_attr);
2530 }
2531 }
2532 if (f71882fg_has_in1_alarm[data->type]) {
2533 f71882fg_remove_sysfs_files(pdev,
2534 fxxxx_in1_alarm_attr,
2535 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002536 }
2537 }
Hans de Goede498be962009-01-07 16:37:28 +01002538
Hans de Goedefc16c562009-12-09 20:36:01 +01002539 if (start_reg & 0x02) {
2540 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2541 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002542
Hans de Goede4d538112011-05-25 20:43:32 +02002543 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002544 f71882fg_remove_sysfs_files(pdev,
2545 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002546 }
Hans de Goede498be962009-01-07 16:37:28 +01002547
Hans de Goedefc16c562009-12-09 20:36:01 +01002548 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002549 case f71808a:
2550 f71882fg_remove_sysfs_files(pdev,
2551 &fxxxx_auto_pwm_attr[0][0],
2552 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2553 f71882fg_remove_sysfs_files(pdev,
2554 f71808a_fan3_attr,
2555 ARRAY_SIZE(f71808a_fan3_attr));
2556 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002557 case f71862fg:
2558 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002559 &f71862fg_auto_pwm_attr[0][0],
2560 ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) *
2561 nr_fans);
Hans de Goedefc16c562009-12-09 20:36:01 +01002562 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002563 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002564 case f71869:
2565 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002566 &f71869_auto_pwm_attr[0][0],
2567 ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans);
Hans de Goedec11bb992011-03-09 20:57:15 +01002568 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002569 case f8000:
2570 f71882fg_remove_sysfs_files(pdev,
2571 f8000_fan_attr,
2572 ARRAY_SIZE(f8000_fan_attr));
2573 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002574 &f8000_auto_pwm_attr[0][0],
2575 ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans);
Hans de Goedefc16c562009-12-09 20:36:01 +01002576 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002577 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002578 f71882fg_remove_sysfs_files(pdev,
2579 &fxxxx_auto_pwm_attr[0][0],
2580 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2581 }
2582 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002583 return 0;
2584}
2585
Guenter Roeck00383892012-08-04 09:46:36 -07002586static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002587{
Hans de Goede45fb3662007-07-13 14:34:19 +02002588 u16 devid;
Guenter Roeck00383892012-08-04 09:46:36 -07002589 unsigned short address;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002590 int err = superio_enter(sioaddr);
2591 if (err)
2592 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002593
2594 devid = superio_inw(sioaddr, SIO_REG_MANID);
2595 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002596 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002597 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002598 goto exit;
2599 }
2600
Jean Delvare67b671b2007-12-06 23:13:42 +01002601 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002602 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002603 case SIO_F71808E_ID:
2604 sio_data->type = f71808e;
2605 break;
Hans de Goede629c58b2011-05-25 20:43:32 +02002606 case SIO_F71808A_ID:
2607 sio_data->type = f71808a;
2608 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002609 case SIO_F71858_ID:
2610 sio_data->type = f71858fg;
2611 break;
Hans de Goede498be962009-01-07 16:37:28 +01002612 case SIO_F71862_ID:
2613 sio_data->type = f71862fg;
2614 break;
Peter Hung2725fe22015-07-07 16:22:36 +08002615 case SIO_F71868_ID:
2616 sio_data->type = f71868a;
2617 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002618 case SIO_F71869_ID:
2619 sio_data->type = f71869;
2620 break;
Hans de Goede5da556e2011-07-03 13:32:53 +02002621 case SIO_F71869A_ID:
2622 sio_data->type = f71869a;
2623 break;
Hans de Goede498be962009-01-07 16:37:28 +01002624 case SIO_F71882_ID:
2625 sio_data->type = f71882fg;
2626 break;
Hans de Goede76698962009-12-09 20:36:01 +01002627 case SIO_F71889_ID:
2628 sio_data->type = f71889fg;
2629 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002630 case SIO_F71889E_ID:
2631 sio_data->type = f71889ed;
2632 break;
Hans de Goedea66c1082011-03-26 10:45:02 +01002633 case SIO_F71889A_ID:
2634 sio_data->type = f71889a;
2635 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002636 case SIO_F8000_ID:
2637 sio_data->type = f8000;
2638 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002639 case SIO_F81865_ID:
2640 sio_data->type = f81865f;
2641 break;
Peter Hung2725fe22015-07-07 16:22:36 +08002642 case SIO_F81866_ID:
2643 sio_data->type = f81866a;
2644 break;
Hans de Goede498be962009-01-07 16:37:28 +01002645 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002646 pr_info("Unsupported Fintek device: %04x\n",
2647 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002648 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002649 goto exit;
2650 }
2651
Hans de Goede09475d32009-06-15 18:39:52 +02002652 if (sio_data->type == f71858fg)
2653 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2654 else
2655 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2656
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002657 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002658 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002659 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002660 goto exit;
2661 }
2662
Guenter Roeck00383892012-08-04 09:46:36 -07002663 address = superio_inw(sioaddr, SIO_REG_ADDR);
2664 if (address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002665 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002666 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002667 goto exit;
2668 }
Guenter Roeck00383892012-08-04 09:46:36 -07002669 address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
Hans de Goede45fb3662007-07-13 14:34:19 +02002670
Guenter Roeck00383892012-08-04 09:46:36 -07002671 err = address;
Joe Perches22d3b412010-10-20 06:51:34 +00002672 pr_info("Found %s chip at %#x, revision %d\n",
Guenter Roeck00383892012-08-04 09:46:36 -07002673 f71882fg_names[sio_data->type], (unsigned int)address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002674 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2675exit:
2676 superio_exit(sioaddr);
2677 return err;
2678}
2679
Guenter Roeck00383892012-08-04 09:46:36 -07002680static int __init f71882fg_device_add(int address,
2681 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002682{
2683 struct resource res = {
2684 .start = address,
2685 .end = address + REGION_LENGTH - 1,
2686 .flags = IORESOURCE_IO,
2687 };
2688 int err;
2689
2690 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002691 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002692 return -ENOMEM;
2693
2694 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002695 err = acpi_check_resource_conflict(&res);
2696 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002697 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002698
Hans de Goede45fb3662007-07-13 14:34:19 +02002699 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002700 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002701 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002702 goto exit_device_put;
2703 }
2704
Hans de Goede498be962009-01-07 16:37:28 +01002705 err = platform_device_add_data(f71882fg_pdev, sio_data,
2706 sizeof(struct f71882fg_sio_data));
2707 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002708 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002709 goto exit_device_put;
2710 }
2711
Hans de Goede45fb3662007-07-13 14:34:19 +02002712 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002713 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002714 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002715 goto exit_device_put;
2716 }
2717
2718 return 0;
2719
2720exit_device_put:
2721 platform_device_put(f71882fg_pdev);
2722
2723 return err;
2724}
2725
2726static int __init f71882fg_init(void)
2727{
Guenter Roeck00383892012-08-04 09:46:36 -07002728 int err;
2729 int address;
Hans de Goede498be962009-01-07 16:37:28 +01002730 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002731
Hans de Goede498be962009-01-07 16:37:28 +01002732 memset(&sio_data, 0, sizeof(sio_data));
2733
Guenter Roeck00383892012-08-04 09:46:36 -07002734 address = f71882fg_find(0x2e, &sio_data);
2735 if (address < 0)
2736 address = f71882fg_find(0x4e, &sio_data);
2737 if (address < 0)
2738 return address;
Hans de Goede45fb3662007-07-13 14:34:19 +02002739
Hans de Goedec13548c2009-01-07 16:37:27 +01002740 err = platform_driver_register(&f71882fg_driver);
2741 if (err)
Guenter Roeck00383892012-08-04 09:46:36 -07002742 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002743
Hans de Goede498be962009-01-07 16:37:28 +01002744 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002745 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002746 goto exit_driver;
2747
2748 return 0;
2749
2750exit_driver:
2751 platform_driver_unregister(&f71882fg_driver);
Hans de Goede45fb3662007-07-13 14:34:19 +02002752 return err;
2753}
2754
2755static void __exit f71882fg_exit(void)
2756{
2757 platform_device_unregister(f71882fg_pdev);
2758 platform_driver_unregister(&f71882fg_driver);
2759}
2760
2761MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goede7958e3b2011-07-03 13:32:53 +02002762MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
Hans de Goede45fb3662007-07-13 14:34:19 +02002763MODULE_LICENSE("GPL");
2764
2765module_init(f71882fg_init);
2766module_exit(f71882fg_exit);