blob: 3a7185ab6c50de23bf496c01cd257d7f2db587bd [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
Guenter Roeck20eaf722012-01-19 11:02:17 -0800509/*
510 * Temp attr for the f8000
511 * Note on the f8000 temp_ovt (crit) is used as max, and temp_high (max)
512 * is used as hysteresis value to clear alarms
513 * Also like the f71858fg its temperature indexes start at 0
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100514 */
Hans de Goede0bae6402011-03-09 20:57:10 +0100515static struct sensor_device_attribute_2 f8000_temp_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100516 SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
517 SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_crit,
518 store_temp_crit, 0, 0),
519 SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
520 store_temp_max, 0, 0),
521 SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200522 SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100523 SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
524 SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
525 store_temp_crit, 0, 1),
526 SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
527 store_temp_max, 0, 1),
528 SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200529 SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100530 SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
531 SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
532 store_temp_crit, 0, 2),
533 SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
534 store_temp_max, 0, 2),
535 SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
Hans de Goedeb6858bc2009-06-15 18:39:51 +0200536 SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100537};
538
Hans de Goede0bae6402011-03-09 20:57:10 +0100539/* in attr for all models */
540static struct sensor_device_attribute_2 fxxxx_in_attr[] = {
541 SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
542 SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
543 SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
544 SENSOR_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 0, 3),
545 SENSOR_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 0, 4),
546 SENSOR_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 0, 5),
547 SENSOR_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 0, 6),
548 SENSOR_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 0, 7),
549 SENSOR_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 0, 8),
Peter Hung2725fe22015-07-07 16:22:36 +0800550 SENSOR_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 0, 9),
Hans de Goede0bae6402011-03-09 20:57:10 +0100551};
552
553/* For models with in1 alarm capability */
554static struct sensor_device_attribute_2 fxxxx_in1_alarm_attr[] = {
555 SENSOR_ATTR_2(in1_max, S_IRUGO|S_IWUSR, show_in_max, store_in_max,
556 0, 1),
557 SENSOR_ATTR_2(in1_beep, S_IRUGO|S_IWUSR, show_in_beep, store_in_beep,
558 0, 1),
559 SENSOR_ATTR_2(in1_alarm, S_IRUGO, show_in_alarm, NULL, 0, 1),
560};
561
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100562/* Fan / PWM attr common to all models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100563static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100564 SENSOR_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100565 SENSOR_ATTR_2(fan1_full_speed, S_IRUGO|S_IWUSR,
566 show_fan_full_speed,
567 store_fan_full_speed, 0, 0),
Mark van Doesburgbc37ae72009-01-07 16:37:27 +0100568 SENSOR_ATTR_2(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100569 SENSOR_ATTR_2(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 0),
570 SENSOR_ATTR_2(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
571 store_pwm_enable, 0, 0),
572 SENSOR_ATTR_2(pwm1_interpolate, S_IRUGO|S_IWUSR,
573 show_pwm_interpolate, store_pwm_interpolate, 0, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100574}, {
575 SENSOR_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 0, 1),
576 SENSOR_ATTR_2(fan2_full_speed, S_IRUGO|S_IWUSR,
577 show_fan_full_speed,
578 store_fan_full_speed, 0, 1),
579 SENSOR_ATTR_2(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100580 SENSOR_ATTR_2(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 1),
581 SENSOR_ATTR_2(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
582 store_pwm_enable, 0, 1),
583 SENSOR_ATTR_2(pwm2_interpolate, S_IRUGO|S_IWUSR,
584 show_pwm_interpolate, store_pwm_interpolate, 0, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100585}, {
586 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
587 SENSOR_ATTR_2(fan3_full_speed, S_IRUGO|S_IWUSR,
588 show_fan_full_speed,
589 store_fan_full_speed, 0, 2),
590 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
Hans de Goede3fc78382009-06-15 18:39:50 +0200591 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
592 SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
593 store_pwm_enable, 0, 2),
Hans de Goede498be962009-01-07 16:37:28 +0100594 SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
595 show_pwm_interpolate, store_pwm_interpolate, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100596}, {
597 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
598 SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
599 show_fan_full_speed,
600 store_fan_full_speed, 0, 3),
601 SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
602 SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
603 SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
604 store_pwm_enable, 0, 3),
605 SENSOR_ATTR_2(pwm4_interpolate, S_IRUGO|S_IWUSR,
606 show_pwm_interpolate, store_pwm_interpolate, 0, 3),
607} };
Hans de Goede498be962009-01-07 16:37:28 +0100608
Hans de Goede629c58b2011-05-25 20:43:32 +0200609/* Attr for the third fan of the f71808a, which only has manual pwm */
610static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
611 SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
612 SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
613 SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
614 show_simple_pwm, store_simple_pwm, 0, 2),
615};
616
Hans de Goede66344aa2009-12-09 20:35:59 +0100617/* Attr for models which can beep on Fan alarm */
618static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100619 SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
620 store_fan_beep, 0, 0),
621 SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
622 store_fan_beep, 0, 1),
623 SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
624 store_fan_beep, 0, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100625 SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
626 store_fan_beep, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100627};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100628
Guenter Roeck20eaf722012-01-19 11:02:17 -0800629/*
630 * PWM attr for the f71862fg, fewer pwms and fewer zones per pwm than the
631 * standard models
632 */
Hans de Goede55840142011-09-09 12:12:33 +0200633static struct sensor_device_attribute_2 f71862fg_auto_pwm_attr[3][7] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100634 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
635 show_pwm_auto_point_channel,
636 store_pwm_auto_point_channel, 0, 0),
Hans de Goede498be962009-01-07 16:37:28 +0100637 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
638 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
639 1, 0),
640 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
641 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
642 4, 0),
643 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
644 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
645 0, 0),
646 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
647 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
648 3, 0),
649 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
650 show_pwm_auto_point_temp_hyst,
651 store_pwm_auto_point_temp_hyst,
652 0, 0),
653 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
654 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +0200655}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100656 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
657 show_pwm_auto_point_channel,
658 store_pwm_auto_point_channel, 0, 1),
Hans de Goede498be962009-01-07 16:37:28 +0100659 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
660 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
661 1, 1),
662 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
663 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
664 4, 1),
665 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
666 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
667 0, 1),
668 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
669 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
670 3, 1),
671 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
672 show_pwm_auto_point_temp_hyst,
673 store_pwm_auto_point_temp_hyst,
674 0, 1),
675 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
676 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +0200677}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100678 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
679 show_pwm_auto_point_channel,
680 store_pwm_auto_point_channel, 0, 2),
Hans de Goede49010622009-01-07 16:37:30 +0100681 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
682 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
683 1, 2),
684 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
685 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
686 4, 2),
687 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
688 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
689 0, 2),
690 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
691 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
692 3, 2),
693 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
694 show_pwm_auto_point_temp_hyst,
695 store_pwm_auto_point_temp_hyst,
696 0, 2),
697 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
698 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +0200699} };
Hans de Goede498be962009-01-07 16:37:28 +0100700
Guenter Roeck20eaf722012-01-19 11:02:17 -0800701/*
702 * PWM attr for the f71808e/f71869, almost identical to the f71862fg, but the
703 * pwm setting when the temperature is above the pwmX_auto_point1_temp can be
704 * programmed instead of being hardcoded to 0xff
705 */
Hans de Goede55840142011-09-09 12:12:33 +0200706static struct sensor_device_attribute_2 f71869_auto_pwm_attr[3][8] = { {
Hans de Goedec11bb992011-03-09 20:57:15 +0100707 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
708 show_pwm_auto_point_channel,
709 store_pwm_auto_point_channel, 0, 0),
710 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
711 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
712 0, 0),
713 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
714 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
715 1, 0),
716 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
717 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
718 4, 0),
719 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
720 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
721 0, 0),
722 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
723 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
724 3, 0),
725 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
726 show_pwm_auto_point_temp_hyst,
727 store_pwm_auto_point_temp_hyst,
728 0, 0),
729 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
730 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +0200731}, {
Hans de Goedec11bb992011-03-09 20:57:15 +0100732 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
733 show_pwm_auto_point_channel,
734 store_pwm_auto_point_channel, 0, 1),
735 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
736 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
737 0, 1),
738 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
739 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
740 1, 1),
741 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
742 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
743 4, 1),
744 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
745 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
746 0, 1),
747 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
748 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
749 3, 1),
750 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
751 show_pwm_auto_point_temp_hyst,
752 store_pwm_auto_point_temp_hyst,
753 0, 1),
754 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
755 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +0200756}, {
Hans de Goedec11bb992011-03-09 20:57:15 +0100757 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
758 show_pwm_auto_point_channel,
759 store_pwm_auto_point_channel, 0, 2),
760 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
761 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
762 0, 2),
763 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
764 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
765 1, 2),
766 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
767 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
768 4, 2),
769 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
770 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
771 0, 2),
772 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
773 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
774 3, 2),
775 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
776 show_pwm_auto_point_temp_hyst,
777 store_pwm_auto_point_temp_hyst,
778 0, 2),
779 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
780 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +0200781} };
Hans de Goedec11bb992011-03-09 20:57:15 +0100782
Hans de Goede3cad4022011-03-09 20:57:14 +0100783/* PWM attr for the standard models */
Hans de Goedeb69b0392009-12-09 20:36:00 +0100784static struct sensor_device_attribute_2 fxxxx_auto_pwm_attr[4][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100785 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
786 show_pwm_auto_point_channel,
787 store_pwm_auto_point_channel, 0, 0),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100788 SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
789 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
790 0, 0),
791 SENSOR_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO|S_IWUSR,
792 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
793 1, 0),
794 SENSOR_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO|S_IWUSR,
795 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
796 2, 0),
797 SENSOR_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO|S_IWUSR,
798 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
799 3, 0),
800 SENSOR_ATTR_2(pwm1_auto_point5_pwm, S_IRUGO|S_IWUSR,
801 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
802 4, 0),
803 SENSOR_ATTR_2(pwm1_auto_point1_temp, S_IRUGO|S_IWUSR,
804 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
805 0, 0),
806 SENSOR_ATTR_2(pwm1_auto_point2_temp, S_IRUGO|S_IWUSR,
807 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
808 1, 0),
809 SENSOR_ATTR_2(pwm1_auto_point3_temp, S_IRUGO|S_IWUSR,
810 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
811 2, 0),
812 SENSOR_ATTR_2(pwm1_auto_point4_temp, S_IRUGO|S_IWUSR,
813 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
814 3, 0),
815 SENSOR_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
816 show_pwm_auto_point_temp_hyst,
817 store_pwm_auto_point_temp_hyst,
818 0, 0),
819 SENSOR_ATTR_2(pwm1_auto_point2_temp_hyst, S_IRUGO,
820 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
821 SENSOR_ATTR_2(pwm1_auto_point3_temp_hyst, S_IRUGO,
822 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
823 SENSOR_ATTR_2(pwm1_auto_point4_temp_hyst, S_IRUGO,
824 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100825}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100826 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
827 show_pwm_auto_point_channel,
828 store_pwm_auto_point_channel, 0, 1),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100829 SENSOR_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO|S_IWUSR,
830 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
831 0, 1),
832 SENSOR_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO|S_IWUSR,
833 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
834 1, 1),
835 SENSOR_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO|S_IWUSR,
836 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
837 2, 1),
838 SENSOR_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO|S_IWUSR,
839 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
840 3, 1),
841 SENSOR_ATTR_2(pwm2_auto_point5_pwm, S_IRUGO|S_IWUSR,
842 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
843 4, 1),
844 SENSOR_ATTR_2(pwm2_auto_point1_temp, S_IRUGO|S_IWUSR,
845 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
846 0, 1),
847 SENSOR_ATTR_2(pwm2_auto_point2_temp, S_IRUGO|S_IWUSR,
848 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
849 1, 1),
850 SENSOR_ATTR_2(pwm2_auto_point3_temp, S_IRUGO|S_IWUSR,
851 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
852 2, 1),
853 SENSOR_ATTR_2(pwm2_auto_point4_temp, S_IRUGO|S_IWUSR,
854 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
855 3, 1),
856 SENSOR_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
857 show_pwm_auto_point_temp_hyst,
858 store_pwm_auto_point_temp_hyst,
859 0, 1),
860 SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
861 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
862 SENSOR_ATTR_2(pwm2_auto_point3_temp_hyst, S_IRUGO,
863 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
864 SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
865 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100866}, {
Hans de Goede66344aa2009-12-09 20:35:59 +0100867 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
868 show_pwm_auto_point_channel,
869 store_pwm_auto_point_channel, 0, 2),
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100870 SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
871 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
872 0, 2),
873 SENSOR_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO|S_IWUSR,
874 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
875 1, 2),
876 SENSOR_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO|S_IWUSR,
877 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
878 2, 2),
879 SENSOR_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO|S_IWUSR,
880 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
881 3, 2),
882 SENSOR_ATTR_2(pwm3_auto_point5_pwm, S_IRUGO|S_IWUSR,
883 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
884 4, 2),
885 SENSOR_ATTR_2(pwm3_auto_point1_temp, S_IRUGO|S_IWUSR,
886 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
887 0, 2),
888 SENSOR_ATTR_2(pwm3_auto_point2_temp, S_IRUGO|S_IWUSR,
889 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
890 1, 2),
891 SENSOR_ATTR_2(pwm3_auto_point3_temp, S_IRUGO|S_IWUSR,
892 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
893 2, 2),
894 SENSOR_ATTR_2(pwm3_auto_point4_temp, S_IRUGO|S_IWUSR,
895 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
896 3, 2),
897 SENSOR_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
898 show_pwm_auto_point_temp_hyst,
899 store_pwm_auto_point_temp_hyst,
900 0, 2),
901 SENSOR_ATTR_2(pwm3_auto_point2_temp_hyst, S_IRUGO,
902 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
903 SENSOR_ATTR_2(pwm3_auto_point3_temp_hyst, S_IRUGO,
904 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
905 SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
906 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100907}, {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +0100908 SENSOR_ATTR_2(pwm4_auto_channels_temp, S_IRUGO|S_IWUSR,
909 show_pwm_auto_point_channel,
910 store_pwm_auto_point_channel, 0, 3),
911 SENSOR_ATTR_2(pwm4_auto_point1_pwm, S_IRUGO|S_IWUSR,
912 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
913 0, 3),
914 SENSOR_ATTR_2(pwm4_auto_point2_pwm, S_IRUGO|S_IWUSR,
915 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
916 1, 3),
917 SENSOR_ATTR_2(pwm4_auto_point3_pwm, S_IRUGO|S_IWUSR,
918 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
919 2, 3),
920 SENSOR_ATTR_2(pwm4_auto_point4_pwm, S_IRUGO|S_IWUSR,
921 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
922 3, 3),
923 SENSOR_ATTR_2(pwm4_auto_point5_pwm, S_IRUGO|S_IWUSR,
924 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
925 4, 3),
926 SENSOR_ATTR_2(pwm4_auto_point1_temp, S_IRUGO|S_IWUSR,
927 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
928 0, 3),
929 SENSOR_ATTR_2(pwm4_auto_point2_temp, S_IRUGO|S_IWUSR,
930 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
931 1, 3),
932 SENSOR_ATTR_2(pwm4_auto_point3_temp, S_IRUGO|S_IWUSR,
933 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
934 2, 3),
935 SENSOR_ATTR_2(pwm4_auto_point4_temp, S_IRUGO|S_IWUSR,
936 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
937 3, 3),
938 SENSOR_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
939 show_pwm_auto_point_temp_hyst,
940 store_pwm_auto_point_temp_hyst,
941 0, 3),
942 SENSOR_ATTR_2(pwm4_auto_point2_temp_hyst, S_IRUGO,
943 show_pwm_auto_point_temp_hyst, NULL, 1, 3),
944 SENSOR_ATTR_2(pwm4_auto_point3_temp_hyst, S_IRUGO,
945 show_pwm_auto_point_temp_hyst, NULL, 2, 3),
946 SENSOR_ATTR_2(pwm4_auto_point4_temp_hyst, S_IRUGO,
947 show_pwm_auto_point_temp_hyst, NULL, 3, 3),
Hans de Goedeb69b0392009-12-09 20:36:00 +0100948} };
Hans de Goede45fb3662007-07-13 14:34:19 +0200949
Hans de Goede66344aa2009-12-09 20:35:59 +0100950/* Fan attr specific to the f8000 (4th fan input can only measure speed) */
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100951static struct sensor_device_attribute_2 f8000_fan_attr[] = {
952 SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
Hans de Goede66344aa2009-12-09 20:35:59 +0100953};
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100954
Guenter Roeck20eaf722012-01-19 11:02:17 -0800955/*
956 * PWM attr for the f8000, zones mapped to temp instead of to pwm!
957 * Also the register block at offset A0 maps to TEMP1 (so our temp2, as the
958 * F8000 starts counting temps at 0), B0 maps the TEMP2 and C0 maps to TEMP0
959 */
Hans de Goede55840142011-09-09 12:12:33 +0200960static struct sensor_device_attribute_2 f8000_auto_pwm_attr[3][14] = { {
Hans de Goede66344aa2009-12-09 20:35:59 +0100961 SENSOR_ATTR_2(pwm1_auto_channels_temp, S_IRUGO|S_IWUSR,
962 show_pwm_auto_point_channel,
963 store_pwm_auto_point_channel, 0, 0),
Hans de Goedeed4f7c22009-01-07 16:37:30 +0100964 SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
965 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
966 0, 2),
967 SENSOR_ATTR_2(temp1_auto_point2_pwm, S_IRUGO|S_IWUSR,
968 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
969 1, 2),
970 SENSOR_ATTR_2(temp1_auto_point3_pwm, S_IRUGO|S_IWUSR,
971 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
972 2, 2),
973 SENSOR_ATTR_2(temp1_auto_point4_pwm, S_IRUGO|S_IWUSR,
974 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
975 3, 2),
976 SENSOR_ATTR_2(temp1_auto_point5_pwm, S_IRUGO|S_IWUSR,
977 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
978 4, 2),
979 SENSOR_ATTR_2(temp1_auto_point1_temp, S_IRUGO|S_IWUSR,
980 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
981 0, 2),
982 SENSOR_ATTR_2(temp1_auto_point2_temp, S_IRUGO|S_IWUSR,
983 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
984 1, 2),
985 SENSOR_ATTR_2(temp1_auto_point3_temp, S_IRUGO|S_IWUSR,
986 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
987 2, 2),
988 SENSOR_ATTR_2(temp1_auto_point4_temp, S_IRUGO|S_IWUSR,
989 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
990 3, 2),
991 SENSOR_ATTR_2(temp1_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
992 show_pwm_auto_point_temp_hyst,
993 store_pwm_auto_point_temp_hyst,
994 0, 2),
995 SENSOR_ATTR_2(temp1_auto_point2_temp_hyst, S_IRUGO,
996 show_pwm_auto_point_temp_hyst, NULL, 1, 2),
997 SENSOR_ATTR_2(temp1_auto_point3_temp_hyst, S_IRUGO,
998 show_pwm_auto_point_temp_hyst, NULL, 2, 2),
999 SENSOR_ATTR_2(temp1_auto_point4_temp_hyst, S_IRUGO,
1000 show_pwm_auto_point_temp_hyst, NULL, 3, 2),
Hans de Goede55840142011-09-09 12:12:33 +02001001}, {
Hans de Goede66344aa2009-12-09 20:35:59 +01001002 SENSOR_ATTR_2(pwm2_auto_channels_temp, S_IRUGO|S_IWUSR,
1003 show_pwm_auto_point_channel,
1004 store_pwm_auto_point_channel, 0, 1),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001005 SENSOR_ATTR_2(temp2_auto_point1_pwm, S_IRUGO|S_IWUSR,
1006 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1007 0, 0),
1008 SENSOR_ATTR_2(temp2_auto_point2_pwm, S_IRUGO|S_IWUSR,
1009 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1010 1, 0),
1011 SENSOR_ATTR_2(temp2_auto_point3_pwm, S_IRUGO|S_IWUSR,
1012 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1013 2, 0),
1014 SENSOR_ATTR_2(temp2_auto_point4_pwm, S_IRUGO|S_IWUSR,
1015 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1016 3, 0),
1017 SENSOR_ATTR_2(temp2_auto_point5_pwm, S_IRUGO|S_IWUSR,
1018 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1019 4, 0),
1020 SENSOR_ATTR_2(temp2_auto_point1_temp, S_IRUGO|S_IWUSR,
1021 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1022 0, 0),
1023 SENSOR_ATTR_2(temp2_auto_point2_temp, S_IRUGO|S_IWUSR,
1024 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1025 1, 0),
1026 SENSOR_ATTR_2(temp2_auto_point3_temp, S_IRUGO|S_IWUSR,
1027 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1028 2, 0),
1029 SENSOR_ATTR_2(temp2_auto_point4_temp, S_IRUGO|S_IWUSR,
1030 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1031 3, 0),
1032 SENSOR_ATTR_2(temp2_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1033 show_pwm_auto_point_temp_hyst,
1034 store_pwm_auto_point_temp_hyst,
1035 0, 0),
1036 SENSOR_ATTR_2(temp2_auto_point2_temp_hyst, S_IRUGO,
1037 show_pwm_auto_point_temp_hyst, NULL, 1, 0),
1038 SENSOR_ATTR_2(temp2_auto_point3_temp_hyst, S_IRUGO,
1039 show_pwm_auto_point_temp_hyst, NULL, 2, 0),
1040 SENSOR_ATTR_2(temp2_auto_point4_temp_hyst, S_IRUGO,
1041 show_pwm_auto_point_temp_hyst, NULL, 3, 0),
Hans de Goede55840142011-09-09 12:12:33 +02001042}, {
Hans de Goede66344aa2009-12-09 20:35:59 +01001043 SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
1044 show_pwm_auto_point_channel,
1045 store_pwm_auto_point_channel, 0, 2),
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001046 SENSOR_ATTR_2(temp3_auto_point1_pwm, S_IRUGO|S_IWUSR,
1047 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1048 0, 1),
1049 SENSOR_ATTR_2(temp3_auto_point2_pwm, S_IRUGO|S_IWUSR,
1050 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1051 1, 1),
1052 SENSOR_ATTR_2(temp3_auto_point3_pwm, S_IRUGO|S_IWUSR,
1053 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1054 2, 1),
1055 SENSOR_ATTR_2(temp3_auto_point4_pwm, S_IRUGO|S_IWUSR,
1056 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1057 3, 1),
1058 SENSOR_ATTR_2(temp3_auto_point5_pwm, S_IRUGO|S_IWUSR,
1059 show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
1060 4, 1),
1061 SENSOR_ATTR_2(temp3_auto_point1_temp, S_IRUGO|S_IWUSR,
1062 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1063 0, 1),
1064 SENSOR_ATTR_2(temp3_auto_point2_temp, S_IRUGO|S_IWUSR,
1065 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1066 1, 1),
1067 SENSOR_ATTR_2(temp3_auto_point3_temp, S_IRUGO|S_IWUSR,
1068 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1069 2, 1),
1070 SENSOR_ATTR_2(temp3_auto_point4_temp, S_IRUGO|S_IWUSR,
1071 show_pwm_auto_point_temp, store_pwm_auto_point_temp,
1072 3, 1),
1073 SENSOR_ATTR_2(temp3_auto_point1_temp_hyst, S_IRUGO|S_IWUSR,
1074 show_pwm_auto_point_temp_hyst,
1075 store_pwm_auto_point_temp_hyst,
1076 0, 1),
1077 SENSOR_ATTR_2(temp3_auto_point2_temp_hyst, S_IRUGO,
1078 show_pwm_auto_point_temp_hyst, NULL, 1, 1),
1079 SENSOR_ATTR_2(temp3_auto_point3_temp_hyst, S_IRUGO,
1080 show_pwm_auto_point_temp_hyst, NULL, 2, 1),
1081 SENSOR_ATTR_2(temp3_auto_point4_temp_hyst, S_IRUGO,
1082 show_pwm_auto_point_temp_hyst, NULL, 3, 1),
Hans de Goede55840142011-09-09 12:12:33 +02001083} };
Hans de Goede45fb3662007-07-13 14:34:19 +02001084
1085/* Super I/O functions */
1086static inline int superio_inb(int base, int reg)
1087{
1088 outb(reg, base);
1089 return inb(base + 1);
1090}
1091
1092static int superio_inw(int base, int reg)
1093{
1094 int val;
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001095 val = superio_inb(base, reg) << 8;
1096 val |= superio_inb(base, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001097 return val;
1098}
1099
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001100static inline int superio_enter(int base)
Hans de Goede45fb3662007-07-13 14:34:19 +02001101{
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001102 /* Don't step on other drivers' I/O space by accident */
1103 if (!request_muxed_region(base, 2, DRVNAME)) {
Joe Perches22d3b412010-10-20 06:51:34 +00001104 pr_err("I/O address 0x%04x already in use\n", base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001105 return -EBUSY;
1106 }
1107
Hans de Goede45fb3662007-07-13 14:34:19 +02001108 /* according to the datasheet the key must be send twice! */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001109 outb(SIO_UNLOCK_KEY, base);
1110 outb(SIO_UNLOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001111
1112 return 0;
Hans de Goede45fb3662007-07-13 14:34:19 +02001113}
1114
Giel van Schijndel162bb592010-05-27 19:58:40 +02001115static inline void superio_select(int base, int ld)
Hans de Goede45fb3662007-07-13 14:34:19 +02001116{
1117 outb(SIO_REG_LDSEL, base);
1118 outb(ld, base + 1);
1119}
1120
1121static inline void superio_exit(int base)
1122{
1123 outb(SIO_LOCK_KEY, base);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04001124 release_region(base, 2);
Hans de Goede45fb3662007-07-13 14:34:19 +02001125}
1126
Hans de Goede2f650632009-01-07 16:37:31 +01001127static inline int fan_from_reg(u16 reg)
Hans de Goede45fb3662007-07-13 14:34:19 +02001128{
1129 return reg ? (1500000 / reg) : 0;
1130}
1131
Hans de Goede2f650632009-01-07 16:37:31 +01001132static inline u16 fan_to_reg(int fan)
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001133{
1134 return fan ? (1500000 / fan) : 0;
1135}
1136
Hans de Goede45fb3662007-07-13 14:34:19 +02001137static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg)
1138{
1139 u8 val;
1140
1141 outb(reg, data->addr + ADDR_REG_OFFSET);
1142 val = inb(data->addr + DATA_REG_OFFSET);
1143
1144 return val;
1145}
1146
1147static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg)
1148{
1149 u16 val;
1150
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001151 val = f71882fg_read8(data, reg) << 8;
1152 val |= f71882fg_read8(data, reg + 1);
Hans de Goede45fb3662007-07-13 14:34:19 +02001153
1154 return val;
1155}
1156
1157static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val)
1158{
1159 outb(reg, data->addr + ADDR_REG_OFFSET);
1160 outb(val, data->addr + DATA_REG_OFFSET);
1161}
1162
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001163static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
1164{
Giel van Schijndelbd328ac2010-05-27 19:58:42 +02001165 f71882fg_write8(data, reg, val >> 8);
1166 f71882fg_write8(data, reg + 1, val & 0xff);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001167}
1168
Hans de Goede09475d32009-06-15 18:39:52 +02001169static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
1170{
1171 if (data->type == f71858fg)
1172 return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
1173 else
1174 return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
1175}
1176
Mark van Doesburg77a4a3e2009-01-07 16:37:27 +01001177static struct f71882fg_data *f71882fg_update_device(struct device *dev)
Hans de Goede45fb3662007-07-13 14:34:19 +02001178{
1179 struct f71882fg_data *data = dev_get_drvdata(dev);
Jean Delvaref27def02011-03-26 10:45:01 +01001180 int nr_fans = f71882fg_nr_fans[data->type];
1181 int nr_temps = f71882fg_nr_temps[data->type];
Hans de Goedee5e713c2011-03-10 08:54:02 +01001182 int nr, reg, point;
Hans de Goede45fb3662007-07-13 14:34:19 +02001183
1184 mutex_lock(&data->update_lock);
1185
1186 /* Update once every 60 seconds */
Giel van Schijndel162bb592010-05-27 19:58:40 +02001187 if (time_after(jiffies, data->last_limits + 60 * HZ) ||
Hans de Goede45fb3662007-07-13 14:34:19 +02001188 !data->valid) {
Hans de Goede0bae6402011-03-09 20:57:10 +01001189 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01001190 data->in1_max =
1191 f71882fg_read8(data, F71882FG_REG_IN1_HIGH);
1192 data->in_beep =
1193 f71882fg_read8(data, F71882FG_REG_IN_BEEP);
1194 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001195
1196 /* Get High & boundary temps*/
Hans de Goedee5e713c2011-03-10 08:54:02 +01001197 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1198 nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001199 data->temp_ovt[nr] = f71882fg_read8(data,
1200 F71882FG_REG_TEMP_OVT(nr));
1201 data->temp_high[nr] = f71882fg_read8(data,
1202 F71882FG_REG_TEMP_HIGH(nr));
1203 }
1204
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001205 if (data->type != f8000) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001206 data->temp_hyst[0] = f71882fg_read8(data,
1207 F71882FG_REG_TEMP_HYST(0));
1208 data->temp_hyst[1] = f71882fg_read8(data,
1209 F71882FG_REG_TEMP_HYST(1));
Hans de Goede09475d32009-06-15 18:39:52 +02001210 }
Hans de Goede78aa4f72011-03-09 20:57:12 +01001211 /* All but the f71858fg / f8000 have this register */
1212 if ((data->type != f71858fg) && (data->type != f8000)) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001213 reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
Hans de Goede44c4dc52011-03-09 20:57:07 +01001214 data->temp_type[1] = (reg & 0x02) ? 2 : 4;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001215 data->temp_type[2] = (reg & 0x04) ? 2 : 4;
1216 data->temp_type[3] = (reg & 0x08) ? 2 : 4;
1217 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001218
Hans de Goede4d538112011-05-25 20:43:32 +02001219 if (f71882fg_fan_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001220 data->fan_beep = f71882fg_read8(data,
1221 F71882FG_REG_FAN_BEEP);
Hans de Goede4d538112011-05-25 20:43:32 +02001222
1223 if (f71882fg_temp_has_beep[data->type])
Hans de Goede78aa4f72011-03-09 20:57:12 +01001224 data->temp_beep = f71882fg_read8(data,
1225 F71882FG_REG_TEMP_BEEP);
Hans de Goede78aa4f72011-03-09 20:57:12 +01001226
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001227 data->pwm_enable = f71882fg_read8(data,
1228 F71882FG_REG_PWM_ENABLE);
Hans de Goedebc274902009-01-07 16:37:29 +01001229 data->pwm_auto_point_hyst[0] =
1230 f71882fg_read8(data, F71882FG_REG_FAN_HYST(0));
1231 data->pwm_auto_point_hyst[1] =
1232 f71882fg_read8(data, F71882FG_REG_FAN_HYST(1));
1233
Hans de Goede498be962009-01-07 16:37:28 +01001234 for (nr = 0; nr < nr_fans; nr++) {
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001235 data->pwm_auto_point_mapping[nr] =
1236 f71882fg_read8(data,
1237 F71882FG_REG_POINT_MAPPING(nr));
1238
Hans de Goedee5e713c2011-03-10 08:54:02 +01001239 switch (data->type) {
1240 default:
Hans de Goede498be962009-01-07 16:37:28 +01001241 for (point = 0; point < 5; point++) {
1242 data->pwm_auto_point_pwm[nr][point] =
1243 f71882fg_read8(data,
1244 F71882FG_REG_POINT_PWM
1245 (nr, point));
1246 }
1247 for (point = 0; point < 4; point++) {
1248 data->pwm_auto_point_temp[nr][point] =
1249 f71882fg_read8(data,
1250 F71882FG_REG_POINT_TEMP
1251 (nr, point));
1252 }
Hans de Goedee5e713c2011-03-10 08:54:02 +01001253 break;
1254 case f71808e:
1255 case f71869:
1256 data->pwm_auto_point_pwm[nr][0] =
1257 f71882fg_read8(data,
1258 F71882FG_REG_POINT_PWM(nr, 0));
1259 /* Fall through */
1260 case f71862fg:
Hans de Goede498be962009-01-07 16:37:28 +01001261 data->pwm_auto_point_pwm[nr][1] =
1262 f71882fg_read8(data,
1263 F71882FG_REG_POINT_PWM
1264 (nr, 1));
1265 data->pwm_auto_point_pwm[nr][4] =
1266 f71882fg_read8(data,
1267 F71882FG_REG_POINT_PWM
1268 (nr, 4));
1269 data->pwm_auto_point_temp[nr][0] =
1270 f71882fg_read8(data,
1271 F71882FG_REG_POINT_TEMP
1272 (nr, 0));
1273 data->pwm_auto_point_temp[nr][3] =
1274 f71882fg_read8(data,
1275 F71882FG_REG_POINT_TEMP
1276 (nr, 3));
Hans de Goedee5e713c2011-03-10 08:54:02 +01001277 break;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001278 }
1279 }
Hans de Goede45fb3662007-07-13 14:34:19 +02001280 data->last_limits = jiffies;
1281 }
1282
1283 /* Update every second */
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04001284 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001285 data->temp_status = f71882fg_read8(data,
1286 F71882FG_REG_TEMP_STATUS);
1287 data->temp_diode_open = f71882fg_read8(data,
1288 F71882FG_REG_TEMP_DIODE_OPEN);
Hans de Goedee5e713c2011-03-10 08:54:02 +01001289 for (nr = data->temp_start; nr < nr_temps + data->temp_start;
1290 nr++)
Hans de Goede09475d32009-06-15 18:39:52 +02001291 data->temp[nr] = f71882fg_read_temp(data, nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001292
1293 data->fan_status = f71882fg_read8(data,
1294 F71882FG_REG_FAN_STATUS);
Hans de Goede498be962009-01-07 16:37:28 +01001295 for (nr = 0; nr < nr_fans; nr++) {
Hans de Goede45fb3662007-07-13 14:34:19 +02001296 data->fan[nr] = f71882fg_read16(data,
1297 F71882FG_REG_FAN(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001298 data->fan_target[nr] =
1299 f71882fg_read16(data, F71882FG_REG_FAN_TARGET(nr));
1300 data->fan_full_speed[nr] =
1301 f71882fg_read16(data,
1302 F71882FG_REG_FAN_FULL_SPEED(nr));
1303 data->pwm[nr] =
1304 f71882fg_read8(data, F71882FG_REG_PWM(nr));
1305 }
Hans de Goede629c58b2011-05-25 20:43:32 +02001306 /* Some models have 1 more fan with limited capabilities */
1307 if (data->type == f71808a) {
1308 data->fan[2] = f71882fg_read16(data,
1309 F71882FG_REG_FAN(2));
1310 data->pwm[2] = f71882fg_read8(data,
1311 F71882FG_REG_PWM(2));
1312 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001313 if (data->type == f8000)
1314 data->fan[3] = f71882fg_read16(data,
1315 F71882FG_REG_FAN(3));
Hans de Goede0bae6402011-03-09 20:57:10 +01001316
1317 if (f71882fg_has_in1_alarm[data->type])
Hans de Goede498be962009-01-07 16:37:28 +01001318 data->in_status = f71882fg_read8(data,
Hans de Goede45fb3662007-07-13 14:34:19 +02001319 F71882FG_REG_IN_STATUS);
Hans de Goede0bae6402011-03-09 20:57:10 +01001320 for (nr = 0; nr < F71882FG_MAX_INS; nr++)
1321 if (f71882fg_has_in[data->type][nr])
1322 data->in[nr] = f71882fg_read8(data,
1323 F71882FG_REG_IN(nr));
Hans de Goede45fb3662007-07-13 14:34:19 +02001324
1325 data->last_updated = jiffies;
1326 data->valid = 1;
1327 }
1328
1329 mutex_unlock(&data->update_lock);
1330
1331 return data;
1332}
1333
1334/* Sysfs Interface */
1335static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
1336 char *buf)
1337{
1338 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001339 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001340 int speed = fan_from_reg(data->fan[nr]);
1341
1342 if (speed == FAN_MIN_DETECT)
1343 speed = 0;
1344
1345 return sprintf(buf, "%d\n", speed);
1346}
1347
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001348static ssize_t show_fan_full_speed(struct device *dev,
1349 struct device_attribute *devattr, char *buf)
1350{
1351 struct f71882fg_data *data = f71882fg_update_device(dev);
1352 int nr = to_sensor_dev_attr_2(devattr)->index;
1353 int speed = fan_from_reg(data->fan_full_speed[nr]);
1354 return sprintf(buf, "%d\n", speed);
1355}
1356
1357static ssize_t store_fan_full_speed(struct device *dev,
1358 struct device_attribute *devattr,
1359 const char *buf, size_t count)
1360{
1361 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001362 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1363 long val;
1364
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001365 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001366 if (err)
1367 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001368
Guenter Roeck2a844c12013-01-09 08:09:34 -08001369 val = clamp_val(val, 23, 1500000);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001370 val = fan_to_reg(val);
1371
1372 mutex_lock(&data->update_lock);
Hans de Goede4c82c382009-01-07 16:37:30 +01001373 f71882fg_write16(data, F71882FG_REG_FAN_FULL_SPEED(nr), val);
1374 data->fan_full_speed[nr] = val;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001375 mutex_unlock(&data->update_lock);
1376
1377 return count;
1378}
1379
Hans de Goede45fb3662007-07-13 14:34:19 +02001380static ssize_t show_fan_beep(struct device *dev, struct device_attribute
1381 *devattr, char *buf)
1382{
1383 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001384 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001385
1386 if (data->fan_beep & (1 << nr))
1387 return sprintf(buf, "1\n");
1388 else
1389 return sprintf(buf, "0\n");
1390}
1391
1392static ssize_t store_fan_beep(struct device *dev, struct device_attribute
1393 *devattr, const char *buf, size_t count)
1394{
1395 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001396 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1397 unsigned long val;
1398
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001399 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001400 if (err)
1401 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001402
1403 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001404 data->fan_beep = f71882fg_read8(data, F71882FG_REG_FAN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001405 if (val)
1406 data->fan_beep |= 1 << nr;
1407 else
1408 data->fan_beep &= ~(1 << nr);
1409
1410 f71882fg_write8(data, F71882FG_REG_FAN_BEEP, data->fan_beep);
1411 mutex_unlock(&data->update_lock);
1412
1413 return count;
1414}
1415
1416static ssize_t show_fan_alarm(struct device *dev, struct device_attribute
1417 *devattr, char *buf)
1418{
1419 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001420 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001421
1422 if (data->fan_status & (1 << nr))
1423 return sprintf(buf, "1\n");
1424 else
1425 return sprintf(buf, "0\n");
1426}
1427
1428static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
1429 char *buf)
1430{
1431 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001432 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001433
1434 return sprintf(buf, "%d\n", data->in[nr] * 8);
1435}
1436
1437static ssize_t show_in_max(struct device *dev, struct device_attribute
1438 *devattr, char *buf)
1439{
1440 struct f71882fg_data *data = f71882fg_update_device(dev);
1441
1442 return sprintf(buf, "%d\n", data->in1_max * 8);
1443}
1444
1445static ssize_t store_in_max(struct device *dev, struct device_attribute
1446 *devattr, const char *buf, size_t count)
1447{
1448 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001449 int err;
1450 long val;
1451
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001452 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001453 if (err)
1454 return err;
1455
1456 val /= 8;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001457 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001458
1459 mutex_lock(&data->update_lock);
1460 f71882fg_write8(data, F71882FG_REG_IN1_HIGH, val);
1461 data->in1_max = val;
1462 mutex_unlock(&data->update_lock);
1463
1464 return count;
1465}
1466
1467static ssize_t show_in_beep(struct device *dev, struct device_attribute
1468 *devattr, char *buf)
1469{
1470 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001471 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001472
1473 if (data->in_beep & (1 << nr))
1474 return sprintf(buf, "1\n");
1475 else
1476 return sprintf(buf, "0\n");
1477}
1478
1479static ssize_t store_in_beep(struct device *dev, struct device_attribute
1480 *devattr, const char *buf, size_t count)
1481{
1482 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001483 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1484 unsigned long val;
1485
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001486 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001487 if (err)
1488 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001489
1490 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001491 data->in_beep = f71882fg_read8(data, F71882FG_REG_IN_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001492 if (val)
1493 data->in_beep |= 1 << nr;
1494 else
1495 data->in_beep &= ~(1 << nr);
1496
1497 f71882fg_write8(data, F71882FG_REG_IN_BEEP, data->in_beep);
1498 mutex_unlock(&data->update_lock);
1499
1500 return count;
1501}
1502
1503static ssize_t show_in_alarm(struct device *dev, struct device_attribute
1504 *devattr, char *buf)
1505{
1506 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001507 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001508
1509 if (data->in_status & (1 << nr))
1510 return sprintf(buf, "1\n");
1511 else
1512 return sprintf(buf, "0\n");
1513}
1514
1515static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
1516 char *buf)
1517{
1518 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001519 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede09475d32009-06-15 18:39:52 +02001520 int sign, temp;
Hans de Goede45fb3662007-07-13 14:34:19 +02001521
Hans de Goede09475d32009-06-15 18:39:52 +02001522 if (data->type == f71858fg) {
1523 /* TEMP_TABLE_SEL 1 or 3 ? */
1524 if (data->temp_config & 1) {
1525 sign = data->temp[nr] & 0x0001;
1526 temp = (data->temp[nr] >> 5) & 0x7ff;
1527 } else {
1528 sign = data->temp[nr] & 0x8000;
1529 temp = (data->temp[nr] >> 5) & 0x3ff;
1530 }
1531 temp *= 125;
1532 if (sign)
1533 temp -= 128000;
1534 } else
1535 temp = data->temp[nr] * 1000;
1536
1537 return sprintf(buf, "%d\n", temp);
Hans de Goede45fb3662007-07-13 14:34:19 +02001538}
1539
1540static ssize_t show_temp_max(struct device *dev, struct device_attribute
1541 *devattr, char *buf)
1542{
1543 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001544 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001545
1546 return sprintf(buf, "%d\n", data->temp_high[nr] * 1000);
1547}
1548
1549static ssize_t store_temp_max(struct device *dev, struct device_attribute
1550 *devattr, const char *buf, size_t count)
1551{
1552 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001553 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1554 long val;
1555
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001556 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001557 if (err)
1558 return err;
1559
1560 val /= 1000;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001561 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001562
1563 mutex_lock(&data->update_lock);
1564 f71882fg_write8(data, F71882FG_REG_TEMP_HIGH(nr), val);
1565 data->temp_high[nr] = val;
1566 mutex_unlock(&data->update_lock);
1567
1568 return count;
1569}
1570
1571static ssize_t show_temp_max_hyst(struct device *dev, struct device_attribute
1572 *devattr, char *buf)
1573{
1574 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001575 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001576 int temp_max_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001577
Hans de Goedece0bfa52009-01-07 16:37:28 +01001578 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001579 if (nr & 1)
1580 temp_max_hyst = data->temp_hyst[nr / 2] >> 4;
1581 else
1582 temp_max_hyst = data->temp_hyst[nr / 2] & 0x0f;
1583 temp_max_hyst = (data->temp_high[nr] - temp_max_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001584 mutex_unlock(&data->update_lock);
1585
1586 return sprintf(buf, "%d\n", temp_max_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001587}
1588
1589static ssize_t store_temp_max_hyst(struct device *dev, struct device_attribute
1590 *devattr, const char *buf, size_t count)
1591{
1592 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001593 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001594 ssize_t ret = count;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001595 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001596 long val;
1597
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001598 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001599 if (err)
1600 return err;
1601
1602 val /= 1000;
Hans de Goede45fb3662007-07-13 14:34:19 +02001603
1604 mutex_lock(&data->update_lock);
1605
1606 /* convert abs to relative and check */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001607 data->temp_high[nr] = f71882fg_read8(data, F71882FG_REG_TEMP_HIGH(nr));
Guenter Roeck2a844c12013-01-09 08:09:34 -08001608 val = clamp_val(val, data->temp_high[nr] - 15, data->temp_high[nr]);
Hans de Goede45fb3662007-07-13 14:34:19 +02001609 val = data->temp_high[nr] - val;
Hans de Goede45fb3662007-07-13 14:34:19 +02001610
1611 /* convert value to register contents */
Hans de Goedebc274902009-01-07 16:37:29 +01001612 reg = f71882fg_read8(data, F71882FG_REG_TEMP_HYST(nr / 2));
1613 if (nr & 1)
1614 reg = (reg & 0x0f) | (val << 4);
1615 else
1616 reg = (reg & 0xf0) | val;
1617 f71882fg_write8(data, F71882FG_REG_TEMP_HYST(nr / 2), reg);
1618 data->temp_hyst[nr / 2] = reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02001619
Hans de Goede45fb3662007-07-13 14:34:19 +02001620 mutex_unlock(&data->update_lock);
1621 return ret;
1622}
1623
1624static ssize_t show_temp_crit(struct device *dev, struct device_attribute
1625 *devattr, char *buf)
1626{
1627 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001628 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001629
1630 return sprintf(buf, "%d\n", data->temp_ovt[nr] * 1000);
1631}
1632
1633static ssize_t store_temp_crit(struct device *dev, struct device_attribute
1634 *devattr, const char *buf, size_t count)
1635{
1636 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001637 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1638 long val;
1639
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001640 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001641 if (err)
1642 return err;
1643
1644 val /= 1000;
Guenter Roeck2a844c12013-01-09 08:09:34 -08001645 val = clamp_val(val, 0, 255);
Hans de Goede45fb3662007-07-13 14:34:19 +02001646
1647 mutex_lock(&data->update_lock);
1648 f71882fg_write8(data, F71882FG_REG_TEMP_OVT(nr), val);
1649 data->temp_ovt[nr] = val;
1650 mutex_unlock(&data->update_lock);
1651
1652 return count;
1653}
1654
1655static ssize_t show_temp_crit_hyst(struct device *dev, struct device_attribute
1656 *devattr, char *buf)
1657{
1658 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001659 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001660 int temp_crit_hyst;
Hans de Goede45fb3662007-07-13 14:34:19 +02001661
Hans de Goedece0bfa52009-01-07 16:37:28 +01001662 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001663 if (nr & 1)
1664 temp_crit_hyst = data->temp_hyst[nr / 2] >> 4;
1665 else
1666 temp_crit_hyst = data->temp_hyst[nr / 2] & 0x0f;
1667 temp_crit_hyst = (data->temp_ovt[nr] - temp_crit_hyst) * 1000;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001668 mutex_unlock(&data->update_lock);
1669
1670 return sprintf(buf, "%d\n", temp_crit_hyst);
Hans de Goede45fb3662007-07-13 14:34:19 +02001671}
1672
1673static ssize_t show_temp_type(struct device *dev, struct device_attribute
1674 *devattr, char *buf)
1675{
1676 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001677 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001678
1679 return sprintf(buf, "%d\n", data->temp_type[nr]);
1680}
1681
1682static ssize_t show_temp_beep(struct device *dev, struct device_attribute
1683 *devattr, char *buf)
1684{
1685 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001686 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001687
Hans de Goede7567a042009-01-07 16:37:28 +01001688 if (data->temp_beep & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001689 return sprintf(buf, "1\n");
1690 else
1691 return sprintf(buf, "0\n");
1692}
1693
1694static ssize_t store_temp_beep(struct device *dev, struct device_attribute
1695 *devattr, const char *buf, size_t count)
1696{
1697 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001698 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1699 unsigned long val;
1700
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001701 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001702 if (err)
1703 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02001704
1705 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001706 data->temp_beep = f71882fg_read8(data, F71882FG_REG_TEMP_BEEP);
Hans de Goede45fb3662007-07-13 14:34:19 +02001707 if (val)
Hans de Goede7567a042009-01-07 16:37:28 +01001708 data->temp_beep |= 1 << nr;
Hans de Goede45fb3662007-07-13 14:34:19 +02001709 else
Hans de Goede7567a042009-01-07 16:37:28 +01001710 data->temp_beep &= ~(1 << nr);
Hans de Goede45fb3662007-07-13 14:34:19 +02001711
1712 f71882fg_write8(data, F71882FG_REG_TEMP_BEEP, data->temp_beep);
1713 mutex_unlock(&data->update_lock);
1714
1715 return count;
1716}
1717
1718static ssize_t show_temp_alarm(struct device *dev, struct device_attribute
1719 *devattr, char *buf)
1720{
1721 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001722 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001723
Hans de Goede7567a042009-01-07 16:37:28 +01001724 if (data->temp_status & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001725 return sprintf(buf, "1\n");
1726 else
1727 return sprintf(buf, "0\n");
1728}
1729
1730static ssize_t show_temp_fault(struct device *dev, struct device_attribute
1731 *devattr, char *buf)
1732{
1733 struct f71882fg_data *data = f71882fg_update_device(dev);
Mark van Doesburgbc37ae72009-01-07 16:37:27 +01001734 int nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goede45fb3662007-07-13 14:34:19 +02001735
Hans de Goede7567a042009-01-07 16:37:28 +01001736 if (data->temp_diode_open & (1 << nr))
Hans de Goede45fb3662007-07-13 14:34:19 +02001737 return sprintf(buf, "1\n");
1738 else
1739 return sprintf(buf, "0\n");
1740}
1741
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001742static ssize_t show_pwm(struct device *dev,
1743 struct device_attribute *devattr, char *buf)
1744{
1745 struct f71882fg_data *data = f71882fg_update_device(dev);
1746 int val, nr = to_sensor_dev_attr_2(devattr)->index;
Hans de Goedece0bfa52009-01-07 16:37:28 +01001747 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001748 if (data->pwm_enable & (1 << (2 * nr)))
1749 /* PWM mode */
1750 val = data->pwm[nr];
1751 else {
1752 /* RPM mode */
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001753 val = 255 * fan_from_reg(data->fan_target[nr])
1754 / fan_from_reg(data->fan_full_speed[nr]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001755 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001756 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001757 return sprintf(buf, "%d\n", val);
1758}
1759
1760static ssize_t store_pwm(struct device *dev,
1761 struct device_attribute *devattr, const char *buf,
1762 size_t count)
1763{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001764 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001765 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1766 long val;
1767
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001768 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001769 if (err)
1770 return err;
1771
Guenter Roeck2a844c12013-01-09 08:09:34 -08001772 val = clamp_val(val, 0, 255);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001773
1774 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001775 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001776 if ((data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 3) != 2) ||
1777 (data->type != f8000 && !((data->pwm_enable >> 2 * nr) & 2))) {
1778 count = -EROFS;
1779 goto leave;
1780 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001781 if (data->pwm_enable & (1 << (2 * nr))) {
1782 /* PWM mode */
1783 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1784 data->pwm[nr] = val;
1785 } else {
1786 /* RPM mode */
Hans de Goedece0bfa52009-01-07 16:37:28 +01001787 int target, full_speed;
1788 full_speed = f71882fg_read16(data,
1789 F71882FG_REG_FAN_FULL_SPEED(nr));
1790 target = fan_to_reg(val * fan_from_reg(full_speed) / 255);
1791 f71882fg_write16(data, F71882FG_REG_FAN_TARGET(nr), target);
1792 data->fan_target[nr] = target;
1793 data->fan_full_speed[nr] = full_speed;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001794 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001795leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001796 mutex_unlock(&data->update_lock);
1797
1798 return count;
1799}
1800
Hans de Goede629c58b2011-05-25 20:43:32 +02001801static ssize_t show_simple_pwm(struct device *dev,
1802 struct device_attribute *devattr, char *buf)
1803{
1804 struct f71882fg_data *data = f71882fg_update_device(dev);
1805 int val, nr = to_sensor_dev_attr_2(devattr)->index;
1806
1807 val = data->pwm[nr];
1808 return sprintf(buf, "%d\n", val);
1809}
1810
1811static ssize_t store_simple_pwm(struct device *dev,
1812 struct device_attribute *devattr,
1813 const char *buf, size_t count)
1814{
1815 struct f71882fg_data *data = dev_get_drvdata(dev);
1816 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1817 long val;
1818
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001819 err = kstrtol(buf, 10, &val);
Hans de Goede629c58b2011-05-25 20:43:32 +02001820 if (err)
1821 return err;
1822
Guenter Roeck2a844c12013-01-09 08:09:34 -08001823 val = clamp_val(val, 0, 255);
Hans de Goede629c58b2011-05-25 20:43:32 +02001824
1825 mutex_lock(&data->update_lock);
1826 f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
1827 data->pwm[nr] = val;
1828 mutex_unlock(&data->update_lock);
1829
1830 return count;
1831}
1832
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001833static ssize_t show_pwm_enable(struct device *dev,
1834 struct device_attribute *devattr, char *buf)
1835{
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001836 int result = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001837 struct f71882fg_data *data = f71882fg_update_device(dev);
1838 int nr = to_sensor_dev_attr_2(devattr)->index;
1839
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001840 switch ((data->pwm_enable >> 2 * nr) & 3) {
1841 case 0:
1842 case 1:
1843 result = 2; /* Normal auto mode */
1844 break;
1845 case 2:
1846 result = 1; /* Manual mode */
1847 break;
1848 case 3:
1849 if (data->type == f8000)
1850 result = 3; /* Thermostat mode */
1851 else
1852 result = 1; /* Manual mode */
1853 break;
1854 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001855
1856 return sprintf(buf, "%d\n", result);
1857}
1858
1859static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
1860 *devattr, const char *buf, size_t count)
1861{
1862 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001863 int err, nr = to_sensor_dev_attr_2(devattr)->index;
1864 long val;
1865
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001866 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001867 if (err)
1868 return err;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001869
Hans de Goede3fc78382009-06-15 18:39:50 +02001870 /* Special case for F8000 pwm channel 3 which only does auto mode */
1871 if (data->type == f8000 && nr == 2 && val != 2)
1872 return -EINVAL;
1873
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001874 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001875 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001876 /* Special case for F8000 auto PWM mode / Thermostat mode */
1877 if (data->type == f8000 && ((data->pwm_enable >> 2 * nr) & 1)) {
1878 switch (val) {
1879 case 2:
1880 data->pwm_enable &= ~(2 << (2 * nr));
1881 break; /* Normal auto mode */
1882 case 3:
1883 data->pwm_enable |= 2 << (2 * nr);
1884 break; /* Thermostat mode */
1885 default:
1886 count = -EINVAL;
1887 goto leave;
1888 }
1889 } else {
1890 switch (val) {
1891 case 1:
Hans de Goede09475d32009-06-15 18:39:52 +02001892 /* The f71858fg does not support manual RPM mode */
1893 if (data->type == f71858fg &&
1894 ((data->pwm_enable >> (2 * nr)) & 1)) {
1895 count = -EINVAL;
1896 goto leave;
1897 }
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001898 data->pwm_enable |= 2 << (2 * nr);
1899 break; /* Manual */
1900 case 2:
1901 data->pwm_enable &= ~(2 << (2 * nr));
1902 break; /* Normal auto mode */
1903 default:
1904 count = -EINVAL;
1905 goto leave;
1906 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001907 }
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001908 f71882fg_write8(data, F71882FG_REG_PWM_ENABLE, data->pwm_enable);
Hans de Goedeed4f7c22009-01-07 16:37:30 +01001909leave:
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001910 mutex_unlock(&data->update_lock);
1911
1912 return count;
1913}
1914
1915static ssize_t show_pwm_auto_point_pwm(struct device *dev,
1916 struct device_attribute *devattr,
1917 char *buf)
1918{
1919 int result;
1920 struct f71882fg_data *data = f71882fg_update_device(dev);
1921 int pwm = to_sensor_dev_attr_2(devattr)->index;
1922 int point = to_sensor_dev_attr_2(devattr)->nr;
1923
Hans de Goedece0bfa52009-01-07 16:37:28 +01001924 mutex_lock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001925 if (data->pwm_enable & (1 << (2 * pwm))) {
1926 /* PWM mode */
1927 result = data->pwm_auto_point_pwm[pwm][point];
1928 } else {
1929 /* RPM mode */
1930 result = 32 * 255 / (32 + data->pwm_auto_point_pwm[pwm][point]);
1931 }
Hans de Goedece0bfa52009-01-07 16:37:28 +01001932 mutex_unlock(&data->update_lock);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001933
1934 return sprintf(buf, "%d\n", result);
1935}
1936
1937static ssize_t store_pwm_auto_point_pwm(struct device *dev,
1938 struct device_attribute *devattr,
1939 const char *buf, size_t count)
1940{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001941 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001942 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001943 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001944 long val;
1945
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01001946 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001947 if (err)
1948 return err;
1949
Guenter Roeck2a844c12013-01-09 08:09:34 -08001950 val = clamp_val(val, 0, 255);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001951
1952 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01001953 data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001954 if (data->pwm_enable & (1 << (2 * pwm))) {
1955 /* PWM mode */
1956 } else {
1957 /* RPM mode */
1958 if (val < 29) /* Prevent negative numbers */
1959 val = 255;
1960 else
1961 val = (255 - val) * 32 / val;
1962 }
1963 f71882fg_write8(data, F71882FG_REG_POINT_PWM(pwm, point), val);
1964 data->pwm_auto_point_pwm[pwm][point] = val;
1965 mutex_unlock(&data->update_lock);
1966
1967 return count;
1968}
1969
1970static ssize_t show_pwm_auto_point_temp_hyst(struct device *dev,
1971 struct device_attribute *devattr,
1972 char *buf)
1973{
1974 int result = 0;
1975 struct f71882fg_data *data = f71882fg_update_device(dev);
1976 int nr = to_sensor_dev_attr_2(devattr)->index;
1977 int point = to_sensor_dev_attr_2(devattr)->nr;
1978
1979 mutex_lock(&data->update_lock);
Hans de Goedebc274902009-01-07 16:37:29 +01001980 if (nr & 1)
1981 result = data->pwm_auto_point_hyst[nr / 2] >> 4;
1982 else
1983 result = data->pwm_auto_point_hyst[nr / 2] & 0x0f;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001984 result = 1000 * (data->pwm_auto_point_temp[nr][point] - result);
1985 mutex_unlock(&data->update_lock);
1986
1987 return sprintf(buf, "%d\n", result);
1988}
1989
1990static ssize_t store_pwm_auto_point_temp_hyst(struct device *dev,
1991 struct device_attribute *devattr,
1992 const char *buf, size_t count)
1993{
Hans de Goedece0bfa52009-01-07 16:37:28 +01001994 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001995 int err, nr = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01001996 int point = to_sensor_dev_attr_2(devattr)->nr;
Hans de Goedebc274902009-01-07 16:37:29 +01001997 u8 reg;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02001998 long val;
1999
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002000 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002001 if (err)
2002 return err;
2003
2004 val /= 1000;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002005
2006 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002007 data->pwm_auto_point_temp[nr][point] =
2008 f71882fg_read8(data, F71882FG_REG_POINT_TEMP(nr, point));
Guenter Roeck2a844c12013-01-09 08:09:34 -08002009 val = clamp_val(val, data->pwm_auto_point_temp[nr][point] - 15,
2010 data->pwm_auto_point_temp[nr][point]);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002011 val = data->pwm_auto_point_temp[nr][point] - val;
2012
Hans de Goedebc274902009-01-07 16:37:29 +01002013 reg = f71882fg_read8(data, F71882FG_REG_FAN_HYST(nr / 2));
2014 if (nr & 1)
2015 reg = (reg & 0x0f) | (val << 4);
2016 else
2017 reg = (reg & 0xf0) | val;
2018
2019 f71882fg_write8(data, F71882FG_REG_FAN_HYST(nr / 2), reg);
2020 data->pwm_auto_point_hyst[nr / 2] = reg;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002021 mutex_unlock(&data->update_lock);
2022
2023 return count;
2024}
2025
2026static ssize_t show_pwm_interpolate(struct device *dev,
2027 struct device_attribute *devattr, char *buf)
2028{
2029 int result;
2030 struct f71882fg_data *data = f71882fg_update_device(dev);
2031 int nr = to_sensor_dev_attr_2(devattr)->index;
2032
2033 result = (data->pwm_auto_point_mapping[nr] >> 4) & 1;
2034
2035 return sprintf(buf, "%d\n", result);
2036}
2037
2038static ssize_t store_pwm_interpolate(struct device *dev,
2039 struct device_attribute *devattr,
2040 const char *buf, size_t count)
2041{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002042 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002043 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2044 unsigned long val;
2045
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002046 err = kstrtoul(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002047 if (err)
2048 return err;
Hans de Goedece0bfa52009-01-07 16:37:28 +01002049
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002050 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002051 data->pwm_auto_point_mapping[nr] =
2052 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002053 if (val)
2054 val = data->pwm_auto_point_mapping[nr] | (1 << 4);
2055 else
2056 val = data->pwm_auto_point_mapping[nr] & (~(1 << 4));
2057 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2058 data->pwm_auto_point_mapping[nr] = val;
2059 mutex_unlock(&data->update_lock);
2060
2061 return count;
2062}
2063
2064static ssize_t show_pwm_auto_point_channel(struct device *dev,
2065 struct device_attribute *devattr,
2066 char *buf)
2067{
2068 int result;
2069 struct f71882fg_data *data = f71882fg_update_device(dev);
2070 int nr = to_sensor_dev_attr_2(devattr)->index;
2071
Hans de Goede09475d32009-06-15 18:39:52 +02002072 result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
2073 data->temp_start);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002074
2075 return sprintf(buf, "%d\n", result);
2076}
2077
2078static ssize_t store_pwm_auto_point_channel(struct device *dev,
2079 struct device_attribute *devattr,
2080 const char *buf, size_t count)
2081{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002082 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002083 int err, nr = to_sensor_dev_attr_2(devattr)->index;
2084 long val;
2085
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002086 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002087 if (err)
2088 return err;
Hans de Goede30453012009-01-07 16:37:30 +01002089
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002090 switch (val) {
2091 case 1:
Hans de Goede30453012009-01-07 16:37:30 +01002092 val = 0;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002093 break;
2094 case 2:
Hans de Goede30453012009-01-07 16:37:30 +01002095 val = 1;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002096 break;
2097 case 4:
Hans de Goede30453012009-01-07 16:37:30 +01002098 val = 2;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002099 break;
2100 default:
2101 return -EINVAL;
2102 }
Hans de Goede09475d32009-06-15 18:39:52 +02002103 val += data->temp_start;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002104 mutex_lock(&data->update_lock);
Hans de Goedece0bfa52009-01-07 16:37:28 +01002105 data->pwm_auto_point_mapping[nr] =
2106 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002107 val = (data->pwm_auto_point_mapping[nr] & 0xfc) | val;
2108 f71882fg_write8(data, F71882FG_REG_POINT_MAPPING(nr), val);
2109 data->pwm_auto_point_mapping[nr] = val;
2110 mutex_unlock(&data->update_lock);
2111
2112 return count;
2113}
2114
2115static ssize_t show_pwm_auto_point_temp(struct device *dev,
2116 struct device_attribute *devattr,
2117 char *buf)
2118{
2119 int result;
2120 struct f71882fg_data *data = f71882fg_update_device(dev);
2121 int pwm = to_sensor_dev_attr_2(devattr)->index;
2122 int point = to_sensor_dev_attr_2(devattr)->nr;
2123
2124 result = data->pwm_auto_point_temp[pwm][point];
2125 return sprintf(buf, "%d\n", 1000 * result);
2126}
2127
2128static ssize_t store_pwm_auto_point_temp(struct device *dev,
2129 struct device_attribute *devattr,
2130 const char *buf, size_t count)
2131{
Hans de Goedece0bfa52009-01-07 16:37:28 +01002132 struct f71882fg_data *data = dev_get_drvdata(dev);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002133 int err, pwm = to_sensor_dev_attr_2(devattr)->index;
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002134 int point = to_sensor_dev_attr_2(devattr)->nr;
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002135 long val;
2136
Frans Meulenbroeks179c4fd2012-01-04 20:58:52 +01002137 err = kstrtol(buf, 10, &val);
Giel van Schijndele8a4eac2010-05-27 19:58:41 +02002138 if (err)
2139 return err;
2140
2141 val /= 1000;
Hans de Goede76698962009-12-09 20:36:01 +01002142
Hans de Goede98f7ba12011-03-09 20:57:09 +01002143 if (data->auto_point_temp_signed)
Guenter Roeck2a844c12013-01-09 08:09:34 -08002144 val = clamp_val(val, -128, 127);
Hans de Goede76698962009-12-09 20:36:01 +01002145 else
Guenter Roeck2a844c12013-01-09 08:09:34 -08002146 val = clamp_val(val, 0, 127);
Mark van Doesburg9ab796e2009-01-07 16:37:27 +01002147
2148 mutex_lock(&data->update_lock);
2149 f71882fg_write8(data, F71882FG_REG_POINT_TEMP(pwm, point), val);
2150 data->pwm_auto_point_temp[pwm][point] = val;
2151 mutex_unlock(&data->update_lock);
2152
2153 return count;
2154}
2155
Hans de Goede45fb3662007-07-13 14:34:19 +02002156static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
2157 char *buf)
2158{
Hans de Goede498be962009-01-07 16:37:28 +01002159 struct f71882fg_data *data = dev_get_drvdata(dev);
2160 return sprintf(buf, "%s\n", f71882fg_names[data->type]);
Hans de Goede45fb3662007-07-13 14:34:19 +02002161}
2162
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002163static int f71882fg_create_sysfs_files(struct platform_device *pdev,
Hans de Goedec13548c2009-01-07 16:37:27 +01002164 struct sensor_device_attribute_2 *attr, int count)
2165{
2166 int err, i;
Hans de Goede45fb3662007-07-13 14:34:19 +02002167
Hans de Goedec13548c2009-01-07 16:37:27 +01002168 for (i = 0; i < count; i++) {
2169 err = device_create_file(&pdev->dev, &attr[i].dev_attr);
2170 if (err)
2171 return err;
2172 }
2173 return 0;
2174}
2175
Hans de Goedefc16c562009-12-09 20:36:01 +01002176static void f71882fg_remove_sysfs_files(struct platform_device *pdev,
2177 struct sensor_device_attribute_2 *attr, int count)
2178{
2179 int i;
2180
2181 for (i = 0; i < count; i++)
2182 device_remove_file(&pdev->dev, &attr[i].dev_attr);
2183}
2184
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002185static int f71882fg_create_fan_sysfs_files(
Hans de Goede65434392011-09-09 12:12:35 +02002186 struct platform_device *pdev, int idx)
Hans de Goede9af07942011-09-09 12:12:34 +02002187{
2188 struct f71882fg_data *data = platform_get_drvdata(pdev);
2189 int err;
2190
Hans de Goede65434392011-09-09 12:12:35 +02002191 /* Sanity check the pwm setting */
2192 err = 0;
2193 switch (data->type) {
2194 case f71858fg:
2195 if (((data->pwm_enable >> (idx * 2)) & 3) == 3)
2196 err = 1;
2197 break;
2198 case f71862fg:
2199 if (((data->pwm_enable >> (idx * 2)) & 1) != 1)
2200 err = 1;
2201 break;
2202 case f8000:
2203 if (idx == 2)
2204 err = data->pwm_enable & 0x20;
2205 break;
2206 default:
2207 break;
2208 }
2209 if (err) {
2210 dev_err(&pdev->dev,
2211 "Invalid (reserved) pwm settings: 0x%02x, "
2212 "skipping fan %d\n",
2213 (data->pwm_enable >> (idx * 2)) & 3, idx + 1);
2214 return 0; /* This is a non fatal condition */
2215 }
2216
Hans de Goede9af07942011-09-09 12:12:34 +02002217 err = f71882fg_create_sysfs_files(pdev, &fxxxx_fan_attr[idx][0],
2218 ARRAY_SIZE(fxxxx_fan_attr[0]));
2219 if (err)
2220 return err;
2221
2222 if (f71882fg_fan_has_beep[data->type]) {
2223 err = f71882fg_create_sysfs_files(pdev,
2224 &fxxxx_fan_beep_attr[idx],
2225 1);
2226 if (err)
2227 return err;
2228 }
2229
Hans de Goede65434392011-09-09 12:12:35 +02002230 dev_info(&pdev->dev, "Fan: %d is in %s mode\n", idx + 1,
2231 (data->pwm_enable & (1 << (2 * idx))) ? "duty-cycle" : "RPM");
2232
2233 /* Check for unsupported auto pwm settings */
2234 switch (data->type) {
2235 case f71808e:
2236 case f71808a:
2237 case f71869:
2238 case f71869a:
2239 case f71889fg:
2240 case f71889ed:
2241 case f71889a:
2242 data->pwm_auto_point_mapping[idx] =
2243 f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(idx));
2244 if ((data->pwm_auto_point_mapping[idx] & 0x80) ||
2245 (data->pwm_auto_point_mapping[idx] & 3) == 0) {
2246 dev_warn(&pdev->dev,
2247 "Auto pwm controlled by raw digital "
2248 "data, disabling pwm auto_point "
2249 "sysfs attributes for fan %d\n", idx + 1);
2250 return 0; /* This is a non fatal condition */
2251 }
2252 break;
2253 default:
2254 break;
2255 }
Hans de Goede9af07942011-09-09 12:12:34 +02002256
2257 switch (data->type) {
2258 case f71862fg:
2259 err = f71882fg_create_sysfs_files(pdev,
2260 &f71862fg_auto_pwm_attr[idx][0],
2261 ARRAY_SIZE(f71862fg_auto_pwm_attr[0]));
2262 break;
2263 case f71808e:
2264 case f71869:
2265 err = f71882fg_create_sysfs_files(pdev,
2266 &f71869_auto_pwm_attr[idx][0],
2267 ARRAY_SIZE(f71869_auto_pwm_attr[0]));
2268 break;
2269 case f8000:
2270 err = f71882fg_create_sysfs_files(pdev,
2271 &f8000_auto_pwm_attr[idx][0],
2272 ARRAY_SIZE(f8000_auto_pwm_attr[0]));
2273 break;
2274 default:
2275 err = f71882fg_create_sysfs_files(pdev,
2276 &fxxxx_auto_pwm_attr[idx][0],
2277 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]));
2278 }
2279
2280 return err;
2281}
2282
Bill Pemberton6c931ae2012-11-19 13:22:35 -05002283static int f71882fg_probe(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002284{
2285 struct f71882fg_data *data;
Jingoo Hana8b3a3a2013-07-30 17:13:06 +09002286 struct f71882fg_sio_data *sio_data = dev_get_platdata(&pdev->dev);
Jean Delvaref27def02011-03-26 10:45:01 +01002287 int nr_fans = f71882fg_nr_fans[sio_data->type];
2288 int nr_temps = f71882fg_nr_temps[sio_data->type];
2289 int err, i;
Hans de Goede98f7ba12011-03-09 20:57:09 +01002290 u8 start_reg, reg;
Hans de Goede45fb3662007-07-13 14:34:19 +02002291
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002292 data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
2293 GFP_KERNEL);
Hans de Goedec13548c2009-01-07 16:37:27 +01002294 if (!data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002295 return -ENOMEM;
2296
2297 data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
Hans de Goede498be962009-01-07 16:37:28 +01002298 data->type = sio_data->type;
Hans de Goede09475d32009-06-15 18:39:52 +02002299 data->temp_start =
2300 (data->type == f71858fg || data->type == f8000) ? 0 : 1;
Hans de Goede45fb3662007-07-13 14:34:19 +02002301 mutex_init(&data->update_lock);
2302 platform_set_drvdata(pdev, data);
2303
Hans de Goede3cc74752009-01-07 16:37:28 +01002304 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede12d66e82009-01-07 16:37:29 +01002305 if (start_reg & 0x04) {
2306 dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002307 return -ENODEV;
Hans de Goede12d66e82009-01-07 16:37:29 +01002308 }
Hans de Goede3cc74752009-01-07 16:37:28 +01002309 if (!(start_reg & 0x03)) {
2310 dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
Guenter Roeck33cd66e2012-06-02 09:58:05 -07002311 return -ENODEV;
Hans de Goede3cc74752009-01-07 16:37:28 +01002312 }
2313
Hans de Goede45fb3662007-07-13 14:34:19 +02002314 /* Register sysfs interface files */
Hans de Goedec13548c2009-01-07 16:37:27 +01002315 err = device_create_file(&pdev->dev, &dev_attr_name);
2316 if (err)
2317 goto exit_unregister_sysfs;
2318
Hans de Goedec13548c2009-01-07 16:37:27 +01002319 if (start_reg & 0x01) {
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002320 switch (data->type) {
Hans de Goede09475d32009-06-15 18:39:52 +02002321 case f71858fg:
2322 data->temp_config =
2323 f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
2324 if (data->temp_config & 0x10)
Guenter Roeck20eaf722012-01-19 11:02:17 -08002325 /*
2326 * The f71858fg temperature alarms behave as
2327 * the f8000 alarms in this mode
2328 */
Hans de Goede09475d32009-06-15 18:39:52 +02002329 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002330 f8000_temp_attr,
2331 ARRAY_SIZE(f8000_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002332 else
2333 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002334 f71858fg_temp_attr,
2335 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goede09475d32009-06-15 18:39:52 +02002336 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002337 case f8000:
2338 err = f71882fg_create_sysfs_files(pdev,
2339 f8000_temp_attr,
2340 ARRAY_SIZE(f8000_temp_attr));
2341 break;
2342 default:
2343 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002344 &fxxxx_temp_attr[0][0],
2345 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002346 }
2347 if (err)
2348 goto exit_unregister_sysfs;
2349
Hans de Goede4d538112011-05-25 20:43:32 +02002350 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002351 err = f71882fg_create_sysfs_files(pdev,
2352 &fxxxx_temp_beep_attr[0][0],
2353 ARRAY_SIZE(fxxxx_temp_beep_attr[0])
2354 * nr_temps);
2355 if (err)
2356 goto exit_unregister_sysfs;
2357 }
2358
Hans de Goede0bae6402011-03-09 20:57:10 +01002359 for (i = 0; i < F71882FG_MAX_INS; i++) {
2360 if (f71882fg_has_in[data->type][i]) {
2361 err = device_create_file(&pdev->dev,
2362 &fxxxx_in_attr[i].dev_attr);
2363 if (err)
2364 goto exit_unregister_sysfs;
2365 }
2366 }
2367 if (f71882fg_has_in1_alarm[data->type]) {
Hans de Goede498be962009-01-07 16:37:28 +01002368 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede66344aa2009-12-09 20:35:59 +01002369 fxxxx_in1_alarm_attr,
2370 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goede498be962009-01-07 16:37:28 +01002371 if (err)
2372 goto exit_unregister_sysfs;
2373 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002374 }
2375
Hans de Goede45fb3662007-07-13 14:34:19 +02002376 if (start_reg & 0x02) {
Hans de Goede98f7ba12011-03-09 20:57:09 +01002377 switch (data->type) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002378 case f71808e:
Hans de Goede629c58b2011-05-25 20:43:32 +02002379 case f71808a:
Hans de Goedec11bb992011-03-09 20:57:15 +01002380 case f71869:
Hans de Goede5da556e2011-07-03 13:32:53 +02002381 case f71869a:
Hans de Goedee5e713c2011-03-10 08:54:02 +01002382 /* These always have signed auto point temps */
Hans de Goedec11bb992011-03-09 20:57:15 +01002383 data->auto_point_temp_signed = 1;
2384 /* Fall through to select correct fan/pwm reg bank! */
Hans de Goede98f7ba12011-03-09 20:57:09 +01002385 case f71889fg:
Hans de Goede3cad4022011-03-09 20:57:14 +01002386 case f71889ed:
Hans de Goedea66c1082011-03-26 10:45:02 +01002387 case f71889a:
Hans de Goede98f7ba12011-03-09 20:57:09 +01002388 reg = f71882fg_read8(data, F71882FG_REG_FAN_FAULT_T);
2389 if (reg & F71882FG_FAN_NEG_TEMP_EN)
2390 data->auto_point_temp_signed = 1;
Hans de Goede3cad4022011-03-09 20:57:14 +01002391 /* Ensure banked pwm registers point to right bank */
2392 reg &= ~F71882FG_FAN_PROG_SEL;
2393 f71882fg_write8(data, F71882FG_REG_FAN_FAULT_T, reg);
Hans de Goede98f7ba12011-03-09 20:57:09 +01002394 break;
2395 default:
2396 break;
2397 }
2398
Hans de Goede996cadb2009-06-15 18:39:51 +02002399 data->pwm_enable =
2400 f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
2401
Hans de Goede9af07942011-09-09 12:12:34 +02002402 for (i = 0; i < nr_fans; i++) {
Hans de Goede65434392011-09-09 12:12:35 +02002403 err = f71882fg_create_fan_sysfs_files(pdev, i);
Hans de Goede9af07942011-09-09 12:12:34 +02002404 if (err)
2405 goto exit_unregister_sysfs;
Hans de Goede9af07942011-09-09 12:12:34 +02002406 }
2407
2408 /* Some types have 1 extra fan with limited functionality */
Hans de Goedee48a7f12011-03-09 20:57:13 +01002409 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002410 case f71808a:
2411 err = f71882fg_create_sysfs_files(pdev,
Hans de Goede629c58b2011-05-25 20:43:32 +02002412 f71808a_fan3_attr,
2413 ARRAY_SIZE(f71808a_fan3_attr));
2414 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002415 case f8000:
2416 err = f71882fg_create_sysfs_files(pdev,
2417 f8000_fan_attr,
2418 ARRAY_SIZE(f8000_fan_attr));
2419 break;
Hans de Goedee48a7f12011-03-09 20:57:13 +01002420 default:
Hans de Goede9af07942011-09-09 12:12:34 +02002421 break;
Hans de Goede498be962009-01-07 16:37:28 +01002422 }
Hans de Goedec13548c2009-01-07 16:37:27 +01002423 if (err)
2424 goto exit_unregister_sysfs;
Hans de Goede45fb3662007-07-13 14:34:19 +02002425 }
2426
Tony Jones1beeffe2007-08-20 13:46:20 -07002427 data->hwmon_dev = hwmon_device_register(&pdev->dev);
2428 if (IS_ERR(data->hwmon_dev)) {
2429 err = PTR_ERR(data->hwmon_dev);
Hans de Goedec13548c2009-01-07 16:37:27 +01002430 data->hwmon_dev = NULL;
Hans de Goede45fb3662007-07-13 14:34:19 +02002431 goto exit_unregister_sysfs;
2432 }
2433
2434 return 0;
2435
2436exit_unregister_sysfs:
Hans de Goedec13548c2009-01-07 16:37:27 +01002437 f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
Hans de Goede3cc74752009-01-07 16:37:28 +01002438 return err; /* f71882fg_remove() also frees our data */
Hans de Goede45fb3662007-07-13 14:34:19 +02002439}
2440
Hans de Goedec13548c2009-01-07 16:37:27 +01002441static int f71882fg_remove(struct platform_device *pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002442{
Hans de Goede45fb3662007-07-13 14:34:19 +02002443 struct f71882fg_data *data = platform_get_drvdata(pdev);
Jean Delvaref27def02011-03-26 10:45:01 +01002444 int nr_fans = f71882fg_nr_fans[data->type];
2445 int nr_temps = f71882fg_nr_temps[data->type];
2446 int i;
Hans de Goedefc16c562009-12-09 20:36:01 +01002447 u8 start_reg = f71882fg_read8(data, F71882FG_REG_START);
Hans de Goede45fb3662007-07-13 14:34:19 +02002448
Hans de Goedec13548c2009-01-07 16:37:27 +01002449 if (data->hwmon_dev)
2450 hwmon_device_unregister(data->hwmon_dev);
Hans de Goede45fb3662007-07-13 14:34:19 +02002451
Hans de Goedec13548c2009-01-07 16:37:27 +01002452 device_remove_file(&pdev->dev, &dev_attr_name);
Hans de Goede45fb3662007-07-13 14:34:19 +02002453
Hans de Goedefc16c562009-12-09 20:36:01 +01002454 if (start_reg & 0x01) {
2455 switch (data->type) {
2456 case f71858fg:
2457 if (data->temp_config & 0x10)
2458 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002459 f8000_temp_attr,
2460 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002461 else
2462 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002463 f71858fg_temp_attr,
2464 ARRAY_SIZE(f71858fg_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002465 break;
2466 case f8000:
2467 f71882fg_remove_sysfs_files(pdev,
Hans de Goede0bae6402011-03-09 20:57:10 +01002468 f8000_temp_attr,
2469 ARRAY_SIZE(f8000_temp_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002470 break;
Hans de Goede0bae6402011-03-09 20:57:10 +01002471 default:
2472 f71882fg_remove_sysfs_files(pdev,
Hans de Goede60d2b372011-03-09 20:57:11 +01002473 &fxxxx_temp_attr[0][0],
2474 ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
Hans de Goede0bae6402011-03-09 20:57:10 +01002475 }
Hans de Goede4d538112011-05-25 20:43:32 +02002476 if (f71882fg_temp_has_beep[data->type]) {
Hans de Goede78aa4f72011-03-09 20:57:12 +01002477 f71882fg_remove_sysfs_files(pdev,
2478 &fxxxx_temp_beep_attr[0][0],
2479 ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
2480 }
2481
Hans de Goede0bae6402011-03-09 20:57:10 +01002482 for (i = 0; i < F71882FG_MAX_INS; i++) {
2483 if (f71882fg_has_in[data->type][i]) {
2484 device_remove_file(&pdev->dev,
2485 &fxxxx_in_attr[i].dev_attr);
2486 }
2487 }
2488 if (f71882fg_has_in1_alarm[data->type]) {
2489 f71882fg_remove_sysfs_files(pdev,
2490 fxxxx_in1_alarm_attr,
2491 ARRAY_SIZE(fxxxx_in1_alarm_attr));
Hans de Goedefc16c562009-12-09 20:36:01 +01002492 }
2493 }
Hans de Goede498be962009-01-07 16:37:28 +01002494
Hans de Goedefc16c562009-12-09 20:36:01 +01002495 if (start_reg & 0x02) {
2496 f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
2497 ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
Hans de Goede45fb3662007-07-13 14:34:19 +02002498
Hans de Goede4d538112011-05-25 20:43:32 +02002499 if (f71882fg_fan_has_beep[data->type]) {
Hans de Goedefc16c562009-12-09 20:36:01 +01002500 f71882fg_remove_sysfs_files(pdev,
2501 fxxxx_fan_beep_attr, nr_fans);
Hans de Goede78aa4f72011-03-09 20:57:12 +01002502 }
Hans de Goede498be962009-01-07 16:37:28 +01002503
Hans de Goedefc16c562009-12-09 20:36:01 +01002504 switch (data->type) {
Hans de Goede629c58b2011-05-25 20:43:32 +02002505 case f71808a:
2506 f71882fg_remove_sysfs_files(pdev,
2507 &fxxxx_auto_pwm_attr[0][0],
2508 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2509 f71882fg_remove_sysfs_files(pdev,
2510 f71808a_fan3_attr,
2511 ARRAY_SIZE(f71808a_fan3_attr));
2512 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002513 case f71862fg:
2514 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002515 &f71862fg_auto_pwm_attr[0][0],
2516 ARRAY_SIZE(f71862fg_auto_pwm_attr[0]) *
2517 nr_fans);
Hans de Goedefc16c562009-12-09 20:36:01 +01002518 break;
Hans de Goedee5e713c2011-03-10 08:54:02 +01002519 case f71808e:
Hans de Goedec11bb992011-03-09 20:57:15 +01002520 case f71869:
2521 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002522 &f71869_auto_pwm_attr[0][0],
2523 ARRAY_SIZE(f71869_auto_pwm_attr[0]) * nr_fans);
Hans de Goedec11bb992011-03-09 20:57:15 +01002524 break;
Hans de Goedefc16c562009-12-09 20:36:01 +01002525 case f8000:
2526 f71882fg_remove_sysfs_files(pdev,
2527 f8000_fan_attr,
2528 ARRAY_SIZE(f8000_fan_attr));
2529 f71882fg_remove_sysfs_files(pdev,
Hans de Goede55840142011-09-09 12:12:33 +02002530 &f8000_auto_pwm_attr[0][0],
2531 ARRAY_SIZE(f8000_auto_pwm_attr[0]) * nr_fans);
Hans de Goedefc16c562009-12-09 20:36:01 +01002532 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002533 default:
Hans de Goedefc16c562009-12-09 20:36:01 +01002534 f71882fg_remove_sysfs_files(pdev,
2535 &fxxxx_auto_pwm_attr[0][0],
2536 ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
2537 }
2538 }
Hans de Goede45fb3662007-07-13 14:34:19 +02002539 return 0;
2540}
2541
Guenter Roeck00383892012-08-04 09:46:36 -07002542static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002543{
Hans de Goede45fb3662007-07-13 14:34:19 +02002544 u16 devid;
Guenter Roeck00383892012-08-04 09:46:36 -07002545 unsigned short address;
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002546 int err = superio_enter(sioaddr);
2547 if (err)
2548 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002549
2550 devid = superio_inw(sioaddr, SIO_REG_MANID);
2551 if (devid != SIO_FINTEK_ID) {
Joe Perches22d3b412010-10-20 06:51:34 +00002552 pr_debug("Not a Fintek device\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002553 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002554 goto exit;
2555 }
2556
Jean Delvare67b671b2007-12-06 23:13:42 +01002557 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
Hans de Goede498be962009-01-07 16:37:28 +01002558 switch (devid) {
Hans de Goedee5e713c2011-03-10 08:54:02 +01002559 case SIO_F71808E_ID:
2560 sio_data->type = f71808e;
2561 break;
Hans de Goede629c58b2011-05-25 20:43:32 +02002562 case SIO_F71808A_ID:
2563 sio_data->type = f71808a;
2564 break;
Hans de Goede09475d32009-06-15 18:39:52 +02002565 case SIO_F71858_ID:
2566 sio_data->type = f71858fg;
2567 break;
Hans de Goede498be962009-01-07 16:37:28 +01002568 case SIO_F71862_ID:
2569 sio_data->type = f71862fg;
2570 break;
Peter Hung2725fe22015-07-07 16:22:36 +08002571 case SIO_F71868_ID:
2572 sio_data->type = f71868a;
2573 break;
Hans de Goedec11bb992011-03-09 20:57:15 +01002574 case SIO_F71869_ID:
2575 sio_data->type = f71869;
2576 break;
Hans de Goede5da556e2011-07-03 13:32:53 +02002577 case SIO_F71869A_ID:
2578 sio_data->type = f71869a;
2579 break;
Hans de Goede498be962009-01-07 16:37:28 +01002580 case SIO_F71882_ID:
2581 sio_data->type = f71882fg;
2582 break;
Hans de Goede76698962009-12-09 20:36:01 +01002583 case SIO_F71889_ID:
2584 sio_data->type = f71889fg;
2585 break;
Hans de Goede3cad4022011-03-09 20:57:14 +01002586 case SIO_F71889E_ID:
2587 sio_data->type = f71889ed;
2588 break;
Hans de Goedea66c1082011-03-26 10:45:02 +01002589 case SIO_F71889A_ID:
2590 sio_data->type = f71889a;
2591 break;
Hans de Goedeed4f7c22009-01-07 16:37:30 +01002592 case SIO_F8000_ID:
2593 sio_data->type = f8000;
2594 break;
Jean Delvare383586b2011-03-26 10:45:02 +01002595 case SIO_F81865_ID:
2596 sio_data->type = f81865f;
2597 break;
Peter Hung2725fe22015-07-07 16:22:36 +08002598 case SIO_F81866_ID:
2599 sio_data->type = f81866a;
2600 break;
Hans de Goede498be962009-01-07 16:37:28 +01002601 default:
Joe Perches22d3b412010-10-20 06:51:34 +00002602 pr_info("Unsupported Fintek device: %04x\n",
2603 (unsigned int)devid);
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002604 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002605 goto exit;
2606 }
2607
Hans de Goede09475d32009-06-15 18:39:52 +02002608 if (sio_data->type == f71858fg)
2609 superio_select(sioaddr, SIO_F71858FG_LD_HWM);
2610 else
2611 superio_select(sioaddr, SIO_F71882FG_LD_HWM);
2612
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002613 if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
Joe Perches22d3b412010-10-20 06:51:34 +00002614 pr_warn("Device not activated\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002615 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002616 goto exit;
2617 }
2618
Guenter Roeck00383892012-08-04 09:46:36 -07002619 address = superio_inw(sioaddr, SIO_REG_ADDR);
2620 if (address == 0) {
Joe Perches22d3b412010-10-20 06:51:34 +00002621 pr_warn("Base address not set\n");
Giel van Schijndelcadb8652010-10-03 08:09:49 -04002622 err = -ENODEV;
Hans de Goede45fb3662007-07-13 14:34:19 +02002623 goto exit;
2624 }
Guenter Roeck00383892012-08-04 09:46:36 -07002625 address &= ~(REGION_LENGTH - 1); /* Ignore 3 LSB */
Hans de Goede45fb3662007-07-13 14:34:19 +02002626
Guenter Roeck00383892012-08-04 09:46:36 -07002627 err = address;
Joe Perches22d3b412010-10-20 06:51:34 +00002628 pr_info("Found %s chip at %#x, revision %d\n",
Guenter Roeck00383892012-08-04 09:46:36 -07002629 f71882fg_names[sio_data->type], (unsigned int)address,
Hans de Goede45fb3662007-07-13 14:34:19 +02002630 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
2631exit:
2632 superio_exit(sioaddr);
2633 return err;
2634}
2635
Guenter Roeck00383892012-08-04 09:46:36 -07002636static int __init f71882fg_device_add(int address,
2637 const struct f71882fg_sio_data *sio_data)
Hans de Goede45fb3662007-07-13 14:34:19 +02002638{
2639 struct resource res = {
2640 .start = address,
2641 .end = address + REGION_LENGTH - 1,
2642 .flags = IORESOURCE_IO,
2643 };
2644 int err;
2645
2646 f71882fg_pdev = platform_device_alloc(DRVNAME, address);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002647 if (!f71882fg_pdev)
Hans de Goede45fb3662007-07-13 14:34:19 +02002648 return -ENOMEM;
2649
2650 res.name = f71882fg_pdev->name;
Jean Delvareb9acb642009-01-07 16:37:35 +01002651 err = acpi_check_resource_conflict(&res);
2652 if (err)
Hans de Goede18632f82009-02-17 19:59:54 +01002653 goto exit_device_put;
Jean Delvareb9acb642009-01-07 16:37:35 +01002654
Hans de Goede45fb3662007-07-13 14:34:19 +02002655 err = platform_device_add_resources(f71882fg_pdev, &res, 1);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002656 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002657 pr_err("Device resource addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002658 goto exit_device_put;
2659 }
2660
Hans de Goede498be962009-01-07 16:37:28 +01002661 err = platform_device_add_data(f71882fg_pdev, sio_data,
2662 sizeof(struct f71882fg_sio_data));
2663 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002664 pr_err("Platform data allocation failed\n");
Hans de Goede498be962009-01-07 16:37:28 +01002665 goto exit_device_put;
2666 }
2667
Hans de Goede45fb3662007-07-13 14:34:19 +02002668 err = platform_device_add(f71882fg_pdev);
Mark M. Hoffman8afb1042007-08-21 23:10:46 -04002669 if (err) {
Joe Perches22d3b412010-10-20 06:51:34 +00002670 pr_err("Device addition failed\n");
Hans de Goede45fb3662007-07-13 14:34:19 +02002671 goto exit_device_put;
2672 }
2673
2674 return 0;
2675
2676exit_device_put:
2677 platform_device_put(f71882fg_pdev);
2678
2679 return err;
2680}
2681
2682static int __init f71882fg_init(void)
2683{
Guenter Roeck00383892012-08-04 09:46:36 -07002684 int err;
2685 int address;
Hans de Goede498be962009-01-07 16:37:28 +01002686 struct f71882fg_sio_data sio_data;
Hans de Goede45fb3662007-07-13 14:34:19 +02002687
Hans de Goede498be962009-01-07 16:37:28 +01002688 memset(&sio_data, 0, sizeof(sio_data));
2689
Guenter Roeck00383892012-08-04 09:46:36 -07002690 address = f71882fg_find(0x2e, &sio_data);
2691 if (address < 0)
2692 address = f71882fg_find(0x4e, &sio_data);
2693 if (address < 0)
2694 return address;
Hans de Goede45fb3662007-07-13 14:34:19 +02002695
Hans de Goedec13548c2009-01-07 16:37:27 +01002696 err = platform_driver_register(&f71882fg_driver);
2697 if (err)
Guenter Roeck00383892012-08-04 09:46:36 -07002698 return err;
Hans de Goede45fb3662007-07-13 14:34:19 +02002699
Hans de Goede498be962009-01-07 16:37:28 +01002700 err = f71882fg_device_add(address, &sio_data);
Hans de Goedec13548c2009-01-07 16:37:27 +01002701 if (err)
Hans de Goede45fb3662007-07-13 14:34:19 +02002702 goto exit_driver;
2703
2704 return 0;
2705
2706exit_driver:
2707 platform_driver_unregister(&f71882fg_driver);
Hans de Goede45fb3662007-07-13 14:34:19 +02002708 return err;
2709}
2710
2711static void __exit f71882fg_exit(void)
2712{
2713 platform_device_unregister(f71882fg_pdev);
2714 platform_driver_unregister(&f71882fg_driver);
2715}
2716
2717MODULE_DESCRIPTION("F71882FG Hardware Monitoring Driver");
Hans de Goede7958e3b2011-07-03 13:32:53 +02002718MODULE_AUTHOR("Hans Edgington, Hans de Goede <hdegoede@redhat.com>");
Hans de Goede45fb3662007-07-13 14:34:19 +02002719MODULE_LICENSE("GPL");
2720
2721module_init(f71882fg_init);
2722module_exit(f71882fg_exit);