xref: /linux/drivers/hwmon/w83627ehf.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
208e7e278SJean Delvare /*
38969e84dSGuenter Roeck  *  w83627ehf - Driver for the hardware monitoring functionality of
48969e84dSGuenter Roeck  *		the Winbond W83627EHF Super-I/O chip
57c81c60fSJean Delvare  *  Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
68969e84dSGuenter Roeck  *  Copyright (C) 2006  Yuan Mu (Winbond),
78969e84dSGuenter Roeck  *			Rudolf Marek <r.marek@assembler.cz>
88969e84dSGuenter Roeck  *			David Hubbard <david.c.hubbard@gmail.com>
98969e84dSGuenter Roeck  *			Daniel J Blueman <daniel.blueman@gmail.com>
108969e84dSGuenter Roeck  *  Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
118969e84dSGuenter Roeck  *
128969e84dSGuenter Roeck  *  Shamelessly ripped from the w83627hf driver
138969e84dSGuenter Roeck  *  Copyright (C) 2003  Mark Studebaker
148969e84dSGuenter Roeck  *
158969e84dSGuenter Roeck  *  Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
168969e84dSGuenter Roeck  *  in testing and debugging this driver.
178969e84dSGuenter Roeck  *
188969e84dSGuenter Roeck  *  This driver also supports the W83627EHG, which is the lead-free
198969e84dSGuenter Roeck  *  version of the W83627EHF.
208969e84dSGuenter Roeck  *
218969e84dSGuenter Roeck  *  Supports the following chips:
228969e84dSGuenter Roeck  *
238969e84dSGuenter Roeck  *  Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
248969e84dSGuenter Roeck  *  w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
258969e84dSGuenter Roeck  *					       0x8860 0xa1
268969e84dSGuenter Roeck  *  w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
278969e84dSGuenter Roeck  *  w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
288969e84dSGuenter Roeck  *  w83627uhg    8      2       2       3      0xa230 0xc1    0x5ca3
298969e84dSGuenter Roeck  *  w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
308969e84dSGuenter Roeck  *  w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
3108e7e278SJean Delvare  */
3208e7e278SJean Delvare 
33abdc6fd1SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34abdc6fd1SJoe Perches 
3508e7e278SJean Delvare #include <linux/module.h>
3608e7e278SJean Delvare #include <linux/init.h>
3708e7e278SJean Delvare #include <linux/slab.h>
381ea6dd38SDavid Hubbard #include <linux/jiffies.h>
391ea6dd38SDavid Hubbard #include <linux/platform_device.h>
40943b0830SMark M. Hoffman #include <linux/hwmon.h>
41412fec82SYuan Mu #include <linux/hwmon-sysfs.h>
42fc18d6c0SJean Delvare #include <linux/hwmon-vid.h>
43943b0830SMark M. Hoffman #include <linux/err.h>
449a61bf63SIngo Molnar #include <linux/mutex.h>
45b9acb64aSJean Delvare #include <linux/acpi.h>
466055fae8SH Hartley Sweeten #include <linux/io.h>
4708e7e278SJean Delvare #include "lm75.h"
4808e7e278SJean Delvare 
49eff7687dSJean Delvare enum kinds {
50eff7687dSJean Delvare 	w83627ehf, w83627dhg, w83627dhg_p, w83627uhg,
513207408aSDr. David Alan Gilbert 	w83667hg, w83667hg_b,
52eff7687dSJean Delvare };
531ea6dd38SDavid Hubbard 
541ea6dd38SDavid Hubbard /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
55e7e1ca6eSGuenter Roeck static const char * const w83627ehf_device_names[] = {
561ea6dd38SDavid Hubbard 	"w83627ehf",
571ea6dd38SDavid Hubbard 	"w83627dhg",
58c1e48dceSJean Delvare 	"w83627dhg",
59eff7687dSJean Delvare 	"w83627uhg",
60237c8d2fSGong Jun 	"w83667hg",
61c39aedafSGuenter Roeck 	"w83667hg",
621ea6dd38SDavid Hubbard };
631ea6dd38SDavid Hubbard 
6467b671bcSJean Delvare static unsigned short force_id;
6567b671bcSJean Delvare module_param(force_id, ushort, 0);
6667b671bcSJean Delvare MODULE_PARM_DESC(force_id, "Override the detected device ID");
6767b671bcSJean Delvare 
681ea6dd38SDavid Hubbard #define DRVNAME "w83627ehf"
6908e7e278SJean Delvare 
7008e7e278SJean Delvare /*
7108e7e278SJean Delvare  * Super-I/O constants and functions
7208e7e278SJean Delvare  */
7308e7e278SJean Delvare 
7408e7e278SJean Delvare #define W83627EHF_LD_HWM	0x0b
75237c8d2fSGong Jun #define W83667HG_LD_VID		0x0d
7608e7e278SJean Delvare 
7708e7e278SJean Delvare #define SIO_REG_LDSEL		0x07	/* Logical device select */
7808e7e278SJean Delvare #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
79fc18d6c0SJean Delvare #define SIO_REG_EN_VRM10	0x2C	/* GPIO3, GPIO4 selection */
8008e7e278SJean Delvare #define SIO_REG_ENABLE		0x30	/* Logical device enable */
8108e7e278SJean Delvare #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
82fc18d6c0SJean Delvare #define SIO_REG_VID_CTRL	0xF0	/* VID control */
83fc18d6c0SJean Delvare #define SIO_REG_VID_DATA	0xF1	/* VID data */
8408e7e278SJean Delvare 
85657c93b1SDavid Hubbard #define SIO_W83627EHF_ID	0x8850
86657c93b1SDavid Hubbard #define SIO_W83627EHG_ID	0x8860
87657c93b1SDavid Hubbard #define SIO_W83627DHG_ID	0xa020
88c1e48dceSJean Delvare #define SIO_W83627DHG_P_ID	0xb070
89eff7687dSJean Delvare #define SIO_W83627UHG_ID	0xa230
90237c8d2fSGong Jun #define SIO_W83667HG_ID		0xa510
91c39aedafSGuenter Roeck #define SIO_W83667HG_B_ID	0xb350
92657c93b1SDavid Hubbard #define SIO_ID_MASK		0xFFF0
9308e7e278SJean Delvare 
9408e7e278SJean Delvare static inline void
superio_outb(int ioreg,int reg,int val)951ea6dd38SDavid Hubbard superio_outb(int ioreg, int reg, int val)
9608e7e278SJean Delvare {
971ea6dd38SDavid Hubbard 	outb(reg, ioreg);
981ea6dd38SDavid Hubbard 	outb(val, ioreg + 1);
9908e7e278SJean Delvare }
10008e7e278SJean Delvare 
10108e7e278SJean Delvare static inline int
superio_inb(int ioreg,int reg)1021ea6dd38SDavid Hubbard superio_inb(int ioreg, int reg)
10308e7e278SJean Delvare {
1041ea6dd38SDavid Hubbard 	outb(reg, ioreg);
1051ea6dd38SDavid Hubbard 	return inb(ioreg + 1);
10608e7e278SJean Delvare }
10708e7e278SJean Delvare 
10808e7e278SJean Delvare static inline void
superio_select(int ioreg,int ld)1091ea6dd38SDavid Hubbard superio_select(int ioreg, int ld)
11008e7e278SJean Delvare {
1111ea6dd38SDavid Hubbard 	outb(SIO_REG_LDSEL, ioreg);
1121ea6dd38SDavid Hubbard 	outb(ld, ioreg + 1);
11308e7e278SJean Delvare }
11408e7e278SJean Delvare 
1150d023530SKatsumi Sato static inline int
superio_enter(int ioreg)1161ea6dd38SDavid Hubbard superio_enter(int ioreg)
11708e7e278SJean Delvare {
1180d023530SKatsumi Sato 	if (!request_muxed_region(ioreg, 2, DRVNAME))
1190d023530SKatsumi Sato 		return -EBUSY;
1200d023530SKatsumi Sato 
1211ea6dd38SDavid Hubbard 	outb(0x87, ioreg);
1221ea6dd38SDavid Hubbard 	outb(0x87, ioreg);
1230d023530SKatsumi Sato 
1240d023530SKatsumi Sato 	return 0;
12508e7e278SJean Delvare }
12608e7e278SJean Delvare 
12708e7e278SJean Delvare static inline void
superio_exit(int ioreg)1281ea6dd38SDavid Hubbard superio_exit(int ioreg)
12908e7e278SJean Delvare {
130022b75a3SJonas Jonsson 	outb(0xaa, ioreg);
1311ea6dd38SDavid Hubbard 	outb(0x02, ioreg);
1321ea6dd38SDavid Hubbard 	outb(0x02, ioreg + 1);
1330d023530SKatsumi Sato 	release_region(ioreg, 2);
13408e7e278SJean Delvare }
13508e7e278SJean Delvare 
13608e7e278SJean Delvare /*
13708e7e278SJean Delvare  * ISA constants
13808e7e278SJean Delvare  */
13908e7e278SJean Delvare 
140e7e1ca6eSGuenter Roeck #define IOREGION_ALIGNMENT	(~7)
1411a641fceSJean Delvare #define IOREGION_OFFSET		5
1421a641fceSJean Delvare #define IOREGION_LENGTH		2
1431ea6dd38SDavid Hubbard #define ADDR_REG_OFFSET		0
1441ea6dd38SDavid Hubbard #define DATA_REG_OFFSET		1
14508e7e278SJean Delvare 
14608e7e278SJean Delvare #define W83627EHF_REG_BANK		0x4E
14708e7e278SJean Delvare #define W83627EHF_REG_CONFIG		0x40
148657c93b1SDavid Hubbard 
1498969e84dSGuenter Roeck /*
1508969e84dSGuenter Roeck  * Not currently used:
151657c93b1SDavid Hubbard  * REG_MAN_ID has the value 0x5ca3 for all supported chips.
152657c93b1SDavid Hubbard  * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
153657c93b1SDavid Hubbard  * REG_MAN_ID is at port 0x4f
1548969e84dSGuenter Roeck  * REG_CHIP_ID is at port 0x58
1558969e84dSGuenter Roeck  */
15608e7e278SJean Delvare 
15708e7e278SJean Delvare static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
15808e7e278SJean Delvare static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
15908e7e278SJean Delvare 
160cf0676feSRudolf Marek /* The W83627EHF registers for nr=7,8,9 are in bank 5 */
161cf0676feSRudolf Marek #define W83627EHF_REG_IN_MAX(nr)	((nr < 7) ? (0x2b + (nr) * 2) : \
162cf0676feSRudolf Marek 					 (0x554 + (((nr) - 7) * 2)))
163cf0676feSRudolf Marek #define W83627EHF_REG_IN_MIN(nr)	((nr < 7) ? (0x2c + (nr) * 2) : \
164cf0676feSRudolf Marek 					 (0x555 + (((nr) - 7) * 2)))
165cf0676feSRudolf Marek #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
166cf0676feSRudolf Marek 					 (0x550 + (nr) - 7))
167cf0676feSRudolf Marek 
168d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
169d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
170d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
171d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
17208e7e278SJean Delvare 
17308e7e278SJean Delvare /* Fan clock dividers are spread over the following five registers */
17408e7e278SJean Delvare #define W83627EHF_REG_FANDIV1		0x47
17508e7e278SJean Delvare #define W83627EHF_REG_FANDIV2		0x4B
17608e7e278SJean Delvare #define W83627EHF_REG_VBAT		0x5D
17708e7e278SJean Delvare #define W83627EHF_REG_DIODE		0x59
17808e7e278SJean Delvare #define W83627EHF_REG_SMI_OVT		0x4C
17908e7e278SJean Delvare 
180a4589dbbSJean Delvare #define W83627EHF_REG_ALARM1		0x459
181a4589dbbSJean Delvare #define W83627EHF_REG_ALARM2		0x45A
182a4589dbbSJean Delvare #define W83627EHF_REG_ALARM3		0x45B
183a4589dbbSJean Delvare 
184363a12a4SDmitry Artamonow #define W83627EHF_REG_CASEOPEN_DET	0x42 /* SMI STATUS #2 */
185363a12a4SDmitry Artamonow #define W83627EHF_REG_CASEOPEN_CLR	0x46 /* SMI MASK #3 */
186363a12a4SDmitry Artamonow 
18708c79950SRudolf Marek /* SmartFan registers */
18841e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
18941e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
19041e9a062SDaniel J Blueman 
19108c79950SRudolf Marek /* DC or PWM output fan configuration */
19208c79950SRudolf Marek static const u8 W83627EHF_REG_PWM_ENABLE[] = {
19308c79950SRudolf Marek 	0x04,			/* SYS FAN0 output mode and PWM mode */
19408c79950SRudolf Marek 	0x04,			/* CPU FAN0 output mode and PWM mode */
19508c79950SRudolf Marek 	0x12,			/* AUX FAN mode */
19641e9a062SDaniel J Blueman 	0x62,			/* CPU FAN1 mode */
19708c79950SRudolf Marek };
19808c79950SRudolf Marek 
19908c79950SRudolf Marek static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
20008c79950SRudolf Marek static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
20108c79950SRudolf Marek 
20208c79950SRudolf Marek /* FAN Duty Cycle, be used to control */
203279af1a9SGuenter Roeck static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
204279af1a9SGuenter Roeck static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
20508c79950SRudolf Marek static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
20608c79950SRudolf Marek 
20708c79950SRudolf Marek /* Advanced Fan control, some values are common for all fans */
208279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
209279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
210279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
211c39aedafSGuenter Roeck 
212279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
213c39aedafSGuenter Roeck 						= { 0xff, 0x67, 0xff, 0x69 };
214279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
215c39aedafSGuenter Roeck 						= { 0xff, 0x68, 0xff, 0x6a };
216c39aedafSGuenter Roeck 
217279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
218279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
219279af1a9SGuenter Roeck 						= { 0x68, 0x6a, 0x6c };
22008c79950SRudolf Marek 
221840e191dSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OFFSET[] = { 0x454, 0x455, 0x456 };
222840e191dSGuenter Roeck 
223d36cf32cSGuenter Roeck static const char *const w83667hg_b_temp_label[] = {
224d36cf32cSGuenter Roeck 	"SYSTIN",
225d36cf32cSGuenter Roeck 	"CPUTIN",
226d36cf32cSGuenter Roeck 	"AUXTIN",
227d36cf32cSGuenter Roeck 	"AMDTSI",
228d36cf32cSGuenter Roeck 	"PECI Agent 1",
229d36cf32cSGuenter Roeck 	"PECI Agent 2",
230d36cf32cSGuenter Roeck 	"PECI Agent 3",
231d36cf32cSGuenter Roeck 	"PECI Agent 4"
232d36cf32cSGuenter Roeck };
233d36cf32cSGuenter Roeck 
2343207408aSDr. David Alan Gilbert #define NUM_REG_TEMP	ARRAY_SIZE(W83627EHF_REG_TEMP)
235d36cf32cSGuenter Roeck 
is_word_sized(u16 reg)23617296febSJean Delvare static int is_word_sized(u16 reg)
237bce26c58SGuenter Roeck {
238ec3e5a16SGuenter Roeck 	return ((((reg & 0xff00) == 0x100
239bce26c58SGuenter Roeck 	      || (reg & 0xff00) == 0x200)
240bce26c58SGuenter Roeck 	     && ((reg & 0x00ff) == 0x50
241bce26c58SGuenter Roeck 	      || (reg & 0x00ff) == 0x53
242ec3e5a16SGuenter Roeck 	      || (reg & 0x00ff) == 0x55))
243ec3e5a16SGuenter Roeck 	     || (reg & 0xfff0) == 0x630
244ec3e5a16SGuenter Roeck 	     || reg == 0x640 || reg == 0x642
245ec3e5a16SGuenter Roeck 	     || ((reg & 0xfff0) == 0x650
246ec3e5a16SGuenter Roeck 		 && (reg & 0x000f) >= 0x06)
247ec3e5a16SGuenter Roeck 	     || reg == 0x73 || reg == 0x75 || reg == 0x77
248ec3e5a16SGuenter Roeck 		);
249bce26c58SGuenter Roeck }
250bce26c58SGuenter Roeck 
25108e7e278SJean Delvare /*
25208e7e278SJean Delvare  * Conversions
25308e7e278SJean Delvare  */
25408e7e278SJean Delvare 
25508c79950SRudolf Marek /* 1 is PWM mode, output in ms */
step_time_from_reg(u8 reg,u8 mode)25608c79950SRudolf Marek static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
25708c79950SRudolf Marek {
25808c79950SRudolf Marek 	return mode ? 100 * reg : 400 * reg;
25908c79950SRudolf Marek }
26008c79950SRudolf Marek 
step_time_to_reg(unsigned int msec,u8 mode)26108c79950SRudolf Marek static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
26208c79950SRudolf Marek {
2632a844c14SGuenter Roeck 	return clamp_val((mode ? (msec + 50) / 100 : (msec + 200) / 400),
2642a844c14SGuenter Roeck 			 1, 255);
26508c79950SRudolf Marek }
26608c79950SRudolf Marek 
fan_from_reg8(u16 reg,unsigned int divreg)26726bc440eSGuenter Roeck static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
26808e7e278SJean Delvare {
26926bc440eSGuenter Roeck 	if (reg == 0 || reg == 255)
27008e7e278SJean Delvare 		return 0;
27126bc440eSGuenter Roeck 	return 1350000U / (reg << divreg);
272ec3e5a16SGuenter Roeck }
27326bc440eSGuenter Roeck 
27408e7e278SJean Delvare static inline unsigned int
div_from_reg(u8 reg)27508e7e278SJean Delvare div_from_reg(u8 reg)
27608e7e278SJean Delvare {
27708e7e278SJean Delvare 	return 1 << reg;
27808e7e278SJean Delvare }
27908e7e278SJean Delvare 
2808969e84dSGuenter Roeck /*
2818969e84dSGuenter Roeck  * Some of the voltage inputs have internal scaling, the tables below
2828969e84dSGuenter Roeck  * contain 8 (the ADC LSB in mV) * scaling factor * 100
2838969e84dSGuenter Roeck  */
284eff7687dSJean Delvare static const u16 scale_in_common[10] = {
285eff7687dSJean Delvare 	800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800
286eff7687dSJean Delvare };
287eff7687dSJean Delvare static const u16 scale_in_w83627uhg[9] = {
288eff7687dSJean Delvare 	800, 800, 3328, 3424, 800, 800, 0, 3328, 3400
289eff7687dSJean Delvare };
290cf0676feSRudolf Marek 
in_from_reg(u8 reg,u8 nr,const u16 * scale_in)291eff7687dSJean Delvare static inline long in_from_reg(u8 reg, u8 nr, const u16 *scale_in)
292cf0676feSRudolf Marek {
293eff7687dSJean Delvare 	return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100);
294cf0676feSRudolf Marek }
295cf0676feSRudolf Marek 
in_to_reg(u32 val,u8 nr,const u16 * scale_in)296eff7687dSJean Delvare static inline u8 in_to_reg(u32 val, u8 nr, const u16 *scale_in)
297cf0676feSRudolf Marek {
2982a844c14SGuenter Roeck 	return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255);
299cf0676feSRudolf Marek }
300cf0676feSRudolf Marek 
30108e7e278SJean Delvare /*
30208e7e278SJean Delvare  * Data structures and manipulation thereof
30308e7e278SJean Delvare  */
30408e7e278SJean Delvare 
30508e7e278SJean Delvare struct w83627ehf_data {
3061ea6dd38SDavid Hubbard 	int addr;	/* IO base of hw monitor block */
3071ea6dd38SDavid Hubbard 	const char *name;
3081ea6dd38SDavid Hubbard 
3099a61bf63SIngo Molnar 	struct mutex lock;
31008e7e278SJean Delvare 
311ec3e5a16SGuenter Roeck 	u16 reg_temp[NUM_REG_TEMP];
312ec3e5a16SGuenter Roeck 	u16 reg_temp_over[NUM_REG_TEMP];
313ec3e5a16SGuenter Roeck 	u16 reg_temp_hyst[NUM_REG_TEMP];
314ec3e5a16SGuenter Roeck 	u16 reg_temp_config[NUM_REG_TEMP];
315d36cf32cSGuenter Roeck 	u8 temp_src[NUM_REG_TEMP];
316d36cf32cSGuenter Roeck 	const char * const *temp_label;
317d36cf32cSGuenter Roeck 
318279af1a9SGuenter Roeck 	const u16 *REG_FAN_MAX_OUTPUT;
319279af1a9SGuenter Roeck 	const u16 *REG_FAN_STEP_OUTPUT;
320eff7687dSJean Delvare 	const u16 *scale_in;
321da2e0255SGuenter Roeck 
3229a61bf63SIngo Molnar 	struct mutex update_lock;
323952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
32408e7e278SJean Delvare 	unsigned long last_updated;	/* In jiffies */
32508e7e278SJean Delvare 
32608e7e278SJean Delvare 	/* Register values */
32783cc8985SGuenter Roeck 	u8 bank;		/* current register bank */
3281ea6dd38SDavid Hubbard 	u8 in_num;		/* number of in inputs we have */
329cf0676feSRudolf Marek 	u8 in[10];		/* Register value */
330cf0676feSRudolf Marek 	u8 in_max[10];		/* Register value */
331cf0676feSRudolf Marek 	u8 in_min[10];		/* Register value */
3323382a918SGuenter Roeck 	unsigned int rpm[5];
333ec3e5a16SGuenter Roeck 	u16 fan_min[5];
33408e7e278SJean Delvare 	u8 fan_div[5];
33508e7e278SJean Delvare 	u8 has_fan;		/* some fan inputs can be disabled */
336ec3e5a16SGuenter Roeck 	u8 has_fan_min;		/* some fans don't have min register */
337da667365SJean Delvare 	u8 temp_type[3];
338840e191dSGuenter Roeck 	s8 temp_offset[3];
339ec3e5a16SGuenter Roeck 	s16 temp[9];
340ec3e5a16SGuenter Roeck 	s16 temp_max[9];
341ec3e5a16SGuenter Roeck 	s16 temp_max_hyst[9];
342a4589dbbSJean Delvare 	u32 alarms;
343363a12a4SDmitry Artamonow 	u8 caseopen;
34408c79950SRudolf Marek 
34508c79950SRudolf Marek 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
34608c79950SRudolf Marek 	u8 pwm_enable[4]; /* 1->manual
3478969e84dSGuenter Roeck 			   * 2->thermal cruise mode (also called SmartFan I)
3488969e84dSGuenter Roeck 			   * 3->fan speed cruise mode
3498969e84dSGuenter Roeck 			   * 4->variable thermal cruise (also called
3508969e84dSGuenter Roeck 			   * SmartFan III)
3518969e84dSGuenter Roeck 			   * 5->enhanced variable thermal cruise (also called
3528969e84dSGuenter Roeck 			   * SmartFan IV)
3538969e84dSGuenter Roeck 			   */
354b84bb518SGuenter Roeck 	u8 pwm_enable_orig[4];	/* original value of pwm_enable */
355237c8d2fSGong Jun 	u8 pwm_num;		/* number of pwm */
35608c79950SRudolf Marek 	u8 pwm[4];
35708c79950SRudolf Marek 	u8 target_temp[4];
35808c79950SRudolf Marek 	u8 tolerance[4];
35908c79950SRudolf Marek 
36041e9a062SDaniel J Blueman 	u8 fan_start_output[4]; /* minimum fan speed when spinning up */
36141e9a062SDaniel J Blueman 	u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
36241e9a062SDaniel J Blueman 	u8 fan_stop_time[4]; /* time at minimum before disabling fan */
36341e9a062SDaniel J Blueman 	u8 fan_max_output[4]; /* maximum fan speed */
36441e9a062SDaniel J Blueman 	u8 fan_step_output[4]; /* rate of change output value */
365fc18d6c0SJean Delvare 
366fc18d6c0SJean Delvare 	u8 vid;
367fc18d6c0SJean Delvare 	u8 vrm;
368a157d06dSGong Jun 
369ec3e5a16SGuenter Roeck 	u16 have_temp;
370840e191dSGuenter Roeck 	u16 have_temp_offset;
371eff7687dSJean Delvare 	u8 in6_skip:1;
372eff7687dSJean Delvare 	u8 temp3_val_only:1;
373266cd583SDr. David Alan Gilbert 	u8 have_vid:1;
3747e630bb5SJean Delvare 
3757e630bb5SJean Delvare 	/* Remember extra register values over suspend/resume */
3767e630bb5SJean Delvare 	u8 vbat;
3777e630bb5SJean Delvare 	u8 fandiv1;
3787e630bb5SJean Delvare 	u8 fandiv2;
37908e7e278SJean Delvare };
38008e7e278SJean Delvare 
3811ea6dd38SDavid Hubbard struct w83627ehf_sio_data {
3821ea6dd38SDavid Hubbard 	int sioreg;
3831ea6dd38SDavid Hubbard 	enum kinds kind;
3841ea6dd38SDavid Hubbard };
3851ea6dd38SDavid Hubbard 
38683cc8985SGuenter Roeck /*
38783cc8985SGuenter Roeck  * On older chips, only registers 0x50-0x5f are banked.
38883cc8985SGuenter Roeck  * On more recent chips, all registers are banked.
38983cc8985SGuenter Roeck  * Assume that is the case and set the bank number for each access.
39083cc8985SGuenter Roeck  * Cache the bank number so it only needs to be set if it changes.
39183cc8985SGuenter Roeck  */
w83627ehf_set_bank(struct w83627ehf_data * data,u16 reg)3921ea6dd38SDavid Hubbard static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
39308e7e278SJean Delvare {
39483cc8985SGuenter Roeck 	u8 bank = reg >> 8;
39583cc8985SGuenter Roeck 	if (data->bank != bank) {
3961ea6dd38SDavid Hubbard 		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
39783cc8985SGuenter Roeck 		outb_p(bank, data->addr + DATA_REG_OFFSET);
39883cc8985SGuenter Roeck 		data->bank = bank;
39908e7e278SJean Delvare 	}
40008e7e278SJean Delvare }
40108e7e278SJean Delvare 
w83627ehf_read_value(struct w83627ehf_data * data,u16 reg)4021ea6dd38SDavid Hubbard static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
40308e7e278SJean Delvare {
40408e7e278SJean Delvare 	int res, word_sized = is_word_sized(reg);
40508e7e278SJean Delvare 
4069a61bf63SIngo Molnar 	mutex_lock(&data->lock);
40708e7e278SJean Delvare 
4081ea6dd38SDavid Hubbard 	w83627ehf_set_bank(data, reg);
4091ea6dd38SDavid Hubbard 	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
4101ea6dd38SDavid Hubbard 	res = inb_p(data->addr + DATA_REG_OFFSET);
41108e7e278SJean Delvare 	if (word_sized) {
41208e7e278SJean Delvare 		outb_p((reg & 0xff) + 1,
4131ea6dd38SDavid Hubbard 		       data->addr + ADDR_REG_OFFSET);
4141ea6dd38SDavid Hubbard 		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
41508e7e278SJean Delvare 	}
41608e7e278SJean Delvare 
4179a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
41808e7e278SJean Delvare 	return res;
41908e7e278SJean Delvare }
42008e7e278SJean Delvare 
w83627ehf_write_value(struct w83627ehf_data * data,u16 reg,u16 value)421e7e1ca6eSGuenter Roeck static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
422e7e1ca6eSGuenter Roeck 				 u16 value)
42308e7e278SJean Delvare {
42408e7e278SJean Delvare 	int word_sized = is_word_sized(reg);
42508e7e278SJean Delvare 
4269a61bf63SIngo Molnar 	mutex_lock(&data->lock);
42708e7e278SJean Delvare 
4281ea6dd38SDavid Hubbard 	w83627ehf_set_bank(data, reg);
4291ea6dd38SDavid Hubbard 	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
43008e7e278SJean Delvare 	if (word_sized) {
4311ea6dd38SDavid Hubbard 		outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
43208e7e278SJean Delvare 		outb_p((reg & 0xff) + 1,
4331ea6dd38SDavid Hubbard 		       data->addr + ADDR_REG_OFFSET);
43408e7e278SJean Delvare 	}
4351ea6dd38SDavid Hubbard 	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
43608e7e278SJean Delvare 
4379a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
43808e7e278SJean Delvare 	return 0;
43908e7e278SJean Delvare }
44008e7e278SJean Delvare 
441c5794cfaSJean Delvare /* We left-align 8-bit temperature values to make the code simpler */
w83627ehf_read_temp(struct w83627ehf_data * data,u16 reg)442c5794cfaSJean Delvare static u16 w83627ehf_read_temp(struct w83627ehf_data *data, u16 reg)
443c5794cfaSJean Delvare {
444c5794cfaSJean Delvare 	u16 res;
445c5794cfaSJean Delvare 
446c5794cfaSJean Delvare 	res = w83627ehf_read_value(data, reg);
447c5794cfaSJean Delvare 	if (!is_word_sized(reg))
448c5794cfaSJean Delvare 		res <<= 8;
449c5794cfaSJean Delvare 
450c5794cfaSJean Delvare 	return res;
451c5794cfaSJean Delvare }
452c5794cfaSJean Delvare 
w83627ehf_write_temp(struct w83627ehf_data * data,u16 reg,u16 value)453c5794cfaSJean Delvare static int w83627ehf_write_temp(struct w83627ehf_data *data, u16 reg,
454c5794cfaSJean Delvare 				       u16 value)
455c5794cfaSJean Delvare {
456c5794cfaSJean Delvare 	if (!is_word_sized(reg))
457c5794cfaSJean Delvare 		value >>= 8;
458c5794cfaSJean Delvare 	return w83627ehf_write_value(data, reg, value);
459c5794cfaSJean Delvare }
460c5794cfaSJean Delvare 
46108e7e278SJean Delvare /* This function assumes that the caller holds data->update_lock */
w83627ehf_write_fan_div(struct w83627ehf_data * data,int nr)4621ea6dd38SDavid Hubbard static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
46308e7e278SJean Delvare {
46408e7e278SJean Delvare 	u8 reg;
46508e7e278SJean Delvare 
46608e7e278SJean Delvare 	switch (nr) {
46708e7e278SJean Delvare 	case 0:
4681ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
46908e7e278SJean Delvare 		    | ((data->fan_div[0] & 0x03) << 4);
47014992c7eSRudolf Marek 		/* fan5 input control bit is write only, compute the value */
47114992c7eSRudolf Marek 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
4721ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
4731ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
47408e7e278SJean Delvare 		    | ((data->fan_div[0] & 0x04) << 3);
4751ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
47608e7e278SJean Delvare 		break;
47708e7e278SJean Delvare 	case 1:
4781ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
47908e7e278SJean Delvare 		    | ((data->fan_div[1] & 0x03) << 6);
48014992c7eSRudolf Marek 		/* fan5 input control bit is write only, compute the value */
48114992c7eSRudolf Marek 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
4821ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
4831ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
48408e7e278SJean Delvare 		    | ((data->fan_div[1] & 0x04) << 4);
4851ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
48608e7e278SJean Delvare 		break;
48708e7e278SJean Delvare 	case 2:
4881ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
48908e7e278SJean Delvare 		    | ((data->fan_div[2] & 0x03) << 6);
4901ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
4911ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
49208e7e278SJean Delvare 		    | ((data->fan_div[2] & 0x04) << 5);
4931ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
49408e7e278SJean Delvare 		break;
49508e7e278SJean Delvare 	case 3:
4961ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
49708e7e278SJean Delvare 		    | (data->fan_div[3] & 0x03);
4981ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
4991ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
50008e7e278SJean Delvare 		    | ((data->fan_div[3] & 0x04) << 5);
5011ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
50208e7e278SJean Delvare 		break;
50308e7e278SJean Delvare 	case 4:
5041ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
50533725ad3SJean Delvare 		    | ((data->fan_div[4] & 0x03) << 2)
50608e7e278SJean Delvare 		    | ((data->fan_div[4] & 0x04) << 5);
5071ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
50808e7e278SJean Delvare 		break;
50908e7e278SJean Delvare 	}
51008e7e278SJean Delvare }
51108e7e278SJean Delvare 
w83627ehf_update_fan_div(struct w83627ehf_data * data)512ea7be66cSMark M. Hoffman static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
51308e7e278SJean Delvare {
51408e7e278SJean Delvare 	int i;
51508e7e278SJean Delvare 
5161ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
51708e7e278SJean Delvare 	data->fan_div[0] = (i >> 4) & 0x03;
51808e7e278SJean Delvare 	data->fan_div[1] = (i >> 6) & 0x03;
5191ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
52008e7e278SJean Delvare 	data->fan_div[2] = (i >> 6) & 0x03;
5211ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
52208e7e278SJean Delvare 	data->fan_div[0] |= (i >> 3) & 0x04;
52308e7e278SJean Delvare 	data->fan_div[1] |= (i >> 4) & 0x04;
52408e7e278SJean Delvare 	data->fan_div[2] |= (i >> 5) & 0x04;
52508e7e278SJean Delvare 	if (data->has_fan & ((1 << 3) | (1 << 4))) {
5261ea6dd38SDavid Hubbard 		i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
52708e7e278SJean Delvare 		data->fan_div[3] = i & 0x03;
52808e7e278SJean Delvare 		data->fan_div[4] = ((i >> 2) & 0x03)
52908e7e278SJean Delvare 				 | ((i >> 5) & 0x04);
53008e7e278SJean Delvare 	}
53108e7e278SJean Delvare 	if (data->has_fan & (1 << 3)) {
5321ea6dd38SDavid Hubbard 		i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
53308e7e278SJean Delvare 		data->fan_div[3] |= (i >> 5) & 0x04;
53408e7e278SJean Delvare 	}
535ea7be66cSMark M. Hoffman }
536ea7be66cSMark M. Hoffman 
w83627ehf_update_pwm(struct w83627ehf_data * data)537ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm(struct w83627ehf_data *data)
538ec3e5a16SGuenter Roeck {
539ec3e5a16SGuenter Roeck 	int i;
540ec3e5a16SGuenter Roeck 	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
541ec3e5a16SGuenter Roeck 
542ec3e5a16SGuenter Roeck 	for (i = 0; i < data->pwm_num; i++) {
543ec3e5a16SGuenter Roeck 		if (!(data->has_fan & (1 << i)))
544ec3e5a16SGuenter Roeck 			continue;
545ec3e5a16SGuenter Roeck 
546ec3e5a16SGuenter Roeck 		/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
547ec3e5a16SGuenter Roeck 		if (i != 1) {
548ec3e5a16SGuenter Roeck 			pwmcfg = w83627ehf_read_value(data,
549ec3e5a16SGuenter Roeck 					W83627EHF_REG_PWM_ENABLE[i]);
550ec3e5a16SGuenter Roeck 			tolerance = w83627ehf_read_value(data,
551ec3e5a16SGuenter Roeck 					W83627EHF_REG_TOLERANCE[i]);
552ec3e5a16SGuenter Roeck 		}
553ec3e5a16SGuenter Roeck 		data->pwm_mode[i] =
554ec3e5a16SGuenter Roeck 			((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
555ec3e5a16SGuenter Roeck 		data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
556ec3e5a16SGuenter Roeck 				       & 3) + 1;
55769595502SDr. David Alan Gilbert 		data->pwm[i] = w83627ehf_read_value(data, W83627EHF_REG_PWM[i]);
558ec3e5a16SGuenter Roeck 
559ec3e5a16SGuenter Roeck 		data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
560ec3e5a16SGuenter Roeck 	}
561ec3e5a16SGuenter Roeck }
562ec3e5a16SGuenter Roeck 
w83627ehf_update_device(struct device * dev)563ea7be66cSMark M. Hoffman static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
564ea7be66cSMark M. Hoffman {
565ea7be66cSMark M. Hoffman 	struct w83627ehf_data *data = dev_get_drvdata(dev);
566ea7be66cSMark M. Hoffman 	int i;
567ea7be66cSMark M. Hoffman 
568ea7be66cSMark M. Hoffman 	mutex_lock(&data->update_lock);
569ea7be66cSMark M. Hoffman 
570ea7be66cSMark M. Hoffman 	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
571ea7be66cSMark M. Hoffman 	 || !data->valid) {
572ea7be66cSMark M. Hoffman 		/* Fan clock dividers */
57369595502SDr. David Alan Gilbert 		w83627ehf_update_fan_div(data);
57408e7e278SJean Delvare 
575cf0676feSRudolf Marek 		/* Measured voltages and limits */
5761ea6dd38SDavid Hubbard 		for (i = 0; i < data->in_num; i++) {
577389ef65dSJean Delvare 			if ((i == 6) && data->in6_skip)
578389ef65dSJean Delvare 				continue;
579389ef65dSJean Delvare 
5801ea6dd38SDavid Hubbard 			data->in[i] = w83627ehf_read_value(data,
581cf0676feSRudolf Marek 				      W83627EHF_REG_IN(i));
5821ea6dd38SDavid Hubbard 			data->in_min[i] = w83627ehf_read_value(data,
583cf0676feSRudolf Marek 					  W83627EHF_REG_IN_MIN(i));
5841ea6dd38SDavid Hubbard 			data->in_max[i] = w83627ehf_read_value(data,
585cf0676feSRudolf Marek 					  W83627EHF_REG_IN_MAX(i));
586cf0676feSRudolf Marek 		}
587cf0676feSRudolf Marek 
58808e7e278SJean Delvare 		/* Measured fan speeds and limits */
58908e7e278SJean Delvare 		for (i = 0; i < 5; i++) {
5903382a918SGuenter Roeck 			u16 reg;
5913382a918SGuenter Roeck 
59208e7e278SJean Delvare 			if (!(data->has_fan & (1 << i)))
59308e7e278SJean Delvare 				continue;
59408e7e278SJean Delvare 
59569595502SDr. David Alan Gilbert 			reg = w83627ehf_read_value(data, W83627EHF_REG_FAN[i]);
59669595502SDr. David Alan Gilbert 			data->rpm[i] = fan_from_reg8(reg, data->fan_div[i]);
597ec3e5a16SGuenter Roeck 
598ec3e5a16SGuenter Roeck 			if (data->has_fan_min & (1 << i))
5991ea6dd38SDavid Hubbard 				data->fan_min[i] = w83627ehf_read_value(data,
60069595502SDr. David Alan Gilbert 					   W83627EHF_REG_FAN_MIN[i]);
60108e7e278SJean Delvare 
6028969e84dSGuenter Roeck 			/*
6038969e84dSGuenter Roeck 			 * If we failed to measure the fan speed and clock
6048969e84dSGuenter Roeck 			 * divider can be increased, let's try that for next
6058969e84dSGuenter Roeck 			 * time
6068969e84dSGuenter Roeck 			 */
60769595502SDr. David Alan Gilbert 			if (reg >= 0xff && data->fan_div[i] < 0x07) {
608b55f3757SGuenter Roeck 				dev_dbg(dev,
609b55f3757SGuenter Roeck 					"Increasing fan%d clock divider from %u to %u\n",
61033725ad3SJean Delvare 					i + 1, div_from_reg(data->fan_div[i]),
61108e7e278SJean Delvare 					div_from_reg(data->fan_div[i] + 1));
61208e7e278SJean Delvare 				data->fan_div[i]++;
61369595502SDr. David Alan Gilbert 				w83627ehf_write_fan_div(data, i);
61408e7e278SJean Delvare 				/* Preserve min limit if possible */
615ec3e5a16SGuenter Roeck 				if ((data->has_fan_min & (1 << i))
616ec3e5a16SGuenter Roeck 				 && data->fan_min[i] >= 2
61708e7e278SJean Delvare 				 && data->fan_min[i] != 255)
6181ea6dd38SDavid Hubbard 					w83627ehf_write_value(data,
61969595502SDr. David Alan Gilbert 						W83627EHF_REG_FAN_MIN[i],
62008e7e278SJean Delvare 						(data->fan_min[i] /= 2));
62108e7e278SJean Delvare 			}
62208e7e278SJean Delvare 		}
62308e7e278SJean Delvare 
62469595502SDr. David Alan Gilbert 		w83627ehf_update_pwm(data);
625ec3e5a16SGuenter Roeck 
626da2e0255SGuenter Roeck 		for (i = 0; i < data->pwm_num; i++) {
627da2e0255SGuenter Roeck 			if (!(data->has_fan & (1 << i)))
628da2e0255SGuenter Roeck 				continue;
629da2e0255SGuenter Roeck 
630ec3e5a16SGuenter Roeck 			data->fan_start_output[i] =
631ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
63269595502SDr. David Alan Gilbert 					     W83627EHF_REG_FAN_START_OUTPUT[i]);
633ec3e5a16SGuenter Roeck 			data->fan_stop_output[i] =
634ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
63569595502SDr. David Alan Gilbert 					     W83627EHF_REG_FAN_STOP_OUTPUT[i]);
636ec3e5a16SGuenter Roeck 			data->fan_stop_time[i] =
637ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
63869595502SDr. David Alan Gilbert 					       W83627EHF_REG_FAN_STOP_TIME[i]);
639da2e0255SGuenter Roeck 
640ec3e5a16SGuenter Roeck 			if (data->REG_FAN_MAX_OUTPUT &&
641ec3e5a16SGuenter Roeck 			    data->REG_FAN_MAX_OUTPUT[i] != 0xff)
642da2e0255SGuenter Roeck 				data->fan_max_output[i] =
643da2e0255SGuenter Roeck 				  w83627ehf_read_value(data,
644da2e0255SGuenter Roeck 						data->REG_FAN_MAX_OUTPUT[i]);
645da2e0255SGuenter Roeck 
646ec3e5a16SGuenter Roeck 			if (data->REG_FAN_STEP_OUTPUT &&
647ec3e5a16SGuenter Roeck 			    data->REG_FAN_STEP_OUTPUT[i] != 0xff)
648da2e0255SGuenter Roeck 				data->fan_step_output[i] =
649da2e0255SGuenter Roeck 				  w83627ehf_read_value(data,
650da2e0255SGuenter Roeck 						data->REG_FAN_STEP_OUTPUT[i]);
651da2e0255SGuenter Roeck 
65208c79950SRudolf Marek 			data->target_temp[i] =
6531ea6dd38SDavid Hubbard 				w83627ehf_read_value(data,
65469595502SDr. David Alan Gilbert 					W83627EHF_REG_TARGET[i]) &
65508c79950SRudolf Marek 					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
65608c79950SRudolf Marek 		}
65708c79950SRudolf Marek 
65808e7e278SJean Delvare 		/* Measured temperatures and limits */
659d36cf32cSGuenter Roeck 		for (i = 0; i < NUM_REG_TEMP; i++) {
660d36cf32cSGuenter Roeck 			if (!(data->have_temp & (1 << i)))
661d36cf32cSGuenter Roeck 				continue;
662c5794cfaSJean Delvare 			data->temp[i] = w83627ehf_read_temp(data,
663ec3e5a16SGuenter Roeck 						data->reg_temp[i]);
664ec3e5a16SGuenter Roeck 			if (data->reg_temp_over[i])
665d36cf32cSGuenter Roeck 				data->temp_max[i]
666c5794cfaSJean Delvare 				  = w83627ehf_read_temp(data,
667ec3e5a16SGuenter Roeck 						data->reg_temp_over[i]);
668ec3e5a16SGuenter Roeck 			if (data->reg_temp_hyst[i])
669d36cf32cSGuenter Roeck 				data->temp_max_hyst[i]
670c5794cfaSJean Delvare 				  = w83627ehf_read_temp(data,
671ec3e5a16SGuenter Roeck 						data->reg_temp_hyst[i]);
67245633fb3SJean Delvare 			if (i > 2)
67345633fb3SJean Delvare 				continue;
674840e191dSGuenter Roeck 			if (data->have_temp_offset & (1 << i))
675840e191dSGuenter Roeck 				data->temp_offset[i]
676840e191dSGuenter Roeck 				  = w83627ehf_read_value(data,
677840e191dSGuenter Roeck 						W83627EHF_REG_TEMP_OFFSET[i]);
67808e7e278SJean Delvare 		}
67908e7e278SJean Delvare 
6801ea6dd38SDavid Hubbard 		data->alarms = w83627ehf_read_value(data,
681a4589dbbSJean Delvare 					W83627EHF_REG_ALARM1) |
6821ea6dd38SDavid Hubbard 			       (w83627ehf_read_value(data,
683a4589dbbSJean Delvare 					W83627EHF_REG_ALARM2) << 8) |
6841ea6dd38SDavid Hubbard 			       (w83627ehf_read_value(data,
685a4589dbbSJean Delvare 					W83627EHF_REG_ALARM3) << 16);
686a4589dbbSJean Delvare 
687363a12a4SDmitry Artamonow 		data->caseopen = w83627ehf_read_value(data,
688363a12a4SDmitry Artamonow 						W83627EHF_REG_CASEOPEN_DET);
689363a12a4SDmitry Artamonow 
69008e7e278SJean Delvare 		data->last_updated = jiffies;
691952a11caSPaul Fertser 		data->valid = true;
69208e7e278SJean Delvare 	}
69308e7e278SJean Delvare 
6949a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
69508e7e278SJean Delvare 	return data;
69608e7e278SJean Delvare }
69708e7e278SJean Delvare 
698cf0676feSRudolf Marek #define store_in_reg(REG, reg) \
699266cd583SDr. David Alan Gilbert static int \
700266cd583SDr. David Alan Gilbert store_in_##reg(struct device *dev, struct w83627ehf_data *data, int channel, \
701266cd583SDr. David Alan Gilbert 	       long val) \
702cf0676feSRudolf Marek { \
703266cd583SDr. David Alan Gilbert 	if (val < 0) \
704266cd583SDr. David Alan Gilbert 		return -EINVAL; \
705cf0676feSRudolf Marek 	mutex_lock(&data->update_lock); \
706266cd583SDr. David Alan Gilbert 	data->in_##reg[channel] = in_to_reg(val, channel, data->scale_in); \
707266cd583SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(channel), \
708266cd583SDr. David Alan Gilbert 			      data->in_##reg[channel]); \
709cf0676feSRudolf Marek 	mutex_unlock(&data->update_lock); \
710266cd583SDr. David Alan Gilbert 	return 0; \
711cf0676feSRudolf Marek }
712cf0676feSRudolf Marek 
store_in_reg(MIN,min)713cf0676feSRudolf Marek store_in_reg(MIN, min)
714cf0676feSRudolf Marek store_in_reg(MAX, max)
715cf0676feSRudolf Marek 
716266cd583SDr. David Alan Gilbert static int
717266cd583SDr. David Alan Gilbert store_fan_min(struct device *dev, struct w83627ehf_data *data, int channel,
718266cd583SDr. David Alan Gilbert 	      long val)
719a4589dbbSJean Delvare {
72008e7e278SJean Delvare 	unsigned int reg;
72108e7e278SJean Delvare 	u8 new_div;
72208e7e278SJean Delvare 
723266cd583SDr. David Alan Gilbert 	if (val < 0)
724266cd583SDr. David Alan Gilbert 		return -EINVAL;
725bce26c58SGuenter Roeck 
7269a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
72708e7e278SJean Delvare 	if (!val) {
72808e7e278SJean Delvare 		/* No min limit, alarm disabled */
729266cd583SDr. David Alan Gilbert 		data->fan_min[channel] = 255;
730266cd583SDr. David Alan Gilbert 		new_div = data->fan_div[channel]; /* No change */
731266cd583SDr. David Alan Gilbert 		dev_info(dev, "fan%u low limit and alarm disabled\n",
732266cd583SDr. David Alan Gilbert 			 channel + 1);
73308e7e278SJean Delvare 	} else if ((reg = 1350000U / val) >= 128 * 255) {
7348969e84dSGuenter Roeck 		/*
7358969e84dSGuenter Roeck 		 * Speed below this value cannot possibly be represented,
7368969e84dSGuenter Roeck 		 * even with the highest divider (128)
7378969e84dSGuenter Roeck 		 */
738266cd583SDr. David Alan Gilbert 		data->fan_min[channel] = 254;
73908e7e278SJean Delvare 		new_div = 7; /* 128 == (1 << 7) */
740b55f3757SGuenter Roeck 		dev_warn(dev,
741b55f3757SGuenter Roeck 			 "fan%u low limit %lu below minimum %u, set to minimum\n",
74269595502SDr. David Alan Gilbert 			 channel + 1, val, fan_from_reg8(254, 7));
74308e7e278SJean Delvare 	} else if (!reg) {
7448969e84dSGuenter Roeck 		/*
7458969e84dSGuenter Roeck 		 * Speed above this value cannot possibly be represented,
7468969e84dSGuenter Roeck 		 * even with the lowest divider (1)
7478969e84dSGuenter Roeck 		 */
748266cd583SDr. David Alan Gilbert 		data->fan_min[channel] = 1;
74908e7e278SJean Delvare 		new_div = 0; /* 1 == (1 << 0) */
750b55f3757SGuenter Roeck 		dev_warn(dev,
751b55f3757SGuenter Roeck 			 "fan%u low limit %lu above maximum %u, set to maximum\n",
75269595502SDr. David Alan Gilbert 			 channel + 1, val, fan_from_reg8(1, 0));
75308e7e278SJean Delvare 	} else {
7548969e84dSGuenter Roeck 		/*
7558969e84dSGuenter Roeck 		 * Automatically pick the best divider, i.e. the one such
7568969e84dSGuenter Roeck 		 * that the min limit will correspond to a register value
7578969e84dSGuenter Roeck 		 * in the 96..192 range
7588969e84dSGuenter Roeck 		 */
75908e7e278SJean Delvare 		new_div = 0;
76008e7e278SJean Delvare 		while (reg > 192 && new_div < 7) {
76108e7e278SJean Delvare 			reg >>= 1;
76208e7e278SJean Delvare 			new_div++;
76308e7e278SJean Delvare 		}
764266cd583SDr. David Alan Gilbert 		data->fan_min[channel] = reg;
76508e7e278SJean Delvare 	}
76608e7e278SJean Delvare 
7678969e84dSGuenter Roeck 	/*
7688969e84dSGuenter Roeck 	 * Write both the fan clock divider (if it changed) and the new
7698969e84dSGuenter Roeck 	 * fan min (unconditionally)
7708969e84dSGuenter Roeck 	 */
771266cd583SDr. David Alan Gilbert 	if (new_div != data->fan_div[channel]) {
77208e7e278SJean Delvare 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
773266cd583SDr. David Alan Gilbert 			channel + 1, div_from_reg(data->fan_div[channel]),
77408e7e278SJean Delvare 			div_from_reg(new_div));
775266cd583SDr. David Alan Gilbert 		data->fan_div[channel] = new_div;
77669595502SDr. David Alan Gilbert 		w83627ehf_write_fan_div(data, channel);
7776b3e4645SJean Delvare 		/* Give the chip time to sample a new speed value */
7786b3e4645SJean Delvare 		data->last_updated = jiffies;
77908e7e278SJean Delvare 	}
78069595502SDr. David Alan Gilbert 
78169595502SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[channel],
782266cd583SDr. David Alan Gilbert 			      data->fan_min[channel]);
7839a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
78408e7e278SJean Delvare 
785266cd583SDr. David Alan Gilbert 	return 0;
78608e7e278SJean Delvare }
78708e7e278SJean Delvare 
788ec3e5a16SGuenter Roeck #define store_temp_reg(addr, reg) \
789266cd583SDr. David Alan Gilbert static int \
790266cd583SDr. David Alan Gilbert store_##reg(struct device *dev, struct w83627ehf_data *data, int channel, \
791266cd583SDr. David Alan Gilbert 	    long val) \
79208e7e278SJean Delvare { \
7939a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
794266cd583SDr. David Alan Gilbert 	data->reg[channel] = LM75_TEMP_TO_REG(val); \
795266cd583SDr. David Alan Gilbert 	w83627ehf_write_temp(data, data->addr[channel], data->reg[channel]); \
7969a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
797266cd583SDr. David Alan Gilbert 	return 0; \
79808e7e278SJean Delvare }
799ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_over, temp_max);
800ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_hyst, temp_max_hyst);
80108e7e278SJean Delvare 
802266cd583SDr. David Alan Gilbert static int
store_temp_offset(struct device * dev,struct w83627ehf_data * data,int channel,long val)803266cd583SDr. David Alan Gilbert store_temp_offset(struct device *dev, struct w83627ehf_data *data, int channel,
804266cd583SDr. David Alan Gilbert 		  long val)
805840e191dSGuenter Roeck {
8062a844c14SGuenter Roeck 	val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
807840e191dSGuenter Roeck 
808840e191dSGuenter Roeck 	mutex_lock(&data->update_lock);
809266cd583SDr. David Alan Gilbert 	data->temp_offset[channel] = val;
810266cd583SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_TEMP_OFFSET[channel], val);
811840e191dSGuenter Roeck 	mutex_unlock(&data->update_lock);
812266cd583SDr. David Alan Gilbert 	return 0;
813840e191dSGuenter Roeck }
814840e191dSGuenter Roeck 
815266cd583SDr. David Alan Gilbert static int
store_pwm_mode(struct device * dev,struct w83627ehf_data * data,int channel,long val)816266cd583SDr. David Alan Gilbert store_pwm_mode(struct device *dev, struct w83627ehf_data *data, int channel,
817266cd583SDr. David Alan Gilbert 	       long val)
818da667365SJean Delvare {
81908c79950SRudolf Marek 	u16 reg;
82008c79950SRudolf Marek 
821266cd583SDr. David Alan Gilbert 	if (val < 0 || val > 1)
82208c79950SRudolf Marek 		return -EINVAL;
823ad77c3e1SGuenter Roeck 
82408c79950SRudolf Marek 	mutex_lock(&data->update_lock);
825266cd583SDr. David Alan Gilbert 	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[channel]);
826266cd583SDr. David Alan Gilbert 	data->pwm_mode[channel] = val;
827266cd583SDr. David Alan Gilbert 	reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[channel]);
82808c79950SRudolf Marek 	if (!val)
829266cd583SDr. David Alan Gilbert 		reg |= 1 << W83627EHF_PWM_MODE_SHIFT[channel];
830266cd583SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[channel], reg);
83108c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
832266cd583SDr. David Alan Gilbert 	return 0;
83308c79950SRudolf Marek }
83408c79950SRudolf Marek 
835266cd583SDr. David Alan Gilbert static int
store_pwm(struct device * dev,struct w83627ehf_data * data,int channel,long val)836266cd583SDr. David Alan Gilbert store_pwm(struct device *dev, struct w83627ehf_data *data, int channel,
837266cd583SDr. David Alan Gilbert 	  long val)
83808c79950SRudolf Marek {
8392a844c14SGuenter Roeck 	val = clamp_val(val, 0, 255);
84008c79950SRudolf Marek 
84108c79950SRudolf Marek 	mutex_lock(&data->update_lock);
842266cd583SDr. David Alan Gilbert 	data->pwm[channel] = val;
84369595502SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_PWM[channel], val);
84408c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
845266cd583SDr. David Alan Gilbert 	return 0;
84608c79950SRudolf Marek }
84708c79950SRudolf Marek 
848266cd583SDr. David Alan Gilbert static int
store_pwm_enable(struct device * dev,struct w83627ehf_data * data,int channel,long val)849266cd583SDr. David Alan Gilbert store_pwm_enable(struct device *dev, struct w83627ehf_data *data, int channel,
850266cd583SDr. David Alan Gilbert 		 long val)
85108c79950SRudolf Marek {
85208c79950SRudolf Marek 	u16 reg;
85308c79950SRudolf Marek 
854266cd583SDr. David Alan Gilbert 	if (!val || val < 0 ||
855266cd583SDr. David Alan Gilbert 	    (val > 4 && val != data->pwm_enable_orig[channel]))
85608c79950SRudolf Marek 		return -EINVAL;
857ec3e5a16SGuenter Roeck 
85808c79950SRudolf Marek 	mutex_lock(&data->update_lock);
859266cd583SDr. David Alan Gilbert 	data->pwm_enable[channel] = val;
860266cd583SDr. David Alan Gilbert 	reg = w83627ehf_read_value(data,
861266cd583SDr. David Alan Gilbert 				   W83627EHF_REG_PWM_ENABLE[channel]);
862266cd583SDr. David Alan Gilbert 	reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[channel]);
863266cd583SDr. David Alan Gilbert 	reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[channel];
864266cd583SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[channel],
865266cd583SDr. David Alan Gilbert 			      reg);
86608c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
867266cd583SDr. David Alan Gilbert 	return 0;
86808c79950SRudolf Marek }
86908c79950SRudolf Marek 
87008c79950SRudolf Marek #define show_tol_temp(reg) \
87108c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
87208c79950SRudolf Marek 				char *buf) \
87308c79950SRudolf Marek { \
874266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
875e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
876e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
87708c79950SRudolf Marek 	int nr = sensor_attr->index; \
878bce26c58SGuenter Roeck 	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
87908c79950SRudolf Marek }
88008c79950SRudolf Marek 
88108c79950SRudolf Marek show_tol_temp(tolerance)
show_tol_temp(target_temp)88208c79950SRudolf Marek show_tol_temp(target_temp)
88308c79950SRudolf Marek 
88408c79950SRudolf Marek static ssize_t
88508c79950SRudolf Marek store_target_temp(struct device *dev, struct device_attribute *attr,
88608c79950SRudolf Marek 			const char *buf, size_t count)
88708c79950SRudolf Marek {
8881ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
88908c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
89008c79950SRudolf Marek 	int nr = sensor_attr->index;
891bce26c58SGuenter Roeck 	long val;
892bce26c58SGuenter Roeck 	int err;
893bce26c58SGuenter Roeck 
894179c4fdbSFrans Meulenbroeks 	err = kstrtol(buf, 10, &val);
895bce26c58SGuenter Roeck 	if (err < 0)
896bce26c58SGuenter Roeck 		return err;
897bce26c58SGuenter Roeck 
8982a844c14SGuenter Roeck 	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 127000), 1000);
89908c79950SRudolf Marek 
90008c79950SRudolf Marek 	mutex_lock(&data->update_lock);
90108c79950SRudolf Marek 	data->target_temp[nr] = val;
90269595502SDr. David Alan Gilbert 	w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
90308c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
90408c79950SRudolf Marek 	return count;
90508c79950SRudolf Marek }
90608c79950SRudolf Marek 
90708c79950SRudolf Marek static ssize_t
store_tolerance(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)90808c79950SRudolf Marek store_tolerance(struct device *dev, struct device_attribute *attr,
90908c79950SRudolf Marek 			const char *buf, size_t count)
91008c79950SRudolf Marek {
9111ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
91208c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
91308c79950SRudolf Marek 	int nr = sensor_attr->index;
91408c79950SRudolf Marek 	u16 reg;
915bce26c58SGuenter Roeck 	long val;
916bce26c58SGuenter Roeck 	int err;
917bce26c58SGuenter Roeck 
918179c4fdbSFrans Meulenbroeks 	err = kstrtol(buf, 10, &val);
919bce26c58SGuenter Roeck 	if (err < 0)
920bce26c58SGuenter Roeck 		return err;
921bce26c58SGuenter Roeck 
92208c79950SRudolf Marek 	/* Limit the temp to 0C - 15C */
9232a844c14SGuenter Roeck 	val = DIV_ROUND_CLOSEST(clamp_val(val, 0, 15000), 1000);
92408c79950SRudolf Marek 
92508c79950SRudolf Marek 	mutex_lock(&data->update_lock);
9261ea6dd38SDavid Hubbard 	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
92708c79950SRudolf Marek 	if (nr == 1)
92808c79950SRudolf Marek 		reg = (reg & 0x0f) | (val << 4);
92908c79950SRudolf Marek 	else
93008c79950SRudolf Marek 		reg = (reg & 0xf0) | val;
9311ea6dd38SDavid Hubbard 	w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
932ec3e5a16SGuenter Roeck 	data->tolerance[nr] = val;
93308c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
93408c79950SRudolf Marek 	return count;
93508c79950SRudolf Marek }
93608c79950SRudolf Marek 
9378f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_target, 0644, show_target_temp,
938266cd583SDr. David Alan Gilbert 	    store_target_temp, 0);
9398f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_target, 0644, show_target_temp,
940266cd583SDr. David Alan Gilbert 	    store_target_temp, 1);
9418f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_target, 0644, show_target_temp,
942266cd583SDr. David Alan Gilbert 	    store_target_temp, 2);
9438f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_target, 0644, show_target_temp,
944266cd583SDr. David Alan Gilbert 	    store_target_temp, 3);
94508c79950SRudolf Marek 
9468f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_tolerance, 0644, show_tolerance,
947266cd583SDr. David Alan Gilbert 	    store_tolerance, 0);
9488f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_tolerance, 0644, show_tolerance,
949266cd583SDr. David Alan Gilbert 	    store_tolerance, 1);
9508f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_tolerance, 0644, show_tolerance,
951266cd583SDr. David Alan Gilbert 	    store_tolerance, 2);
9528f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_tolerance, 0644, show_tolerance,
953266cd583SDr. David Alan Gilbert 	    store_tolerance, 3);
95408c79950SRudolf Marek 
95508c79950SRudolf Marek /* Smart Fan registers */
95608c79950SRudolf Marek 
95708c79950SRudolf Marek #define fan_functions(reg, REG) \
95808c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
95908c79950SRudolf Marek 		       char *buf) \
96008c79950SRudolf Marek { \
961266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
962e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
963e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
96408c79950SRudolf Marek 	int nr = sensor_attr->index; \
96508c79950SRudolf Marek 	return sprintf(buf, "%d\n", data->reg[nr]); \
96608c79950SRudolf Marek } \
96708c79950SRudolf Marek static ssize_t \
96808c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
96908c79950SRudolf Marek 			    const char *buf, size_t count) \
97008c79950SRudolf Marek { \
9711ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
972e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
973e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
97408c79950SRudolf Marek 	int nr = sensor_attr->index; \
975bce26c58SGuenter Roeck 	unsigned long val; \
976bce26c58SGuenter Roeck 	int err; \
977179c4fdbSFrans Meulenbroeks 	err = kstrtoul(buf, 10, &val); \
978bce26c58SGuenter Roeck 	if (err < 0) \
979bce26c58SGuenter Roeck 		return err; \
9802a844c14SGuenter Roeck 	val = clamp_val(val, 1, 255); \
98108c79950SRudolf Marek 	mutex_lock(&data->update_lock); \
98208c79950SRudolf Marek 	data->reg[nr] = val; \
98369595502SDr. David Alan Gilbert 	w83627ehf_write_value(data, REG[nr], val); \
98408c79950SRudolf Marek 	mutex_unlock(&data->update_lock); \
98508c79950SRudolf Marek 	return count; \
98608c79950SRudolf Marek }
98708c79950SRudolf Marek 
98869595502SDr. David Alan Gilbert fan_functions(fan_start_output, W83627EHF_REG_FAN_START_OUTPUT)
98969595502SDr. David Alan Gilbert fan_functions(fan_stop_output, W83627EHF_REG_FAN_STOP_OUTPUT)
99069595502SDr. David Alan Gilbert fan_functions(fan_max_output, data->REG_FAN_MAX_OUTPUT)
99169595502SDr. David Alan Gilbert fan_functions(fan_step_output, data->REG_FAN_STEP_OUTPUT)
99208c79950SRudolf Marek 
99308c79950SRudolf Marek #define fan_time_functions(reg, REG) \
99408c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
99508c79950SRudolf Marek 				char *buf) \
99608c79950SRudolf Marek { \
997266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = w83627ehf_update_device(dev->parent); \
998e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
999e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
100008c79950SRudolf Marek 	int nr = sensor_attr->index; \
100108c79950SRudolf Marek 	return sprintf(buf, "%d\n", \
1002e7e1ca6eSGuenter Roeck 			step_time_from_reg(data->reg[nr], \
1003e7e1ca6eSGuenter Roeck 					   data->pwm_mode[nr])); \
100408c79950SRudolf Marek } \
100508c79950SRudolf Marek \
100608c79950SRudolf Marek static ssize_t \
100708c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
100808c79950SRudolf Marek 			const char *buf, size_t count) \
100908c79950SRudolf Marek { \
10101ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
1011e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1012e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
101308c79950SRudolf Marek 	int nr = sensor_attr->index; \
1014bce26c58SGuenter Roeck 	unsigned long val; \
1015bce26c58SGuenter Roeck 	int err; \
1016179c4fdbSFrans Meulenbroeks 	err = kstrtoul(buf, 10, &val); \
1017bce26c58SGuenter Roeck 	if (err < 0) \
1018bce26c58SGuenter Roeck 		return err; \
1019bce26c58SGuenter Roeck 	val = step_time_to_reg(val, data->pwm_mode[nr]); \
102008c79950SRudolf Marek 	mutex_lock(&data->update_lock); \
102108c79950SRudolf Marek 	data->reg[nr] = val; \
102269595502SDr. David Alan Gilbert 	w83627ehf_write_value(data, REG[nr], val); \
102308c79950SRudolf Marek 	mutex_unlock(&data->update_lock); \
102408c79950SRudolf Marek 	return count; \
102508c79950SRudolf Marek } \
102608c79950SRudolf Marek 
102769595502SDr. David Alan Gilbert fan_time_functions(fan_stop_time, W83627EHF_REG_FAN_STOP_TIME)
102808c79950SRudolf Marek 
10298f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_stop_time, 0644, show_fan_stop_time,
1030266cd583SDr. David Alan Gilbert 	    store_fan_stop_time, 3);
10318f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_start_output, 0644, show_fan_start_output,
1032266cd583SDr. David Alan Gilbert 	    store_fan_start_output, 3);
10338f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_stop_output, 0644, show_fan_stop_output,
1034266cd583SDr. David Alan Gilbert 	    store_fan_stop_output, 3);
10358f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_max_output, 0644, show_fan_max_output,
1036266cd583SDr. David Alan Gilbert 	    store_fan_max_output, 3);
10378f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm4_step_output, 0644, show_fan_step_output,
1038266cd583SDr. David Alan Gilbert 	    store_fan_step_output, 3);
10391ea6dd38SDavid Hubbard 
10408f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_stop_time, 0644, show_fan_stop_time,
1041266cd583SDr. David Alan Gilbert 	    store_fan_stop_time, 2);
10428f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_start_output, 0644, show_fan_start_output,
1043266cd583SDr. David Alan Gilbert 	    store_fan_start_output, 2);
10448f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_stop_output, 0644, show_fan_stop_output,
1045266cd583SDr. David Alan Gilbert 		    store_fan_stop_output, 2);
104608c79950SRudolf Marek 
10478f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_stop_time, 0644, show_fan_stop_time,
1048266cd583SDr. David Alan Gilbert 	    store_fan_stop_time, 0);
10498f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_stop_time, 0644, show_fan_stop_time,
1050266cd583SDr. David Alan Gilbert 	    store_fan_stop_time, 1);
10518f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_start_output, 0644, show_fan_start_output,
1052266cd583SDr. David Alan Gilbert 	    store_fan_start_output, 0);
10538f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_start_output, 0644, show_fan_start_output,
1054266cd583SDr. David Alan Gilbert 	    store_fan_start_output, 1);
10558f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_stop_output, 0644, show_fan_stop_output,
1056266cd583SDr. David Alan Gilbert 	    store_fan_stop_output, 0);
10578f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_stop_output, 0644, show_fan_stop_output,
1058266cd583SDr. David Alan Gilbert 	    store_fan_stop_output, 1);
105941e9a062SDaniel J Blueman 
1060da2e0255SGuenter Roeck 
1061da2e0255SGuenter Roeck /*
1062da2e0255SGuenter Roeck  * pwm1 and pwm3 don't support max and step settings on all chips.
1063da2e0255SGuenter Roeck  * Need to check support while generating/removing attribute files.
1064da2e0255SGuenter Roeck  */
10658f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_max_output, 0644, show_fan_max_output,
1066266cd583SDr. David Alan Gilbert 	    store_fan_max_output, 0);
10678f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm1_step_output, 0644, show_fan_step_output,
1068266cd583SDr. David Alan Gilbert 	    store_fan_step_output, 0);
10698f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_max_output, 0644, show_fan_max_output,
1070266cd583SDr. David Alan Gilbert 	    store_fan_max_output, 1);
10718f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm2_step_output, 0644, show_fan_step_output,
1072266cd583SDr. David Alan Gilbert 	    store_fan_step_output, 1);
10738f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_max_output, 0644, show_fan_max_output,
1074266cd583SDr. David Alan Gilbert 	    store_fan_max_output, 2);
10758f772035SChen Zhou static SENSOR_DEVICE_ATTR(pwm3_step_output, 0644, show_fan_step_output,
1076266cd583SDr. David Alan Gilbert 	    store_fan_step_output, 2);
107708c79950SRudolf Marek 
1078fc18d6c0SJean Delvare static ssize_t
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)10799bbacbfeSJulia Lawall cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf)
1080fc18d6c0SJean Delvare {
1081fc18d6c0SJean Delvare 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1082fc18d6c0SJean Delvare 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1083fc18d6c0SJean Delvare }
10846f447ce0SArmin Wolf static DEVICE_ATTR_RO(cpu0_vid);
1085fc18d6c0SJean Delvare 
1086363a12a4SDmitry Artamonow 
1087363a12a4SDmitry Artamonow /* Case open detection */
1088266cd583SDr. David Alan Gilbert static int
clear_caseopen(struct device * dev,struct w83627ehf_data * data,int channel,long val)1089266cd583SDr. David Alan Gilbert clear_caseopen(struct device *dev, struct w83627ehf_data *data, int channel,
1090266cd583SDr. David Alan Gilbert 	       long val)
1091363a12a4SDmitry Artamonow {
1092931f397bSDr. David Alan Gilbert 	const u16 mask = 0x80;
1093931f397bSDr. David Alan Gilbert 	u16 reg;
1094363a12a4SDmitry Artamonow 
1095931f397bSDr. David Alan Gilbert 	if (val != 0 || channel != 0)
1096363a12a4SDmitry Artamonow 		return -EINVAL;
1097363a12a4SDmitry Artamonow 
1098363a12a4SDmitry Artamonow 	mutex_lock(&data->update_lock);
1099363a12a4SDmitry Artamonow 	reg = w83627ehf_read_value(data, W83627EHF_REG_CASEOPEN_CLR);
1100363a12a4SDmitry Artamonow 	w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg | mask);
1101363a12a4SDmitry Artamonow 	w83627ehf_write_value(data, W83627EHF_REG_CASEOPEN_CLR, reg & ~mask);
1102952a11caSPaul Fertser 	data->valid = false;	/* Force cache refresh */
1103363a12a4SDmitry Artamonow 	mutex_unlock(&data->update_lock);
1104363a12a4SDmitry Artamonow 
1105266cd583SDr. David Alan Gilbert 	return 0;
1106363a12a4SDmitry Artamonow }
1107363a12a4SDmitry Artamonow 
w83627ehf_attrs_visible(struct kobject * kobj,struct attribute * a,int n)1108266cd583SDr. David Alan Gilbert static umode_t w83627ehf_attrs_visible(struct kobject *kobj,
1109266cd583SDr. David Alan Gilbert 				       struct attribute *a, int n)
1110266cd583SDr. David Alan Gilbert {
11115707c8dbSTian Tao 	struct device *dev = kobj_to_dev(kobj);
1112266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1113266cd583SDr. David Alan Gilbert 	struct device_attribute *devattr;
1114266cd583SDr. David Alan Gilbert 	struct sensor_device_attribute *sda;
1115266cd583SDr. David Alan Gilbert 
1116266cd583SDr. David Alan Gilbert 	devattr = container_of(a, struct device_attribute, attr);
1117266cd583SDr. David Alan Gilbert 
1118266cd583SDr. David Alan Gilbert 	/* Not sensor */
1119266cd583SDr. David Alan Gilbert 	if (devattr->show == cpu0_vid_show && data->have_vid)
1120266cd583SDr. David Alan Gilbert 		return a->mode;
1121266cd583SDr. David Alan Gilbert 
1122266cd583SDr. David Alan Gilbert 	sda = (struct sensor_device_attribute *)devattr;
1123266cd583SDr. David Alan Gilbert 
1124266cd583SDr. David Alan Gilbert 	if (sda->index < 2 &&
1125266cd583SDr. David Alan Gilbert 		(devattr->show == show_fan_stop_time ||
1126266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_start_output ||
1127266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_stop_output))
1128266cd583SDr. David Alan Gilbert 		return a->mode;
1129266cd583SDr. David Alan Gilbert 
1130266cd583SDr. David Alan Gilbert 	if (sda->index < 3 &&
1131266cd583SDr. David Alan Gilbert 		(devattr->show == show_fan_max_output ||
1132266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_step_output) &&
1133266cd583SDr. David Alan Gilbert 		data->REG_FAN_STEP_OUTPUT &&
1134266cd583SDr. David Alan Gilbert 		data->REG_FAN_STEP_OUTPUT[sda->index] != 0xff)
1135266cd583SDr. David Alan Gilbert 		return a->mode;
1136266cd583SDr. David Alan Gilbert 
1137266cd583SDr. David Alan Gilbert 	/* if fan3 and fan4 are enabled create the files for them */
1138266cd583SDr. David Alan Gilbert 	if (sda->index == 2 &&
1139266cd583SDr. David Alan Gilbert 		(data->has_fan & (1 << 2)) && data->pwm_num >= 3 &&
1140266cd583SDr. David Alan Gilbert 		(devattr->show == show_fan_stop_time ||
1141266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_start_output ||
1142266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_stop_output))
1143266cd583SDr. David Alan Gilbert 		return a->mode;
1144266cd583SDr. David Alan Gilbert 
1145266cd583SDr. David Alan Gilbert 	if (sda->index == 3 &&
1146266cd583SDr. David Alan Gilbert 		(data->has_fan & (1 << 3)) && data->pwm_num >= 4 &&
1147266cd583SDr. David Alan Gilbert 		(devattr->show == show_fan_stop_time ||
1148266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_start_output ||
1149266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_stop_output ||
1150266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_max_output ||
1151266cd583SDr. David Alan Gilbert 		 devattr->show == show_fan_step_output))
1152266cd583SDr. David Alan Gilbert 		return a->mode;
1153266cd583SDr. David Alan Gilbert 
1154266cd583SDr. David Alan Gilbert 	if ((devattr->show == show_target_temp ||
1155266cd583SDr. David Alan Gilbert 	    devattr->show == show_tolerance) &&
1156266cd583SDr. David Alan Gilbert 	    (data->has_fan & (1 << sda->index)) &&
1157266cd583SDr. David Alan Gilbert 	    sda->index < data->pwm_num)
1158266cd583SDr. David Alan Gilbert 		return a->mode;
1159266cd583SDr. David Alan Gilbert 
1160266cd583SDr. David Alan Gilbert 	return 0;
1161266cd583SDr. David Alan Gilbert }
1162266cd583SDr. David Alan Gilbert 
1163266cd583SDr. David Alan Gilbert /* These groups handle non-standard attributes used in this device */
1164266cd583SDr. David Alan Gilbert static struct attribute *w83627ehf_attrs[] = {
1165266cd583SDr. David Alan Gilbert 
1166266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_stop_time.dev_attr.attr,
1167266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_start_output.dev_attr.attr,
1168266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_stop_output.dev_attr.attr,
1169266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_max_output.dev_attr.attr,
1170266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_step_output.dev_attr.attr,
1171266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_target.dev_attr.attr,
1172266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm1_tolerance.dev_attr.attr,
1173266cd583SDr. David Alan Gilbert 
1174266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_stop_time.dev_attr.attr,
1175266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_start_output.dev_attr.attr,
1176266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_stop_output.dev_attr.attr,
1177266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_max_output.dev_attr.attr,
1178266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_step_output.dev_attr.attr,
1179266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_target.dev_attr.attr,
1180266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm2_tolerance.dev_attr.attr,
1181266cd583SDr. David Alan Gilbert 
1182266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_stop_time.dev_attr.attr,
1183266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_start_output.dev_attr.attr,
1184266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_stop_output.dev_attr.attr,
1185266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_max_output.dev_attr.attr,
1186266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_step_output.dev_attr.attr,
1187266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_target.dev_attr.attr,
1188266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm3_tolerance.dev_attr.attr,
1189266cd583SDr. David Alan Gilbert 
1190266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_stop_time.dev_attr.attr,
1191266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_start_output.dev_attr.attr,
1192266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_stop_output.dev_attr.attr,
1193266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_max_output.dev_attr.attr,
1194266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_step_output.dev_attr.attr,
1195266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_target.dev_attr.attr,
1196266cd583SDr. David Alan Gilbert 	&sensor_dev_attr_pwm4_tolerance.dev_attr.attr,
1197266cd583SDr. David Alan Gilbert 
1198266cd583SDr. David Alan Gilbert 	&dev_attr_cpu0_vid.attr,
1199266cd583SDr. David Alan Gilbert 	NULL
1200266cd583SDr. David Alan Gilbert };
1201266cd583SDr. David Alan Gilbert 
1202266cd583SDr. David Alan Gilbert static const struct attribute_group w83627ehf_group = {
1203266cd583SDr. David Alan Gilbert 	.attrs = w83627ehf_attrs,
1204266cd583SDr. David Alan Gilbert 	.is_visible = w83627ehf_attrs_visible,
1205266cd583SDr. David Alan Gilbert };
1206266cd583SDr. David Alan Gilbert 
1207266cd583SDr. David Alan Gilbert static const struct attribute_group *w83627ehf_groups[] = {
1208266cd583SDr. David Alan Gilbert 	&w83627ehf_group,
1209266cd583SDr. David Alan Gilbert 	NULL
1210363a12a4SDmitry Artamonow };
1211363a12a4SDmitry Artamonow 
121208e7e278SJean Delvare /*
12131ea6dd38SDavid Hubbard  * Driver and device management
121408e7e278SJean Delvare  */
121508e7e278SJean Delvare 
12161ea6dd38SDavid Hubbard /* Get the monitoring functions started */
w83627ehf_init_device(struct w83627ehf_data * data,enum kinds kind)12176c931ae1SBill Pemberton static inline void w83627ehf_init_device(struct w83627ehf_data *data,
1218bf164c58SJean Delvare 						   enum kinds kind)
121908e7e278SJean Delvare {
122008e7e278SJean Delvare 	int i;
1221da667365SJean Delvare 	u8 tmp, diode;
122208e7e278SJean Delvare 
122308e7e278SJean Delvare 	/* Start monitoring is needed */
12241ea6dd38SDavid Hubbard 	tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
122508e7e278SJean Delvare 	if (!(tmp & 0x01))
12261ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
122708e7e278SJean Delvare 				      tmp | 0x01);
122808e7e278SJean Delvare 
1229d36cf32cSGuenter Roeck 	/* Enable temperature sensors if needed */
1230d36cf32cSGuenter Roeck 	for (i = 0; i < NUM_REG_TEMP; i++) {
1231d36cf32cSGuenter Roeck 		if (!(data->have_temp & (1 << i)))
1232d36cf32cSGuenter Roeck 			continue;
1233ec3e5a16SGuenter Roeck 		if (!data->reg_temp_config[i])
1234d36cf32cSGuenter Roeck 			continue;
12351ea6dd38SDavid Hubbard 		tmp = w83627ehf_read_value(data,
1236ec3e5a16SGuenter Roeck 					   data->reg_temp_config[i]);
123708e7e278SJean Delvare 		if (tmp & 0x01)
12381ea6dd38SDavid Hubbard 			w83627ehf_write_value(data,
1239ec3e5a16SGuenter Roeck 					      data->reg_temp_config[i],
124008e7e278SJean Delvare 					      tmp & 0xfe);
124108e7e278SJean Delvare 	}
1242d3130f0eSJean Delvare 
1243d3130f0eSJean Delvare 	/* Enable VBAT monitoring if needed */
1244d3130f0eSJean Delvare 	tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1245d3130f0eSJean Delvare 	if (!(tmp & 0x01))
1246d3130f0eSJean Delvare 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
1247da667365SJean Delvare 
1248da667365SJean Delvare 	/* Get thermal sensor types */
1249bf164c58SJean Delvare 	switch (kind) {
1250bf164c58SJean Delvare 	case w83627ehf:
1251da667365SJean Delvare 		diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1252bf164c58SJean Delvare 		break;
1253eff7687dSJean Delvare 	case w83627uhg:
1254eff7687dSJean Delvare 		diode = 0x00;
1255eff7687dSJean Delvare 		break;
1256bf164c58SJean Delvare 	default:
1257bf164c58SJean Delvare 		diode = 0x70;
1258bf164c58SJean Delvare 	}
1259da667365SJean Delvare 	for (i = 0; i < 3; i++) {
1260bfa02b0dSGuenter Roeck 		const char *label = NULL;
1261bfa02b0dSGuenter Roeck 
1262bfa02b0dSGuenter Roeck 		if (data->temp_label)
1263bfa02b0dSGuenter Roeck 			label = data->temp_label[data->temp_src[i]];
12642265cef2SJean Delvare 
12652265cef2SJean Delvare 		/* Digital source overrides analog type */
1266bfa02b0dSGuenter Roeck 		if (label && strncmp(label, "PECI", 4) == 0)
12672265cef2SJean Delvare 			data->temp_type[i] = 6;
1268bfa02b0dSGuenter Roeck 		else if (label && strncmp(label, "AMD", 3) == 0)
12692265cef2SJean Delvare 			data->temp_type[i] = 5;
12702265cef2SJean Delvare 		else if ((tmp & (0x02 << i)))
1271bf164c58SJean Delvare 			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
1272da667365SJean Delvare 		else
1273da667365SJean Delvare 			data->temp_type[i] = 4; /* thermistor */
1274da667365SJean Delvare 	}
127508e7e278SJean Delvare }
127608e7e278SJean Delvare 
12776c931ae1SBill Pemberton static void
w83627ehf_set_temp_reg_ehf(struct w83627ehf_data * data,int n_temp)12786ba71de5SJean Delvare w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp)
12796ba71de5SJean Delvare {
12806ba71de5SJean Delvare 	int i;
12816ba71de5SJean Delvare 
12826ba71de5SJean Delvare 	for (i = 0; i < n_temp; i++) {
12836ba71de5SJean Delvare 		data->reg_temp[i] = W83627EHF_REG_TEMP[i];
12846ba71de5SJean Delvare 		data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
12856ba71de5SJean Delvare 		data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
12866ba71de5SJean Delvare 		data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
12876ba71de5SJean Delvare 	}
12886ba71de5SJean Delvare }
12896ba71de5SJean Delvare 
12906c931ae1SBill Pemberton static void
w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data * sio_data,struct w83627ehf_data * data)129103f5de2bSJean Delvare w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data,
129203f5de2bSJean Delvare 			   struct w83627ehf_data *data)
129303f5de2bSJean Delvare {
129439292371SYueHaibing 	int fan3pin, fan4pin, fan5pin, regval;
129503f5de2bSJean Delvare 
1296eff7687dSJean Delvare 	/* The W83627UHG is simple, only two fan inputs, no config */
1297eff7687dSJean Delvare 	if (sio_data->kind == w83627uhg) {
1298eff7687dSJean Delvare 		data->has_fan = 0x03; /* fan1 and fan2 */
1299eff7687dSJean Delvare 		data->has_fan_min = 0x03;
1300eff7687dSJean Delvare 		return;
1301eff7687dSJean Delvare 	}
1302eff7687dSJean Delvare 
130303f5de2bSJean Delvare 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
13043207408aSDr. David Alan Gilbert 	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
130503f5de2bSJean Delvare 		fan3pin = 1;
130603f5de2bSJean Delvare 		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
130703f5de2bSJean Delvare 		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
130803f5de2bSJean Delvare 	} else {
130903f5de2bSJean Delvare 		fan3pin = 1;
131003f5de2bSJean Delvare 		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
131103f5de2bSJean Delvare 		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
131203f5de2bSJean Delvare 	}
131303f5de2bSJean Delvare 
131403f5de2bSJean Delvare 	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
131503f5de2bSJean Delvare 	data->has_fan |= (fan3pin << 2);
131603f5de2bSJean Delvare 	data->has_fan_min |= (fan3pin << 2);
131703f5de2bSJean Delvare 
131803f5de2bSJean Delvare 	/*
131903f5de2bSJean Delvare 	 * It looks like fan4 and fan5 pins can be alternatively used
132003f5de2bSJean Delvare 	 * as fan on/off switches, but fan5 control is write only :/
132103f5de2bSJean Delvare 	 * We assume that if the serial interface is disabled, designers
132203f5de2bSJean Delvare 	 * connected fan5 as input unless they are emitting log 1, which
132303f5de2bSJean Delvare 	 * is not the default.
132403f5de2bSJean Delvare 	 */
132503f5de2bSJean Delvare 	regval = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
132603f5de2bSJean Delvare 	if ((regval & (1 << 2)) && fan4pin) {
132703f5de2bSJean Delvare 		data->has_fan |= (1 << 3);
132803f5de2bSJean Delvare 		data->has_fan_min |= (1 << 3);
132903f5de2bSJean Delvare 	}
133003f5de2bSJean Delvare 	if (!(regval & (1 << 1)) && fan5pin) {
133103f5de2bSJean Delvare 		data->has_fan |= (1 << 4);
133203f5de2bSJean Delvare 		data->has_fan_min |= (1 << 4);
133303f5de2bSJean Delvare 	}
133403f5de2bSJean Delvare }
133503f5de2bSJean Delvare 
1336266cd583SDr. David Alan Gilbert static umode_t
w83627ehf_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)1337266cd583SDr. David Alan Gilbert w83627ehf_is_visible(const void *drvdata, enum hwmon_sensor_types type,
1338266cd583SDr. David Alan Gilbert 		     u32 attr, int channel)
1339266cd583SDr. David Alan Gilbert {
1340266cd583SDr. David Alan Gilbert 	const struct w83627ehf_data *data = drvdata;
1341266cd583SDr. David Alan Gilbert 
1342266cd583SDr. David Alan Gilbert 	switch (type) {
1343266cd583SDr. David Alan Gilbert 	case hwmon_temp:
1344266cd583SDr. David Alan Gilbert 		/* channel 0.., name 1.. */
1345266cd583SDr. David Alan Gilbert 		if (!(data->have_temp & (1 << channel)))
1346266cd583SDr. David Alan Gilbert 			return 0;
1347e61d2392SGuenter Roeck 		if (attr == hwmon_temp_input)
1348266cd583SDr. David Alan Gilbert 			return 0444;
1349e61d2392SGuenter Roeck 		if (attr == hwmon_temp_label) {
1350e61d2392SGuenter Roeck 			if (data->temp_label)
1351e61d2392SGuenter Roeck 				return 0444;
1352e61d2392SGuenter Roeck 			return 0;
1353e61d2392SGuenter Roeck 		}
1354266cd583SDr. David Alan Gilbert 		if (channel == 2 && data->temp3_val_only)
1355266cd583SDr. David Alan Gilbert 			return 0;
1356266cd583SDr. David Alan Gilbert 		if (attr == hwmon_temp_max) {
1357266cd583SDr. David Alan Gilbert 			if (data->reg_temp_over[channel])
1358266cd583SDr. David Alan Gilbert 				return 0644;
1359266cd583SDr. David Alan Gilbert 			else
1360266cd583SDr. David Alan Gilbert 				return 0;
1361266cd583SDr. David Alan Gilbert 		}
1362266cd583SDr. David Alan Gilbert 		if (attr == hwmon_temp_max_hyst) {
1363266cd583SDr. David Alan Gilbert 			if (data->reg_temp_hyst[channel])
1364266cd583SDr. David Alan Gilbert 				return 0644;
1365266cd583SDr. David Alan Gilbert 			else
1366266cd583SDr. David Alan Gilbert 				return 0;
1367266cd583SDr. David Alan Gilbert 		}
1368266cd583SDr. David Alan Gilbert 		if (channel > 2)
1369266cd583SDr. David Alan Gilbert 			return 0;
1370266cd583SDr. David Alan Gilbert 		if (attr == hwmon_temp_alarm || attr == hwmon_temp_type)
1371266cd583SDr. David Alan Gilbert 			return 0444;
1372266cd583SDr. David Alan Gilbert 		if (attr == hwmon_temp_offset) {
1373266cd583SDr. David Alan Gilbert 			if (data->have_temp_offset & (1 << channel))
1374266cd583SDr. David Alan Gilbert 				return 0644;
1375266cd583SDr. David Alan Gilbert 			else
1376266cd583SDr. David Alan Gilbert 				return 0;
1377266cd583SDr. David Alan Gilbert 		}
1378266cd583SDr. David Alan Gilbert 		break;
1379266cd583SDr. David Alan Gilbert 
1380266cd583SDr. David Alan Gilbert 	case hwmon_fan:
1381266cd583SDr. David Alan Gilbert 		/* channel 0.., name 1.. */
1382266cd583SDr. David Alan Gilbert 		if (!(data->has_fan & (1 << channel)))
1383266cd583SDr. David Alan Gilbert 			return 0;
1384266cd583SDr. David Alan Gilbert 		if (attr == hwmon_fan_input || attr == hwmon_fan_alarm)
1385266cd583SDr. David Alan Gilbert 			return 0444;
1386266cd583SDr. David Alan Gilbert 		if (attr == hwmon_fan_div) {
1387266cd583SDr. David Alan Gilbert 			return 0444;
1388266cd583SDr. David Alan Gilbert 		}
1389266cd583SDr. David Alan Gilbert 		if (attr == hwmon_fan_min) {
1390266cd583SDr. David Alan Gilbert 			if (data->has_fan_min & (1 << channel))
1391266cd583SDr. David Alan Gilbert 				return 0644;
1392266cd583SDr. David Alan Gilbert 			else
1393266cd583SDr. David Alan Gilbert 				return 0;
1394266cd583SDr. David Alan Gilbert 		}
1395266cd583SDr. David Alan Gilbert 		break;
1396266cd583SDr. David Alan Gilbert 
1397266cd583SDr. David Alan Gilbert 	case hwmon_in:
1398266cd583SDr. David Alan Gilbert 		/* channel 0.., name 0.. */
1399266cd583SDr. David Alan Gilbert 		if (channel >= data->in_num)
1400266cd583SDr. David Alan Gilbert 			return 0;
1401266cd583SDr. David Alan Gilbert 		if (channel == 6 && data->in6_skip)
1402266cd583SDr. David Alan Gilbert 			return 0;
1403266cd583SDr. David Alan Gilbert 		if (attr == hwmon_in_alarm || attr == hwmon_in_input)
1404266cd583SDr. David Alan Gilbert 			return 0444;
1405266cd583SDr. David Alan Gilbert 		if (attr == hwmon_in_min || attr == hwmon_in_max)
1406266cd583SDr. David Alan Gilbert 			return 0644;
1407266cd583SDr. David Alan Gilbert 		break;
1408266cd583SDr. David Alan Gilbert 
1409266cd583SDr. David Alan Gilbert 	case hwmon_pwm:
1410266cd583SDr. David Alan Gilbert 		/* channel 0.., name 1.. */
1411266cd583SDr. David Alan Gilbert 		if (!(data->has_fan & (1 << channel)) ||
1412266cd583SDr. David Alan Gilbert 		    channel >= data->pwm_num)
1413266cd583SDr. David Alan Gilbert 			return 0;
1414266cd583SDr. David Alan Gilbert 		if (attr == hwmon_pwm_mode || attr == hwmon_pwm_enable ||
1415266cd583SDr. David Alan Gilbert 		    attr == hwmon_pwm_input)
1416266cd583SDr. David Alan Gilbert 			return 0644;
1417266cd583SDr. David Alan Gilbert 		break;
1418266cd583SDr. David Alan Gilbert 
1419266cd583SDr. David Alan Gilbert 	case hwmon_intrusion:
1420266cd583SDr. David Alan Gilbert 		return 0644;
1421266cd583SDr. David Alan Gilbert 
1422266cd583SDr. David Alan Gilbert 	default: /* Shouldn't happen */
1423266cd583SDr. David Alan Gilbert 		return 0;
1424266cd583SDr. David Alan Gilbert 	}
1425266cd583SDr. David Alan Gilbert 
1426266cd583SDr. David Alan Gilbert 	return 0; /* Shouldn't happen */
1427266cd583SDr. David Alan Gilbert }
1428266cd583SDr. David Alan Gilbert 
1429266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_temp(struct w83627ehf_data * data,u32 attr,int channel,long * val)1430266cd583SDr. David Alan Gilbert w83627ehf_do_read_temp(struct w83627ehf_data *data, u32 attr,
1431266cd583SDr. David Alan Gilbert 		       int channel, long *val)
1432266cd583SDr. David Alan Gilbert {
1433266cd583SDr. David Alan Gilbert 	switch (attr) {
1434266cd583SDr. David Alan Gilbert 	case hwmon_temp_input:
1435266cd583SDr. David Alan Gilbert 		*val = LM75_TEMP_FROM_REG(data->temp[channel]);
1436266cd583SDr. David Alan Gilbert 		return 0;
1437266cd583SDr. David Alan Gilbert 	case hwmon_temp_max:
1438266cd583SDr. David Alan Gilbert 		*val = LM75_TEMP_FROM_REG(data->temp_max[channel]);
1439266cd583SDr. David Alan Gilbert 		return 0;
1440266cd583SDr. David Alan Gilbert 	case hwmon_temp_max_hyst:
1441266cd583SDr. David Alan Gilbert 		*val = LM75_TEMP_FROM_REG(data->temp_max_hyst[channel]);
1442266cd583SDr. David Alan Gilbert 		return 0;
1443266cd583SDr. David Alan Gilbert 	case hwmon_temp_offset:
1444266cd583SDr. David Alan Gilbert 		*val = data->temp_offset[channel] * 1000;
1445266cd583SDr. David Alan Gilbert 		return 0;
1446266cd583SDr. David Alan Gilbert 	case hwmon_temp_type:
1447266cd583SDr. David Alan Gilbert 		*val = (int)data->temp_type[channel];
1448266cd583SDr. David Alan Gilbert 		return 0;
1449266cd583SDr. David Alan Gilbert 	case hwmon_temp_alarm:
1450266cd583SDr. David Alan Gilbert 		if (channel < 3) {
1451266cd583SDr. David Alan Gilbert 			static const int bit[] = { 4, 5, 13 };
1452266cd583SDr. David Alan Gilbert 
1453266cd583SDr. David Alan Gilbert 			*val = (data->alarms >> bit[channel]) & 1;
1454266cd583SDr. David Alan Gilbert 			return 0;
1455266cd583SDr. David Alan Gilbert 		}
1456266cd583SDr. David Alan Gilbert 		break;
1457266cd583SDr. David Alan Gilbert 
1458266cd583SDr. David Alan Gilbert 	default:
1459266cd583SDr. David Alan Gilbert 		break;
1460266cd583SDr. David Alan Gilbert 	}
1461266cd583SDr. David Alan Gilbert 
1462266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1463266cd583SDr. David Alan Gilbert }
1464266cd583SDr. David Alan Gilbert 
1465266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_in(struct w83627ehf_data * data,u32 attr,int channel,long * val)1466266cd583SDr. David Alan Gilbert w83627ehf_do_read_in(struct w83627ehf_data *data, u32 attr,
1467266cd583SDr. David Alan Gilbert 		     int channel, long *val)
1468266cd583SDr. David Alan Gilbert {
1469266cd583SDr. David Alan Gilbert 	switch (attr) {
1470266cd583SDr. David Alan Gilbert 	case hwmon_in_input:
1471266cd583SDr. David Alan Gilbert 		*val = in_from_reg(data->in[channel], channel, data->scale_in);
1472266cd583SDr. David Alan Gilbert 		return 0;
1473266cd583SDr. David Alan Gilbert 	case hwmon_in_min:
1474266cd583SDr. David Alan Gilbert 		*val = in_from_reg(data->in_min[channel], channel,
1475266cd583SDr. David Alan Gilbert 				   data->scale_in);
1476266cd583SDr. David Alan Gilbert 		return 0;
1477266cd583SDr. David Alan Gilbert 	case hwmon_in_max:
1478266cd583SDr. David Alan Gilbert 		*val = in_from_reg(data->in_max[channel], channel,
1479266cd583SDr. David Alan Gilbert 				   data->scale_in);
1480266cd583SDr. David Alan Gilbert 		return 0;
1481266cd583SDr. David Alan Gilbert 	case hwmon_in_alarm:
1482266cd583SDr. David Alan Gilbert 		if (channel < 10) {
1483266cd583SDr. David Alan Gilbert 			static const int bit[] = { 0, 1, 2, 3, 8, 21, 20, 16, 17, 19 };
1484266cd583SDr. David Alan Gilbert 
1485266cd583SDr. David Alan Gilbert 			*val = (data->alarms >> bit[channel]) & 1;
1486266cd583SDr. David Alan Gilbert 			return 0;
1487266cd583SDr. David Alan Gilbert 		}
1488266cd583SDr. David Alan Gilbert 		break;
1489266cd583SDr. David Alan Gilbert 	default:
1490266cd583SDr. David Alan Gilbert 		break;
1491266cd583SDr. David Alan Gilbert 	}
1492266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1493266cd583SDr. David Alan Gilbert }
1494266cd583SDr. David Alan Gilbert 
1495266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_fan(struct w83627ehf_data * data,u32 attr,int channel,long * val)1496266cd583SDr. David Alan Gilbert w83627ehf_do_read_fan(struct w83627ehf_data *data, u32 attr,
1497266cd583SDr. David Alan Gilbert 		      int channel, long *val)
1498266cd583SDr. David Alan Gilbert {
1499266cd583SDr. David Alan Gilbert 	switch (attr) {
1500266cd583SDr. David Alan Gilbert 	case hwmon_fan_input:
1501266cd583SDr. David Alan Gilbert 		*val = data->rpm[channel];
150269595502SDr. David Alan Gilbert 		return 0;
1503266cd583SDr. David Alan Gilbert 	case hwmon_fan_min:
1504266cd583SDr. David Alan Gilbert 		*val = fan_from_reg8(data->fan_min[channel],
1505266cd583SDr. David Alan Gilbert 				     data->fan_div[channel]);
1506266cd583SDr. David Alan Gilbert 		return 0;
1507266cd583SDr. David Alan Gilbert 	case hwmon_fan_div:
1508266cd583SDr. David Alan Gilbert 		*val = div_from_reg(data->fan_div[channel]);
1509266cd583SDr. David Alan Gilbert 		return 0;
1510266cd583SDr. David Alan Gilbert 	case hwmon_fan_alarm:
1511266cd583SDr. David Alan Gilbert 		if (channel < 5) {
1512266cd583SDr. David Alan Gilbert 			static const int bit[] = { 6, 7, 11, 10, 23 };
1513266cd583SDr. David Alan Gilbert 
1514266cd583SDr. David Alan Gilbert 			*val = (data->alarms >> bit[channel]) & 1;
1515266cd583SDr. David Alan Gilbert 			return 0;
1516266cd583SDr. David Alan Gilbert 		}
1517266cd583SDr. David Alan Gilbert 		break;
1518266cd583SDr. David Alan Gilbert 	default:
1519266cd583SDr. David Alan Gilbert 		break;
1520266cd583SDr. David Alan Gilbert 	}
1521266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1522266cd583SDr. David Alan Gilbert }
1523266cd583SDr. David Alan Gilbert 
1524266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_pwm(struct w83627ehf_data * data,u32 attr,int channel,long * val)1525266cd583SDr. David Alan Gilbert w83627ehf_do_read_pwm(struct w83627ehf_data *data, u32 attr,
1526266cd583SDr. David Alan Gilbert 		      int channel, long *val)
1527266cd583SDr. David Alan Gilbert {
1528266cd583SDr. David Alan Gilbert 	switch (attr) {
1529266cd583SDr. David Alan Gilbert 	case hwmon_pwm_input:
1530266cd583SDr. David Alan Gilbert 		*val = data->pwm[channel];
1531266cd583SDr. David Alan Gilbert 		return 0;
1532266cd583SDr. David Alan Gilbert 	case hwmon_pwm_enable:
1533266cd583SDr. David Alan Gilbert 		*val = data->pwm_enable[channel];
1534266cd583SDr. David Alan Gilbert 		return 0;
1535266cd583SDr. David Alan Gilbert 	case hwmon_pwm_mode:
1536266cd583SDr. David Alan Gilbert 		*val = data->pwm_enable[channel];
1537266cd583SDr. David Alan Gilbert 		return 0;
1538266cd583SDr. David Alan Gilbert 	default:
1539266cd583SDr. David Alan Gilbert 		break;
1540266cd583SDr. David Alan Gilbert 	}
1541266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1542266cd583SDr. David Alan Gilbert }
1543266cd583SDr. David Alan Gilbert 
1544266cd583SDr. David Alan Gilbert static int
w83627ehf_do_read_intrusion(struct w83627ehf_data * data,u32 attr,int channel,long * val)1545931f397bSDr. David Alan Gilbert w83627ehf_do_read_intrusion(struct w83627ehf_data *data, u32 attr,
1546266cd583SDr. David Alan Gilbert 			    int channel, long *val)
1547266cd583SDr. David Alan Gilbert {
1548931f397bSDr. David Alan Gilbert 	if (attr != hwmon_intrusion_alarm || channel != 0)
1549266cd583SDr. David Alan Gilbert 		return -EOPNOTSUPP; /* shouldn't happen */
1550266cd583SDr. David Alan Gilbert 
1551266cd583SDr. David Alan Gilbert 	*val = !!(data->caseopen & 0x10);
1552266cd583SDr. David Alan Gilbert 	return 0;
1553266cd583SDr. David Alan Gilbert }
1554266cd583SDr. David Alan Gilbert 
1555266cd583SDr. David Alan Gilbert static int
w83627ehf_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)1556266cd583SDr. David Alan Gilbert w83627ehf_read(struct device *dev, enum hwmon_sensor_types type,
1557266cd583SDr. David Alan Gilbert 			u32 attr, int channel, long *val)
1558266cd583SDr. David Alan Gilbert {
1559266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = w83627ehf_update_device(dev->parent);
1560266cd583SDr. David Alan Gilbert 
1561266cd583SDr. David Alan Gilbert 	switch (type) {
1562266cd583SDr. David Alan Gilbert 	case hwmon_fan:
1563266cd583SDr. David Alan Gilbert 		return w83627ehf_do_read_fan(data, attr, channel, val);
1564266cd583SDr. David Alan Gilbert 
1565266cd583SDr. David Alan Gilbert 	case hwmon_in:
1566266cd583SDr. David Alan Gilbert 		return w83627ehf_do_read_in(data, attr, channel, val);
1567266cd583SDr. David Alan Gilbert 
1568266cd583SDr. David Alan Gilbert 	case hwmon_pwm:
1569266cd583SDr. David Alan Gilbert 		return w83627ehf_do_read_pwm(data, attr, channel, val);
1570266cd583SDr. David Alan Gilbert 
1571266cd583SDr. David Alan Gilbert 	case hwmon_temp:
1572266cd583SDr. David Alan Gilbert 		return w83627ehf_do_read_temp(data, attr, channel, val);
1573266cd583SDr. David Alan Gilbert 
1574266cd583SDr. David Alan Gilbert 	case hwmon_intrusion:
1575266cd583SDr. David Alan Gilbert 		return w83627ehf_do_read_intrusion(data, attr, channel, val);
1576266cd583SDr. David Alan Gilbert 
1577266cd583SDr. David Alan Gilbert 	default:
1578266cd583SDr. David Alan Gilbert 		break;
1579266cd583SDr. David Alan Gilbert 	}
1580266cd583SDr. David Alan Gilbert 
1581266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1582266cd583SDr. David Alan Gilbert }
1583266cd583SDr. David Alan Gilbert 
1584266cd583SDr. David Alan Gilbert static int
w83627ehf_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)1585266cd583SDr. David Alan Gilbert w83627ehf_read_string(struct device *dev, enum hwmon_sensor_types type,
1586266cd583SDr. David Alan Gilbert 		      u32 attr, int channel, const char **str)
1587266cd583SDr. David Alan Gilbert {
1588266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1589266cd583SDr. David Alan Gilbert 
1590266cd583SDr. David Alan Gilbert 	switch (type) {
1591266cd583SDr. David Alan Gilbert 	case hwmon_temp:
1592266cd583SDr. David Alan Gilbert 		if (attr == hwmon_temp_label) {
1593266cd583SDr. David Alan Gilbert 			*str = data->temp_label[data->temp_src[channel]];
1594266cd583SDr. David Alan Gilbert 			return 0;
1595266cd583SDr. David Alan Gilbert 		}
1596266cd583SDr. David Alan Gilbert 		break;
1597266cd583SDr. David Alan Gilbert 
1598266cd583SDr. David Alan Gilbert 	default:
1599266cd583SDr. David Alan Gilbert 		break;
1600266cd583SDr. David Alan Gilbert 	}
1601266cd583SDr. David Alan Gilbert 	/* Nothing else should be read as a string */
1602266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1603266cd583SDr. David Alan Gilbert }
1604266cd583SDr. David Alan Gilbert 
1605266cd583SDr. David Alan Gilbert static int
w83627ehf_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)1606266cd583SDr. David Alan Gilbert w83627ehf_write(struct device *dev, enum hwmon_sensor_types type,
1607266cd583SDr. David Alan Gilbert 			u32 attr, int channel, long val)
1608266cd583SDr. David Alan Gilbert {
1609266cd583SDr. David Alan Gilbert 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1610266cd583SDr. David Alan Gilbert 
1611266cd583SDr. David Alan Gilbert 	if (type == hwmon_in && attr == hwmon_in_min)
1612266cd583SDr. David Alan Gilbert 		return store_in_min(dev, data, channel, val);
1613266cd583SDr. David Alan Gilbert 	if (type == hwmon_in && attr == hwmon_in_max)
1614266cd583SDr. David Alan Gilbert 		return store_in_max(dev, data, channel, val);
1615266cd583SDr. David Alan Gilbert 
1616266cd583SDr. David Alan Gilbert 	if (type == hwmon_fan && attr == hwmon_fan_min)
1617266cd583SDr. David Alan Gilbert 		return store_fan_min(dev, data, channel, val);
1618266cd583SDr. David Alan Gilbert 
1619266cd583SDr. David Alan Gilbert 	if (type == hwmon_temp && attr == hwmon_temp_max)
1620266cd583SDr. David Alan Gilbert 		return store_temp_max(dev, data, channel, val);
1621266cd583SDr. David Alan Gilbert 	if (type == hwmon_temp && attr == hwmon_temp_max_hyst)
1622266cd583SDr. David Alan Gilbert 		return store_temp_max_hyst(dev, data, channel, val);
1623266cd583SDr. David Alan Gilbert 	if (type == hwmon_temp && attr == hwmon_temp_offset)
1624266cd583SDr. David Alan Gilbert 		return store_temp_offset(dev, data, channel, val);
1625266cd583SDr. David Alan Gilbert 
1626266cd583SDr. David Alan Gilbert 	if (type == hwmon_pwm && attr == hwmon_pwm_mode)
1627266cd583SDr. David Alan Gilbert 		return store_pwm_mode(dev, data, channel, val);
1628266cd583SDr. David Alan Gilbert 	if (type == hwmon_pwm && attr == hwmon_pwm_enable)
1629266cd583SDr. David Alan Gilbert 		return store_pwm_enable(dev, data, channel, val);
1630266cd583SDr. David Alan Gilbert 	if (type == hwmon_pwm && attr == hwmon_pwm_input)
1631266cd583SDr. David Alan Gilbert 		return store_pwm(dev, data, channel, val);
1632266cd583SDr. David Alan Gilbert 
1633266cd583SDr. David Alan Gilbert 	if (type == hwmon_intrusion && attr == hwmon_intrusion_alarm)
1634266cd583SDr. David Alan Gilbert 		return clear_caseopen(dev, data, channel, val);
1635266cd583SDr. David Alan Gilbert 
1636266cd583SDr. David Alan Gilbert 	return -EOPNOTSUPP;
1637266cd583SDr. David Alan Gilbert }
1638266cd583SDr. David Alan Gilbert 
1639266cd583SDr. David Alan Gilbert static const struct hwmon_ops w83627ehf_ops = {
1640266cd583SDr. David Alan Gilbert 	.is_visible = w83627ehf_is_visible,
1641266cd583SDr. David Alan Gilbert 	.read = w83627ehf_read,
1642266cd583SDr. David Alan Gilbert 	.read_string = w83627ehf_read_string,
1643*b418bd0aSKrzysztof Kozlowski 	.write = w83627ehf_write,
1644266cd583SDr. David Alan Gilbert };
1645266cd583SDr. David Alan Gilbert 
1646266cd583SDr. David Alan Gilbert static const struct hwmon_channel_info * const w83627ehf_info[] = {
1647266cd583SDr. David Alan Gilbert 	HWMON_CHANNEL_INFO(fan,
1648266cd583SDr. David Alan Gilbert 		HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1649266cd583SDr. David Alan Gilbert 		HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1650266cd583SDr. David Alan Gilbert 		HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1651266cd583SDr. David Alan Gilbert 		HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN,
1652266cd583SDr. David Alan Gilbert 		HWMON_F_ALARM | HWMON_F_DIV | HWMON_F_INPUT | HWMON_F_MIN),
1653266cd583SDr. David Alan Gilbert 	HWMON_CHANNEL_INFO(in,
1654266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1655266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1656266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1657266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1658266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1659266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1660266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1661266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1662266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN,
1663266cd583SDr. David Alan Gilbert 		HWMON_I_ALARM | HWMON_I_INPUT | HWMON_I_MAX | HWMON_I_MIN),
1664266cd583SDr. David Alan Gilbert 	HWMON_CHANNEL_INFO(pwm,
1665266cd583SDr. David Alan Gilbert 		HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1666266cd583SDr. David Alan Gilbert 		HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1667266cd583SDr. David Alan Gilbert 		HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE,
1668266cd583SDr. David Alan Gilbert 		HWMON_PWM_ENABLE | HWMON_PWM_INPUT | HWMON_PWM_MODE),
1669266cd583SDr. David Alan Gilbert 	HWMON_CHANNEL_INFO(temp,
1670266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1671266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1672266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1673266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1674266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1675266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1676266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1677266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1678266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1679266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1680266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1681266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1682266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1683266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1684266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1685266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE,
1686266cd583SDr. David Alan Gilbert 		HWMON_T_ALARM | HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_MAX |
1687266cd583SDr. David Alan Gilbert 			HWMON_T_MAX_HYST | HWMON_T_OFFSET | HWMON_T_TYPE),
1688266cd583SDr. David Alan Gilbert 	HWMON_CHANNEL_INFO(intrusion,
1689266cd583SDr. David Alan Gilbert 		HWMON_INTRUSION_ALARM),
1690266cd583SDr. David Alan Gilbert 	NULL
1691266cd583SDr. David Alan Gilbert };
1692266cd583SDr. David Alan Gilbert 
1693266cd583SDr. David Alan Gilbert static const struct hwmon_chip_info w83627ehf_chip_info = {
1694266cd583SDr. David Alan Gilbert 	.ops = &w83627ehf_ops,
1695964c1c91SArmin Wolf 	.info = w83627ehf_info,
169608e7e278SJean Delvare };
16971ea6dd38SDavid Hubbard 
w83627ehf_probe(struct platform_device * pdev)1698a8b3a3a5SJingoo Han static int __init w83627ehf_probe(struct platform_device *pdev)
169908e7e278SJean Delvare {
17001ea6dd38SDavid Hubbard 	struct device *dev = &pdev->dev;
170103f5de2bSJean Delvare 	struct w83627ehf_sio_data *sio_data = dev_get_platdata(dev);
170208e7e278SJean Delvare 	struct w83627ehf_data *data;
1703266cd583SDr. David Alan Gilbert 	struct resource *res;
170408e7e278SJean Delvare 	u8 en_vrm10;
17051ea6dd38SDavid Hubbard 	int i, err = 0;
1706228f2aedSArmin Wolf 	struct device *hwmon_dev;
1707228f2aedSArmin Wolf 
170808e7e278SJean Delvare 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
1709228f2aedSArmin Wolf 	if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
1710228f2aedSArmin Wolf 		return -EBUSY;
1711228f2aedSArmin Wolf 
171208e7e278SJean Delvare 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
17131ea6dd38SDavid Hubbard 	if (!data)
17149a61bf63SIngo Molnar 		return -ENOMEM;
17159a61bf63SIngo Molnar 
17161ea6dd38SDavid Hubbard 	data->addr = res->start;
17173300fb4fSJean Delvare 	mutex_init(&data->lock);
17181ea6dd38SDavid Hubbard 	mutex_init(&data->update_lock);
171908e7e278SJean Delvare 	data->name = w83627ehf_device_names[sio_data->kind];
1720237c8d2fSGong Jun 	data->bank = 0xff;		/* Force initial bank selection */
1721237c8d2fSGong Jun 	platform_set_drvdata(pdev, data);
17223207408aSDr. David Alan Gilbert 
1723eff7687dSJean Delvare 	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1724eff7687dSJean Delvare 	data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1725eff7687dSJean Delvare 	/* 667HG has 3 pwms, and 627UHG has only 2 */
1726eff7687dSJean Delvare 	switch (sio_data->kind) {
1727eff7687dSJean Delvare 	default:
1728eff7687dSJean Delvare 		data->pwm_num = 4;
1729eff7687dSJean Delvare 		break;
1730eff7687dSJean Delvare 	case w83667hg:
1731eff7687dSJean Delvare 	case w83667hg_b:
1732eff7687dSJean Delvare 		data->pwm_num = 3;
1733eff7687dSJean Delvare 		break;
1734eff7687dSJean Delvare 	case w83627uhg:
173508e7e278SJean Delvare 		data->pwm_num = 2;
17366ba71de5SJean Delvare 		break;
1737d36cf32cSGuenter Roeck 	}
1738ec3e5a16SGuenter Roeck 
1739ec3e5a16SGuenter Roeck 	/* Default to 3 temperature inputs, code below will adjust as needed */
17403207408aSDr. David Alan Gilbert 	data->have_temp = 0x07;
1741d36cf32cSGuenter Roeck 
1742d36cf32cSGuenter Roeck 	/* Deal with temperature register setup first. */
17436ba71de5SJean Delvare 	if (sio_data->kind == w83667hg_b) {
17446ba71de5SJean Delvare 		u8 reg;
1745ec3e5a16SGuenter Roeck 
1746ec3e5a16SGuenter Roeck 		w83627ehf_set_temp_reg_ehf(data, 4);
1747ec3e5a16SGuenter Roeck 
1748ec3e5a16SGuenter Roeck 		/*
1749d36cf32cSGuenter Roeck 		 * Temperature sources are selected with bank 0, registers 0x49
1750d36cf32cSGuenter Roeck 		 * and 0x4a.
1751d36cf32cSGuenter Roeck 		 */
1752d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x4a);
1753d36cf32cSGuenter Roeck 		data->temp_src[0] = reg >> 5;
1754d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x49);
1755d36cf32cSGuenter Roeck 		data->temp_src[1] = reg & 0x07;
1756d36cf32cSGuenter Roeck 		data->temp_src[2] = (reg >> 4) & 0x07;
1757d36cf32cSGuenter Roeck 
1758d36cf32cSGuenter Roeck 		/*
1759d36cf32cSGuenter Roeck 		 * W83667HG-B has another temperature register at 0x7e.
1760d36cf32cSGuenter Roeck 		 * The temperature source is selected with register 0x7d.
1761d36cf32cSGuenter Roeck 		 * Support it if the source differs from already reported
1762d36cf32cSGuenter Roeck 		 * sources.
1763d36cf32cSGuenter Roeck 		 */
1764d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x7d);
1765d36cf32cSGuenter Roeck 		reg &= 0x07;
1766d36cf32cSGuenter Roeck 		if (reg != data->temp_src[0] && reg != data->temp_src[1]
1767d36cf32cSGuenter Roeck 		    && reg != data->temp_src[2]) {
1768d36cf32cSGuenter Roeck 			data->temp_src[3] = reg;
1769d36cf32cSGuenter Roeck 			data->have_temp |= 1 << 3;
1770d36cf32cSGuenter Roeck 		}
1771d36cf32cSGuenter Roeck 
1772d36cf32cSGuenter Roeck 		/*
1773d36cf32cSGuenter Roeck 		 * Chip supports either AUXTIN or VIN3. Try to find out which
1774d36cf32cSGuenter Roeck 		 * one.
1775d36cf32cSGuenter Roeck 		 */
1776d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1777d36cf32cSGuenter Roeck 		if (data->temp_src[2] == 2 && (reg & 0x01))
1778d36cf32cSGuenter Roeck 			data->have_temp &= ~(1 << 2);
1779d36cf32cSGuenter Roeck 
1780d36cf32cSGuenter Roeck 		if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1781d36cf32cSGuenter Roeck 		    || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1782840e191dSGuenter Roeck 			data->in6_skip = 1;
1783840e191dSGuenter Roeck 
1784840e191dSGuenter Roeck 		data->temp_label = w83667hg_b_temp_label;
1785840e191dSGuenter Roeck 		data->have_temp_offset = data->have_temp & 0x07;
1786840e191dSGuenter Roeck 		for (i = 0; i < 3; i++) {
1787eff7687dSJean Delvare 			if (data->temp_src[i] > 2)
1788eff7687dSJean Delvare 				data->have_temp_offset &= ~(1 << i);
1789eff7687dSJean Delvare 		}
1790eff7687dSJean Delvare 	} else if (sio_data->kind == w83627uhg) {
1791eff7687dSJean Delvare 		u8 reg;
1792eff7687dSJean Delvare 
1793aacb6b00SJean Delvare 		w83627ehf_set_temp_reg_ehf(data, 3);
1794eff7687dSJean Delvare 
1795eff7687dSJean Delvare 		/*
1796eff7687dSJean Delvare 		 * Temperature sources for temp2 and temp3 are selected with
1797eff7687dSJean Delvare 		 * bank 0, registers 0x49 and 0x4a.
1798eff7687dSJean Delvare 		 */
1799eff7687dSJean Delvare 		data->temp_src[0] = 0;	/* SYSTIN */
1800aacb6b00SJean Delvare 		reg = w83627ehf_read_value(data, 0x49) & 0x07;
1801eff7687dSJean Delvare 		/* Adjust to have the same mapping as other source registers */
1802aacb6b00SJean Delvare 		if (reg == 0)
1803eff7687dSJean Delvare 			data->temp_src[1] = 1;
1804eff7687dSJean Delvare 		else if (reg >= 2 && reg <= 5)
1805eff7687dSJean Delvare 			data->temp_src[1] = reg + 2;
1806eff7687dSJean Delvare 		else	/* should never happen */
1807eff7687dSJean Delvare 			data->have_temp &= ~(1 << 1);
1808eff7687dSJean Delvare 		reg = w83627ehf_read_value(data, 0x4a);
1809eff7687dSJean Delvare 		data->temp_src[2] = reg >> 5;
1810eff7687dSJean Delvare 
1811eff7687dSJean Delvare 		/*
1812eff7687dSJean Delvare 		 * Skip temp3 if source is invalid or the same as temp1
1813eff7687dSJean Delvare 		 * or temp2.
1814eff7687dSJean Delvare 		 */
1815eff7687dSJean Delvare 		if (data->temp_src[2] == 2 || data->temp_src[2] == 3 ||
1816eff7687dSJean Delvare 		    data->temp_src[2] == data->temp_src[0] ||
1817eff7687dSJean Delvare 		    ((data->have_temp & (1 << 1)) &&
1818eff7687dSJean Delvare 		     data->temp_src[2] == data->temp_src[1]))
1819eff7687dSJean Delvare 			data->have_temp &= ~(1 << 2);
1820eff7687dSJean Delvare 		else
1821eff7687dSJean Delvare 			data->temp3_val_only = 1;	/* No limit regs */
1822eff7687dSJean Delvare 
1823840e191dSGuenter Roeck 		data->in6_skip = 1;			/* No VIN3 */
1824840e191dSGuenter Roeck 
1825840e191dSGuenter Roeck 		data->temp_label = w83667hg_b_temp_label;
1826840e191dSGuenter Roeck 		data->have_temp_offset = data->have_temp & 0x03;
1827840e191dSGuenter Roeck 		for (i = 0; i < 3; i++) {
1828ec3e5a16SGuenter Roeck 			if (data->temp_src[i] > 1)
18296ba71de5SJean Delvare 				data->have_temp_offset &= ~(1 << i);
18306ba71de5SJean Delvare 		}
1831ec3e5a16SGuenter Roeck 	} else {
18326ba71de5SJean Delvare 		w83627ehf_set_temp_reg_ehf(data, 3);
18336ba71de5SJean Delvare 
18346ba71de5SJean Delvare 		/* Temperature sources are fixed */
18356ba71de5SJean Delvare 
18366ba71de5SJean Delvare 		if (sio_data->kind == w83667hg) {
18376ba71de5SJean Delvare 			u8 reg;
18386ba71de5SJean Delvare 
18396ba71de5SJean Delvare 			/*
18406ba71de5SJean Delvare 			 * Chip supports either AUXTIN or VIN3. Try to find
18416ba71de5SJean Delvare 			 * out which one.
18426ba71de5SJean Delvare 			 */
18436ba71de5SJean Delvare 			reg = w83627ehf_read_value(data,
18446ba71de5SJean Delvare 						W83627EHF_REG_TEMP_CONFIG[2]);
18456ba71de5SJean Delvare 			if (reg & 0x01)
1846ec3e5a16SGuenter Roeck 				data->have_temp &= ~(1 << 2);
1847840e191dSGuenter Roeck 			else
1848a157d06dSGong Jun 				data->in6_skip = 1;
1849a157d06dSGong Jun 		}
18503207408aSDr. David Alan Gilbert 		data->have_temp_offset = data->have_temp & 0x07;
1851c39aedafSGuenter Roeck 	}
1852c39aedafSGuenter Roeck 
1853c39aedafSGuenter Roeck 	if (sio_data->kind == w83667hg_b) {
1854c39aedafSGuenter Roeck 		data->REG_FAN_MAX_OUTPUT =
1855c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
1856c39aedafSGuenter Roeck 		data->REG_FAN_STEP_OUTPUT =
1857c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
1858c39aedafSGuenter Roeck 	} else {
1859c39aedafSGuenter Roeck 		data->REG_FAN_MAX_OUTPUT =
1860c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
1861da2e0255SGuenter Roeck 		data->REG_FAN_STEP_OUTPUT =
1862eff7687dSJean Delvare 		  W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
1863eff7687dSJean Delvare 	}
1864eff7687dSJean Delvare 
1865eff7687dSJean Delvare 	/* Setup input voltage scaling factors */
1866eff7687dSJean Delvare 	if (sio_data->kind == w83627uhg)
1867eff7687dSJean Delvare 		data->scale_in = scale_in_w83627uhg;
186808e7e278SJean Delvare 	else
1869bf164c58SJean Delvare 		data->scale_in = scale_in_common;
187008e7e278SJean Delvare 
1871fc18d6c0SJean Delvare 	/* Initialize the chip */
18720d023530SKatsumi Sato 	w83627ehf_init_device(data, sio_data->kind);
18730d023530SKatsumi Sato 
18740d023530SKatsumi Sato 	data->vrm = vid_which_vrm();
1875228f2aedSArmin Wolf 
18760d023530SKatsumi Sato 	err = superio_enter(sio_data->sioreg);
187758e6e781SJean Delvare 	if (err)
18783207408aSDr. David Alan Gilbert 		return err;
18798969e84dSGuenter Roeck 
18808969e84dSGuenter Roeck 	/* Read VID value */
18818969e84dSGuenter Roeck 	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
18828969e84dSGuenter Roeck 		/*
18838969e84dSGuenter Roeck 		 * W83667HG has different pins for VID input and output, so
1884237c8d2fSGong Jun 		 * we can get the VID input values directly at logical device D
1885237c8d2fSGong Jun 		 * 0xe3.
1886266cd583SDr. David Alan Gilbert 		 */
1887eff7687dSJean Delvare 		superio_select(sio_data->sioreg, W83667HG_LD_VID);
188858e6e781SJean Delvare 		data->vid = superio_inb(sio_data->sioreg, 0xe3);
188958e6e781SJean Delvare 		data->have_vid = true;
18908969e84dSGuenter Roeck 	} else if (sio_data->kind != w83627uhg) {
18918969e84dSGuenter Roeck 		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
18928969e84dSGuenter Roeck 		if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
18938969e84dSGuenter Roeck 			/*
18948969e84dSGuenter Roeck 			 * Set VID input sensibility if needed. In theory the
18958969e84dSGuenter Roeck 			 * BIOS should have set it, but in practice it's not
18968969e84dSGuenter Roeck 			 * always the case. We only do it for the W83627EHF/EHG
189758e6e781SJean Delvare 			 * because the W83627DHG is more complex in this
189858e6e781SJean Delvare 			 * respect.
189958e6e781SJean Delvare 			 */
190058e6e781SJean Delvare 			if (sio_data->kind == w83627ehf) {
1901b55f3757SGuenter Roeck 				en_vrm10 = superio_inb(sio_data->sioreg,
1902b55f3757SGuenter Roeck 						       SIO_REG_EN_VRM10);
1903237c8d2fSGong Jun 				if ((en_vrm10 & 0x08) && data->vrm == 90) {
1904237c8d2fSGong Jun 					dev_warn(dev,
1905fc18d6c0SJean Delvare 						 "Setting VID input voltage to TTL\n");
1906237c8d2fSGong Jun 					superio_outb(sio_data->sioreg,
1907237c8d2fSGong Jun 						     SIO_REG_EN_VRM10,
1908b55f3757SGuenter Roeck 						     en_vrm10 & ~0x08);
1909b55f3757SGuenter Roeck 				} else if (!(en_vrm10 & 0x08)
1910237c8d2fSGong Jun 					   && data->vrm == 100) {
1911237c8d2fSGong Jun 					dev_warn(dev,
1912fc18d6c0SJean Delvare 						 "Setting VID input voltage to VRM10\n");
1913fc18d6c0SJean Delvare 					superio_outb(sio_data->sioreg,
191458e6e781SJean Delvare 						     SIO_REG_EN_VRM10,
191558e6e781SJean Delvare 						     en_vrm10 | 0x08);
1916237c8d2fSGong Jun 				}
1917237c8d2fSGong Jun 			}
1918cbe311f2SJean Delvare 
1919cbe311f2SJean Delvare 			data->vid = superio_inb(sio_data->sioreg,
1920266cd583SDr. David Alan Gilbert 						SIO_REG_VID_DATA);
192158e6e781SJean Delvare 			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
1922b55f3757SGuenter Roeck 				data->vid &= 0x3f;
1923b55f3757SGuenter Roeck 			data->have_vid = true;
1924fc18d6c0SJean Delvare 		} else {
1925237c8d2fSGong Jun 			dev_info(dev,
1926fc18d6c0SJean Delvare 				 "VID pins in output mode, CPU VID not available\n");
192703f5de2bSJean Delvare 		}
192808e7e278SJean Delvare 	}
19290d023530SKatsumi Sato 
19300d023530SKatsumi Sato 	w83627ehf_check_fan_inputs(sio_data, data);
1931ea7be66cSMark M. Hoffman 
193269595502SDr. David Alan Gilbert 	superio_exit(sio_data->sioreg);
1933ec3e5a16SGuenter Roeck 
1934ec3e5a16SGuenter Roeck 	/* Read fan clock dividers immediately */
193569595502SDr. David Alan Gilbert 	w83627ehf_update_fan_div(data);
1936ec3e5a16SGuenter Roeck 
1937ec3e5a16SGuenter Roeck 	/* Read pwm data to save original values */
1938ea7be66cSMark M. Hoffman 	w83627ehf_update_pwm(data);
1939266cd583SDr. David Alan Gilbert 	for (i = 0; i < data->pwm_num; i++)
1940266cd583SDr. David Alan Gilbert 		data->pwm_enable_orig[i] = data->pwm_enable[i];
1941266cd583SDr. David Alan Gilbert 
1942266cd583SDr. David Alan Gilbert 	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
1943266cd583SDr. David Alan Gilbert 							 data->name,
1944228f2aedSArmin Wolf 							 data,
194508e7e278SJean Delvare 							 &w83627ehf_chip_info,
194608e7e278SJean Delvare 							 w83627ehf_groups);
1947655231d4SJonathan Cameron 	return PTR_ERR_OR_ZERO(hwmon_dev);
19487e630bb5SJean Delvare }
19497e630bb5SJean Delvare 
w83627ehf_suspend(struct device * dev)19507e630bb5SJean Delvare static int w83627ehf_suspend(struct device *dev)
19517e630bb5SJean Delvare {
19527e630bb5SJean Delvare 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
19537e630bb5SJean Delvare 
19547e630bb5SJean Delvare 	mutex_lock(&data->update_lock);
19557e630bb5SJean Delvare 	data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
19567e630bb5SJean Delvare 	mutex_unlock(&data->update_lock);
19577e630bb5SJean Delvare 
1958655231d4SJonathan Cameron 	return 0;
19597e630bb5SJean Delvare }
19607e630bb5SJean Delvare 
w83627ehf_resume(struct device * dev)19617e630bb5SJean Delvare static int w83627ehf_resume(struct device *dev)
19627e630bb5SJean Delvare {
19637e630bb5SJean Delvare 	struct w83627ehf_data *data = dev_get_drvdata(dev);
19647e630bb5SJean Delvare 	int i;
19657e630bb5SJean Delvare 
19667e630bb5SJean Delvare 	mutex_lock(&data->update_lock);
19677e630bb5SJean Delvare 	data->bank = 0xff;		/* Force initial bank selection */
19687e630bb5SJean Delvare 
19697e630bb5SJean Delvare 	/* Restore limits */
19707e630bb5SJean Delvare 	for (i = 0; i < data->in_num; i++) {
19717e630bb5SJean Delvare 		if ((i == 6) && data->in6_skip)
19727e630bb5SJean Delvare 			continue;
19737e630bb5SJean Delvare 
19747e630bb5SJean Delvare 		w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i),
19757e630bb5SJean Delvare 				      data->in_min[i]);
19767e630bb5SJean Delvare 		w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i),
19777e630bb5SJean Delvare 				      data->in_max[i]);
19787e630bb5SJean Delvare 	}
19797e630bb5SJean Delvare 
19807e630bb5SJean Delvare 	for (i = 0; i < 5; i++) {
198169595502SDr. David Alan Gilbert 		if (!(data->has_fan_min & (1 << i)))
19827e630bb5SJean Delvare 			continue;
19837e630bb5SJean Delvare 
19847e630bb5SJean Delvare 		w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[i],
19857e630bb5SJean Delvare 				      data->fan_min[i]);
19867e630bb5SJean Delvare 	}
19877e630bb5SJean Delvare 
19887e630bb5SJean Delvare 	for (i = 0; i < NUM_REG_TEMP; i++) {
19897e630bb5SJean Delvare 		if (!(data->have_temp & (1 << i)))
19907e630bb5SJean Delvare 			continue;
19917e630bb5SJean Delvare 
19927e630bb5SJean Delvare 		if (data->reg_temp_over[i])
19937e630bb5SJean Delvare 			w83627ehf_write_temp(data, data->reg_temp_over[i],
19947e630bb5SJean Delvare 					     data->temp_max[i]);
199545633fb3SJean Delvare 		if (data->reg_temp_hyst[i])
199645633fb3SJean Delvare 			w83627ehf_write_temp(data, data->reg_temp_hyst[i],
19977e630bb5SJean Delvare 					     data->temp_max_hyst[i]);
19987e630bb5SJean Delvare 		if (i > 2)
19997e630bb5SJean Delvare 			continue;
20007e630bb5SJean Delvare 		if (data->have_temp_offset & (1 << i))
20017e630bb5SJean Delvare 			w83627ehf_write_value(data,
20027e630bb5SJean Delvare 					      W83627EHF_REG_TEMP_OFFSET[i],
20037e630bb5SJean Delvare 					      data->temp_offset[i]);
20047e630bb5SJean Delvare 	}
20057e630bb5SJean Delvare 
20067e630bb5SJean Delvare 	/* Restore other settings */
2007952a11caSPaul Fertser 	w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat);
20087e630bb5SJean Delvare 
20097e630bb5SJean Delvare 	/* Force re-reading all values */
20107e630bb5SJean Delvare 	data->valid = false;
20117e630bb5SJean Delvare 	mutex_unlock(&data->update_lock);
20127e630bb5SJean Delvare 
2013655231d4SJonathan Cameron 	return 0;
20147e630bb5SJean Delvare }
20151ea6dd38SDavid Hubbard 
2016cdaf7934SLaurent Riffard static DEFINE_SIMPLE_DEV_PM_OPS(w83627ehf_dev_pm_ops, w83627ehf_suspend, w83627ehf_resume);
20171ea6dd38SDavid Hubbard 
2018655231d4SJonathan Cameron static struct platform_driver w83627ehf_driver = {
2019cdaf7934SLaurent Riffard 	.driver = {
202008e7e278SJean Delvare 		.name	= DRVNAME,
202108e7e278SJean Delvare 		.pm	= pm_sleep_ptr(&w83627ehf_dev_pm_ops),
20221ea6dd38SDavid Hubbard 	},
20231ea6dd38SDavid Hubbard };
20241ea6dd38SDavid Hubbard 
202508e7e278SJean Delvare /* w83627ehf_find() looks for a '627 in the Super-I/O config space */
w83627ehf_find(int sioaddr,unsigned short * addr,struct w83627ehf_sio_data * sio_data)20266f7805a8SUwe Kleine-König static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
20276f7805a8SUwe Kleine-König 				 struct w83627ehf_sio_data *sio_data)
20286f7805a8SUwe Kleine-König {
20296f7805a8SUwe Kleine-König 	static const char sio_name_W83627EHF[] __initconst = "W83627EHF";
20306f7805a8SUwe Kleine-König 	static const char sio_name_W83627EHG[] __initconst = "W83627EHG";
20316f7805a8SUwe Kleine-König 	static const char sio_name_W83627DHG[] __initconst = "W83627DHG";
20326f7805a8SUwe Kleine-König 	static const char sio_name_W83627DHG_P[] __initconst = "W83627DHG-P";
20331ea6dd38SDavid Hubbard 	static const char sio_name_W83627UHG[] __initconst = "W83627UHG";
203408e7e278SJean Delvare 	static const char sio_name_W83667HG[] __initconst = "W83667HG";
20351ea6dd38SDavid Hubbard 	static const char sio_name_W83667HG_B[] __initconst = "W83667HG-B";
20360d023530SKatsumi Sato 
203708e7e278SJean Delvare 	u16 val;
20380d023530SKatsumi Sato 	const char *sio_name;
20390d023530SKatsumi Sato 	int err;
20400d023530SKatsumi Sato 
204108e7e278SJean Delvare 	err = superio_enter(sioaddr);
204267b671bcSJean Delvare 	if (err)
204367b671bcSJean Delvare 		return err;
204467b671bcSJean Delvare 
20451ea6dd38SDavid Hubbard 	if (force_id)
20461ea6dd38SDavid Hubbard 		val = force_id;
2047657c93b1SDavid Hubbard 	else
2048657c93b1SDavid Hubbard 		val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
20491ea6dd38SDavid Hubbard 		    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
20501ea6dd38SDavid Hubbard 	switch (val & SIO_ID_MASK) {
20511ea6dd38SDavid Hubbard 	case SIO_W83627EHF_ID:
2052657c93b1SDavid Hubbard 		sio_data->kind = w83627ehf;
20531ea6dd38SDavid Hubbard 		sio_name = sio_name_W83627EHF;
20541ea6dd38SDavid Hubbard 		break;
20551ea6dd38SDavid Hubbard 	case SIO_W83627EHG_ID:
20561ea6dd38SDavid Hubbard 		sio_data->kind = w83627ehf;
20571ea6dd38SDavid Hubbard 		sio_name = sio_name_W83627EHG;
20581ea6dd38SDavid Hubbard 		break;
2059657c93b1SDavid Hubbard 	case SIO_W83627DHG_ID:
2060c1e48dceSJean Delvare 		sio_data->kind = w83627dhg;
2061c1e48dceSJean Delvare 		sio_name = sio_name_W83627DHG;
2062c1e48dceSJean Delvare 		break;
2063c1e48dceSJean Delvare 	case SIO_W83627DHG_P_ID:
2064eff7687dSJean Delvare 		sio_data->kind = w83627dhg_p;
2065eff7687dSJean Delvare 		sio_name = sio_name_W83627DHG_P;
2066eff7687dSJean Delvare 		break;
2067eff7687dSJean Delvare 	case SIO_W83627UHG_ID:
2068237c8d2fSGong Jun 		sio_data->kind = w83627uhg;
2069237c8d2fSGong Jun 		sio_name = sio_name_W83627UHG;
2070237c8d2fSGong Jun 		break;
2071237c8d2fSGong Jun 	case SIO_W83667HG_ID:
2072c39aedafSGuenter Roeck 		sio_data->kind = w83667hg;
2073c39aedafSGuenter Roeck 		sio_name = sio_name_W83667HG;
2074c39aedafSGuenter Roeck 		break;
2075c39aedafSGuenter Roeck 	case SIO_W83667HG_B_ID:
2076657c93b1SDavid Hubbard 		sio_data->kind = w83667hg_b;
20779f66036bSJean Delvare 		sio_name = sio_name_W83667HG_B;
2078abdc6fd1SJoe Perches 		break;
20791ea6dd38SDavid Hubbard 	default:
208008e7e278SJean Delvare 		if (val != 0xffff)
208108e7e278SJean Delvare 			pr_debug("unsupported chip ID: 0x%04x\n", val);
208208e7e278SJean Delvare 		superio_exit(sioaddr);
20831ea6dd38SDavid Hubbard 		return -ENODEV;
20841ea6dd38SDavid Hubbard 	}
20851ea6dd38SDavid Hubbard 
20861ea6dd38SDavid Hubbard 	/* We have a known chip, find the HWM I/O address */
20871a641fceSJean Delvare 	superio_select(sioaddr, W83627EHF_LD_HWM);
20882d8672c5SJean Delvare 	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
2089abdc6fd1SJoe Perches 	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
20901ea6dd38SDavid Hubbard 	*addr = val & IOREGION_ALIGNMENT;
209108e7e278SJean Delvare 	if (*addr == 0) {
209208e7e278SJean Delvare 		pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
209308e7e278SJean Delvare 		superio_exit(sioaddr);
209408e7e278SJean Delvare 		return -ENODEV;
20951ea6dd38SDavid Hubbard 	}
2096475ef855SDavid Hubbard 
2097b55f3757SGuenter Roeck 	/* Activate logical device if needed */
20981ea6dd38SDavid Hubbard 	val = superio_inb(sioaddr, SIO_REG_ENABLE);
2099475ef855SDavid Hubbard 	if (!(val & 0x01)) {
210008e7e278SJean Delvare 		pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n");
21011ea6dd38SDavid Hubbard 		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
2102abdc6fd1SJoe Perches 	}
21031ea6dd38SDavid Hubbard 
21041ea6dd38SDavid Hubbard 	superio_exit(sioaddr);
210508e7e278SJean Delvare 	pr_info("Found %s chip at %#x\n", sio_name, *addr);
210608e7e278SJean Delvare 	sio_data->sioreg = sioaddr;
210708e7e278SJean Delvare 
21088969e84dSGuenter Roeck 	return 0;
21098969e84dSGuenter Roeck }
21101ea6dd38SDavid Hubbard 
2111964c1c91SArmin Wolf /*
21128969e84dSGuenter Roeck  * when Super-I/O functions move to a separate file, the Super-I/O
21131ea6dd38SDavid Hubbard  * bus will manage the lifetime of the device and this module will only keep
21141ea6dd38SDavid Hubbard  * track of the w83627ehf driver.
211508e7e278SJean Delvare  */
211608e7e278SJean Delvare static struct platform_device *pdev;
21171ea6dd38SDavid Hubbard 
sensors_w83627ehf_init(void)21181ea6dd38SDavid Hubbard static int __init sensors_w83627ehf_init(void)
2119964c1c91SArmin Wolf {
2120964c1c91SArmin Wolf 	int err;
2121964c1c91SArmin Wolf 	unsigned short address;
2122964c1c91SArmin Wolf 	struct resource res = {
21231ea6dd38SDavid Hubbard 		.name	= DRVNAME,
21241ea6dd38SDavid Hubbard 		.flags	= IORESOURCE_IO,
21258969e84dSGuenter Roeck 	};
21268969e84dSGuenter Roeck 	struct w83627ehf_sio_data sio_data;
21271ea6dd38SDavid Hubbard 
21281ea6dd38SDavid Hubbard 	/*
21291ea6dd38SDavid Hubbard 	 * initialize sio_data->kind and sio_data->sioreg.
21308969e84dSGuenter Roeck 	 *
21318969e84dSGuenter Roeck 	 * when Super-I/O functions move to a separate file, the Super-I/O
21321ea6dd38SDavid Hubbard 	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
21331ea6dd38SDavid Hubbard 	 * w83627ehf hardware monitor, and call probe()
213408e7e278SJean Delvare 	 */
213508e7e278SJean Delvare 	if (w83627ehf_find(0x2e, &address, &sio_data) &&
21361ea6dd38SDavid Hubbard 	    w83627ehf_find(0x4e, &address, &sio_data))
21371ea6dd38SDavid Hubbard 		return -ENODEV;
2138b9acb64aSJean Delvare 
2139b9acb64aSJean Delvare 	res.start = address + IOREGION_OFFSET;
2140b9acb64aSJean Delvare 	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
21411ea6dd38SDavid Hubbard 
2142964c1c91SArmin Wolf 	err = acpi_check_resource_conflict(&res);
2143964c1c91SArmin Wolf 	if (err)
2144964c1c91SArmin Wolf 		return err;
2145964c1c91SArmin Wolf 
2146964c1c91SArmin Wolf 	pdev = platform_create_bundle(&w83627ehf_driver, w83627ehf_probe, &res, 1, &sio_data,
214708e7e278SJean Delvare 				      sizeof(struct w83627ehf_sio_data));
214808e7e278SJean Delvare 
214908e7e278SJean Delvare 	return PTR_ERR_OR_ZERO(pdev);
215008e7e278SJean Delvare }
21511ea6dd38SDavid Hubbard 
sensors_w83627ehf_exit(void)21521ea6dd38SDavid Hubbard static void __exit sensors_w83627ehf_exit(void)
215308e7e278SJean Delvare {
215408e7e278SJean Delvare 	platform_device_unregister(pdev);
21557c81c60fSJean Delvare 	platform_driver_unregister(&w83627ehf_driver);
215608e7e278SJean Delvare }
215708e7e278SJean Delvare 
215808e7e278SJean Delvare MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
215908e7e278SJean Delvare MODULE_DESCRIPTION("W83627EHF driver");
216008e7e278SJean Delvare MODULE_LICENSE("GPL");
2161 
2162 module_init(sensors_w83627ehf_init);
2163 module_exit(sensors_w83627ehf_exit);
2164