xref: /linux/drivers/hwmon/w83627ehf.c (revision bf164c58e58328c40ebc597a8ac00cc6840f9703)
108e7e278SJean Delvare /*
208e7e278SJean Delvare     w83627ehf - Driver for the hardware monitoring functionality of
308e7e278SJean Delvare 		the Winbond W83627EHF Super-I/O chip
408e7e278SJean Delvare     Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
53379ceeeSJean Delvare     Copyright (C) 2006  Yuan Mu (Winbond),
67188cc66SJean Delvare 			Rudolf Marek <r.marek@assembler.cz>
7c18beb5bSDavid Hubbard 			David Hubbard <david.c.hubbard@gmail.com>
841e9a062SDaniel J Blueman 			Daniel J Blueman <daniel.blueman@gmail.com>
9ec3e5a16SGuenter Roeck     Copyright (C) 2010  Sheng-Yuan Huang (Nuvoton) (PS00)
1008e7e278SJean Delvare 
1108e7e278SJean Delvare     Shamelessly ripped from the w83627hf driver
1208e7e278SJean Delvare     Copyright (C) 2003  Mark Studebaker
1308e7e278SJean Delvare 
1408e7e278SJean Delvare     Thanks to Leon Moonen, Steve Cliffe and Grant Coady for their help
1508e7e278SJean Delvare     in testing and debugging this driver.
1608e7e278SJean Delvare 
178dd2d2caSJean Delvare     This driver also supports the W83627EHG, which is the lead-free
188dd2d2caSJean Delvare     version of the W83627EHF.
198dd2d2caSJean Delvare 
2008e7e278SJean Delvare     This program is free software; you can redistribute it and/or modify
2108e7e278SJean Delvare     it under the terms of the GNU General Public License as published by
2208e7e278SJean Delvare     the Free Software Foundation; either version 2 of the License, or
2308e7e278SJean Delvare     (at your option) any later version.
2408e7e278SJean Delvare 
2508e7e278SJean Delvare     This program is distributed in the hope that it will be useful,
2608e7e278SJean Delvare     but WITHOUT ANY WARRANTY; without even the implied warranty of
2708e7e278SJean Delvare     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2808e7e278SJean Delvare     GNU General Public License for more details.
2908e7e278SJean Delvare 
3008e7e278SJean Delvare     You should have received a copy of the GNU General Public License
3108e7e278SJean Delvare     along with this program; if not, write to the Free Software
3208e7e278SJean Delvare     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
3308e7e278SJean Delvare 
3408e7e278SJean Delvare 
3508e7e278SJean Delvare     Supports the following chips:
3608e7e278SJean Delvare 
37657c93b1SDavid Hubbard     Chip        #vin    #fan    #pwm    #temp  chip IDs       man ID
38657c93b1SDavid Hubbard     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
39657c93b1SDavid Hubbard 					       0x8860 0xa1
40657c93b1SDavid Hubbard     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
41c1e48dceSJean Delvare     w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
42237c8d2fSGong Jun     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
43d36cf32cSGuenter Roeck     w83667hg-b   9      5       3       4      0xb350 0xc1    0x5ca3
44ec3e5a16SGuenter Roeck     nct6775f     9      4       3       9      0xb470 0xc1    0x5ca3
45ec3e5a16SGuenter Roeck     nct6776f     9      5       3       9      0xC330 0xc1    0x5ca3
4608e7e278SJean Delvare */
4708e7e278SJean Delvare 
48abdc6fd1SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
49abdc6fd1SJoe Perches 
5008e7e278SJean Delvare #include <linux/module.h>
5108e7e278SJean Delvare #include <linux/init.h>
5208e7e278SJean Delvare #include <linux/slab.h>
531ea6dd38SDavid Hubbard #include <linux/jiffies.h>
541ea6dd38SDavid Hubbard #include <linux/platform_device.h>
55943b0830SMark M. Hoffman #include <linux/hwmon.h>
56412fec82SYuan Mu #include <linux/hwmon-sysfs.h>
57fc18d6c0SJean Delvare #include <linux/hwmon-vid.h>
58943b0830SMark M. Hoffman #include <linux/err.h>
599a61bf63SIngo Molnar #include <linux/mutex.h>
60b9acb64aSJean Delvare #include <linux/acpi.h>
616055fae8SH Hartley Sweeten #include <linux/io.h>
6208e7e278SJean Delvare #include "lm75.h"
6308e7e278SJean Delvare 
64ec3e5a16SGuenter Roeck enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg, w83667hg_b, nct6775,
65ec3e5a16SGuenter Roeck 	nct6776 };
661ea6dd38SDavid Hubbard 
671ea6dd38SDavid Hubbard /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
68e7e1ca6eSGuenter Roeck static const char * const w83627ehf_device_names[] = {
691ea6dd38SDavid Hubbard 	"w83627ehf",
701ea6dd38SDavid Hubbard 	"w83627dhg",
71c1e48dceSJean Delvare 	"w83627dhg",
72237c8d2fSGong Jun 	"w83667hg",
73c39aedafSGuenter Roeck 	"w83667hg",
74ec3e5a16SGuenter Roeck 	"nct6775",
75ec3e5a16SGuenter Roeck 	"nct6776",
761ea6dd38SDavid Hubbard };
771ea6dd38SDavid Hubbard 
7867b671bcSJean Delvare static unsigned short force_id;
7967b671bcSJean Delvare module_param(force_id, ushort, 0);
8067b671bcSJean Delvare MODULE_PARM_DESC(force_id, "Override the detected device ID");
8167b671bcSJean Delvare 
82d42e869aSIan Dobson static unsigned short fan_debounce;
83d42e869aSIan Dobson module_param(fan_debounce, ushort, 0);
84d42e869aSIan Dobson MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
85d42e869aSIan Dobson 
861ea6dd38SDavid Hubbard #define DRVNAME "w83627ehf"
8708e7e278SJean Delvare 
8808e7e278SJean Delvare /*
8908e7e278SJean Delvare  * Super-I/O constants and functions
9008e7e278SJean Delvare  */
9108e7e278SJean Delvare 
9208e7e278SJean Delvare #define W83627EHF_LD_HWM	0x0b
93237c8d2fSGong Jun #define W83667HG_LD_VID		0x0d
9408e7e278SJean Delvare 
9508e7e278SJean Delvare #define SIO_REG_LDSEL		0x07	/* Logical device select */
9608e7e278SJean Delvare #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
97fc18d6c0SJean Delvare #define SIO_REG_EN_VRM10	0x2C	/* GPIO3, GPIO4 selection */
9808e7e278SJean Delvare #define SIO_REG_ENABLE		0x30	/* Logical device enable */
9908e7e278SJean Delvare #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
100fc18d6c0SJean Delvare #define SIO_REG_VID_CTRL	0xF0	/* VID control */
101fc18d6c0SJean Delvare #define SIO_REG_VID_DATA	0xF1	/* VID data */
10208e7e278SJean Delvare 
103657c93b1SDavid Hubbard #define SIO_W83627EHF_ID	0x8850
104657c93b1SDavid Hubbard #define SIO_W83627EHG_ID	0x8860
105657c93b1SDavid Hubbard #define SIO_W83627DHG_ID	0xa020
106c1e48dceSJean Delvare #define SIO_W83627DHG_P_ID	0xb070
107237c8d2fSGong Jun #define SIO_W83667HG_ID		0xa510
108c39aedafSGuenter Roeck #define SIO_W83667HG_B_ID	0xb350
109ec3e5a16SGuenter Roeck #define SIO_NCT6775_ID		0xb470
110ec3e5a16SGuenter Roeck #define SIO_NCT6776_ID		0xc330
111657c93b1SDavid Hubbard #define SIO_ID_MASK		0xFFF0
11208e7e278SJean Delvare 
11308e7e278SJean Delvare static inline void
1141ea6dd38SDavid Hubbard superio_outb(int ioreg, int reg, int val)
11508e7e278SJean Delvare {
1161ea6dd38SDavid Hubbard 	outb(reg, ioreg);
1171ea6dd38SDavid Hubbard 	outb(val, ioreg + 1);
11808e7e278SJean Delvare }
11908e7e278SJean Delvare 
12008e7e278SJean Delvare static inline int
1211ea6dd38SDavid Hubbard superio_inb(int ioreg, int reg)
12208e7e278SJean Delvare {
1231ea6dd38SDavid Hubbard 	outb(reg, ioreg);
1241ea6dd38SDavid Hubbard 	return inb(ioreg + 1);
12508e7e278SJean Delvare }
12608e7e278SJean Delvare 
12708e7e278SJean Delvare static inline void
1281ea6dd38SDavid Hubbard superio_select(int ioreg, int ld)
12908e7e278SJean Delvare {
1301ea6dd38SDavid Hubbard 	outb(SIO_REG_LDSEL, ioreg);
1311ea6dd38SDavid Hubbard 	outb(ld, ioreg + 1);
13208e7e278SJean Delvare }
13308e7e278SJean Delvare 
13408e7e278SJean Delvare static inline void
1351ea6dd38SDavid Hubbard superio_enter(int ioreg)
13608e7e278SJean Delvare {
1371ea6dd38SDavid Hubbard 	outb(0x87, ioreg);
1381ea6dd38SDavid Hubbard 	outb(0x87, ioreg);
13908e7e278SJean Delvare }
14008e7e278SJean Delvare 
14108e7e278SJean Delvare static inline void
1421ea6dd38SDavid Hubbard superio_exit(int ioreg)
14308e7e278SJean Delvare {
144022b75a3SJonas Jonsson 	outb(0xaa, ioreg);
1451ea6dd38SDavid Hubbard 	outb(0x02, ioreg);
1461ea6dd38SDavid Hubbard 	outb(0x02, ioreg + 1);
14708e7e278SJean Delvare }
14808e7e278SJean Delvare 
14908e7e278SJean Delvare /*
15008e7e278SJean Delvare  * ISA constants
15108e7e278SJean Delvare  */
15208e7e278SJean Delvare 
153e7e1ca6eSGuenter Roeck #define IOREGION_ALIGNMENT	(~7)
1541a641fceSJean Delvare #define IOREGION_OFFSET		5
1551a641fceSJean Delvare #define IOREGION_LENGTH		2
1561ea6dd38SDavid Hubbard #define ADDR_REG_OFFSET		0
1571ea6dd38SDavid Hubbard #define DATA_REG_OFFSET		1
15808e7e278SJean Delvare 
15908e7e278SJean Delvare #define W83627EHF_REG_BANK		0x4E
16008e7e278SJean Delvare #define W83627EHF_REG_CONFIG		0x40
161657c93b1SDavid Hubbard 
162657c93b1SDavid Hubbard /* Not currently used:
163657c93b1SDavid Hubbard  * REG_MAN_ID has the value 0x5ca3 for all supported chips.
164657c93b1SDavid Hubbard  * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model.
165657c93b1SDavid Hubbard  * REG_MAN_ID is at port 0x4f
166657c93b1SDavid Hubbard  * REG_CHIP_ID is at port 0x58 */
16708e7e278SJean Delvare 
16808e7e278SJean Delvare static const u16 W83627EHF_REG_FAN[] = { 0x28, 0x29, 0x2a, 0x3f, 0x553 };
16908e7e278SJean Delvare static const u16 W83627EHF_REG_FAN_MIN[] = { 0x3b, 0x3c, 0x3d, 0x3e, 0x55c };
17008e7e278SJean Delvare 
171cf0676feSRudolf Marek /* The W83627EHF registers for nr=7,8,9 are in bank 5 */
172cf0676feSRudolf Marek #define W83627EHF_REG_IN_MAX(nr)	((nr < 7) ? (0x2b + (nr) * 2) : \
173cf0676feSRudolf Marek 					 (0x554 + (((nr) - 7) * 2)))
174cf0676feSRudolf Marek #define W83627EHF_REG_IN_MIN(nr)	((nr < 7) ? (0x2c + (nr) * 2) : \
175cf0676feSRudolf Marek 					 (0x555 + (((nr) - 7) * 2)))
176cf0676feSRudolf Marek #define W83627EHF_REG_IN(nr)		((nr < 7) ? (0x20 + (nr)) : \
177cf0676feSRudolf Marek 					 (0x550 + (nr) - 7))
178cf0676feSRudolf Marek 
179d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP[] = { 0x27, 0x150, 0x250, 0x7e };
180d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_HYST[] = { 0x3a, 0x153, 0x253, 0 };
181d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_OVER[] = { 0x39, 0x155, 0x255, 0 };
182d36cf32cSGuenter Roeck static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0, 0x152, 0x252, 0 };
18308e7e278SJean Delvare 
18408e7e278SJean Delvare /* Fan clock dividers are spread over the following five registers */
18508e7e278SJean Delvare #define W83627EHF_REG_FANDIV1		0x47
18608e7e278SJean Delvare #define W83627EHF_REG_FANDIV2		0x4B
18708e7e278SJean Delvare #define W83627EHF_REG_VBAT		0x5D
18808e7e278SJean Delvare #define W83627EHF_REG_DIODE		0x59
18908e7e278SJean Delvare #define W83627EHF_REG_SMI_OVT		0x4C
19008e7e278SJean Delvare 
191ec3e5a16SGuenter Roeck /* NCT6775F has its own fan divider registers */
192ec3e5a16SGuenter Roeck #define NCT6775_REG_FANDIV1		0x506
193ec3e5a16SGuenter Roeck #define NCT6775_REG_FANDIV2		0x507
194d42e869aSIan Dobson #define NCT6775_REG_FAN_DEBOUNCE	0xf0
195ec3e5a16SGuenter Roeck 
196a4589dbbSJean Delvare #define W83627EHF_REG_ALARM1		0x459
197a4589dbbSJean Delvare #define W83627EHF_REG_ALARM2		0x45A
198a4589dbbSJean Delvare #define W83627EHF_REG_ALARM3		0x45B
199a4589dbbSJean Delvare 
20008c79950SRudolf Marek /* SmartFan registers */
20141e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPUP_TIME 0x0f
20241e9a062SDaniel J Blueman #define W83627EHF_REG_FAN_STEPDOWN_TIME 0x0e
20341e9a062SDaniel J Blueman 
20408c79950SRudolf Marek /* DC or PWM output fan configuration */
20508c79950SRudolf Marek static const u8 W83627EHF_REG_PWM_ENABLE[] = {
20608c79950SRudolf Marek 	0x04,			/* SYS FAN0 output mode and PWM mode */
20708c79950SRudolf Marek 	0x04,			/* CPU FAN0 output mode and PWM mode */
20808c79950SRudolf Marek 	0x12,			/* AUX FAN mode */
20941e9a062SDaniel J Blueman 	0x62,			/* CPU FAN1 mode */
21008c79950SRudolf Marek };
21108c79950SRudolf Marek 
21208c79950SRudolf Marek static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
21308c79950SRudolf Marek static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
21408c79950SRudolf Marek 
21508c79950SRudolf Marek /* FAN Duty Cycle, be used to control */
216279af1a9SGuenter Roeck static const u16 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
217279af1a9SGuenter Roeck static const u16 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
21808c79950SRudolf Marek static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
21908c79950SRudolf Marek 
22008c79950SRudolf Marek /* Advanced Fan control, some values are common for all fans */
221279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_START_OUTPUT[] = { 0x0a, 0x0b, 0x16, 0x65 };
222279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
223279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0c, 0x0d, 0x17, 0x66 };
224c39aedafSGuenter Roeck 
225279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_COMMON[]
226c39aedafSGuenter Roeck 						= { 0xff, 0x67, 0xff, 0x69 };
227279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_COMMON[]
228c39aedafSGuenter Roeck 						= { 0xff, 0x68, 0xff, 0x6a };
229c39aedafSGuenter Roeck 
230279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B[] = { 0x67, 0x69, 0x6b };
231279af1a9SGuenter Roeck static const u16 W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B[]
232279af1a9SGuenter Roeck 						= { 0x68, 0x6a, 0x6c };
23308c79950SRudolf Marek 
234ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TARGET[] = { 0x101, 0x201, 0x301 };
235ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_MODE[] = { 0x102, 0x202, 0x302 };
236ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STOP_OUTPUT[] = { 0x105, 0x205, 0x305 };
237ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_START_OUTPUT[] = { 0x106, 0x206, 0x306 };
238ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STOP_TIME[] = { 0x107, 0x207, 0x307 };
239ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_PWM[] = { 0x109, 0x209, 0x309 };
240ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_MAX_OUTPUT[] = { 0x10a, 0x20a, 0x30a };
241ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_FAN_STEP_OUTPUT[] = { 0x10b, 0x20b, 0x30b };
24226bc440eSGuenter Roeck static const u16 NCT6775_REG_FAN[] = { 0x630, 0x632, 0x634, 0x636, 0x638 };
243ec3e5a16SGuenter Roeck static const u16 NCT6776_REG_FAN_MIN[] = { 0x63a, 0x63c, 0x63e, 0x640, 0x642};
244ec3e5a16SGuenter Roeck 
245ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP[]
246ec3e5a16SGuenter Roeck 	= { 0x27, 0x150, 0x250, 0x73, 0x75, 0x77, 0x62b, 0x62c, 0x62d };
247ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_CONFIG[]
248ec3e5a16SGuenter Roeck 	= { 0, 0x152, 0x252, 0, 0, 0, 0x628, 0x629, 0x62A };
249ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_HYST[]
250ec3e5a16SGuenter Roeck 	= { 0x3a, 0x153, 0x253, 0, 0, 0, 0x673, 0x678, 0x67D };
251ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_OVER[]
252ec3e5a16SGuenter Roeck 	= { 0x39, 0x155, 0x255, 0, 0, 0, 0x672, 0x677, 0x67C };
253ec3e5a16SGuenter Roeck static const u16 NCT6775_REG_TEMP_SOURCE[]
254ec3e5a16SGuenter Roeck 	= { 0x621, 0x622, 0x623, 0x100, 0x200, 0x300, 0x624, 0x625, 0x626 };
255ec3e5a16SGuenter Roeck 
256d36cf32cSGuenter Roeck static const char *const w83667hg_b_temp_label[] = {
257d36cf32cSGuenter Roeck 	"SYSTIN",
258d36cf32cSGuenter Roeck 	"CPUTIN",
259d36cf32cSGuenter Roeck 	"AUXTIN",
260d36cf32cSGuenter Roeck 	"AMDTSI",
261d36cf32cSGuenter Roeck 	"PECI Agent 1",
262d36cf32cSGuenter Roeck 	"PECI Agent 2",
263d36cf32cSGuenter Roeck 	"PECI Agent 3",
264d36cf32cSGuenter Roeck 	"PECI Agent 4"
265d36cf32cSGuenter Roeck };
266d36cf32cSGuenter Roeck 
267ec3e5a16SGuenter Roeck static const char *const nct6775_temp_label[] = {
268ec3e5a16SGuenter Roeck 	"",
269ec3e5a16SGuenter Roeck 	"SYSTIN",
270ec3e5a16SGuenter Roeck 	"CPUTIN",
271ec3e5a16SGuenter Roeck 	"AUXTIN",
272ec3e5a16SGuenter Roeck 	"AMD SB-TSI",
273ec3e5a16SGuenter Roeck 	"PECI Agent 0",
274ec3e5a16SGuenter Roeck 	"PECI Agent 1",
275ec3e5a16SGuenter Roeck 	"PECI Agent 2",
276ec3e5a16SGuenter Roeck 	"PECI Agent 3",
277ec3e5a16SGuenter Roeck 	"PECI Agent 4",
278ec3e5a16SGuenter Roeck 	"PECI Agent 5",
279ec3e5a16SGuenter Roeck 	"PECI Agent 6",
280ec3e5a16SGuenter Roeck 	"PECI Agent 7",
281ec3e5a16SGuenter Roeck 	"PCH_CHIP_CPU_MAX_TEMP",
282ec3e5a16SGuenter Roeck 	"PCH_CHIP_TEMP",
283ec3e5a16SGuenter Roeck 	"PCH_CPU_TEMP",
284ec3e5a16SGuenter Roeck 	"PCH_MCH_TEMP",
285ec3e5a16SGuenter Roeck 	"PCH_DIM0_TEMP",
286ec3e5a16SGuenter Roeck 	"PCH_DIM1_TEMP",
287ec3e5a16SGuenter Roeck 	"PCH_DIM2_TEMP",
288ec3e5a16SGuenter Roeck 	"PCH_DIM3_TEMP"
289ec3e5a16SGuenter Roeck };
290ec3e5a16SGuenter Roeck 
291ec3e5a16SGuenter Roeck static const char *const nct6776_temp_label[] = {
292ec3e5a16SGuenter Roeck 	"",
293ec3e5a16SGuenter Roeck 	"SYSTIN",
294ec3e5a16SGuenter Roeck 	"CPUTIN",
295ec3e5a16SGuenter Roeck 	"AUXTIN",
296ec3e5a16SGuenter Roeck 	"SMBUSMASTER 0",
297ec3e5a16SGuenter Roeck 	"SMBUSMASTER 1",
298ec3e5a16SGuenter Roeck 	"SMBUSMASTER 2",
299ec3e5a16SGuenter Roeck 	"SMBUSMASTER 3",
300ec3e5a16SGuenter Roeck 	"SMBUSMASTER 4",
301ec3e5a16SGuenter Roeck 	"SMBUSMASTER 5",
302ec3e5a16SGuenter Roeck 	"SMBUSMASTER 6",
303ec3e5a16SGuenter Roeck 	"SMBUSMASTER 7",
304ec3e5a16SGuenter Roeck 	"PECI Agent 0",
305ec3e5a16SGuenter Roeck 	"PECI Agent 1",
306ec3e5a16SGuenter Roeck 	"PCH_CHIP_CPU_MAX_TEMP",
307ec3e5a16SGuenter Roeck 	"PCH_CHIP_TEMP",
308ec3e5a16SGuenter Roeck 	"PCH_CPU_TEMP",
309ec3e5a16SGuenter Roeck 	"PCH_MCH_TEMP",
310ec3e5a16SGuenter Roeck 	"PCH_DIM0_TEMP",
311ec3e5a16SGuenter Roeck 	"PCH_DIM1_TEMP",
312ec3e5a16SGuenter Roeck 	"PCH_DIM2_TEMP",
313ec3e5a16SGuenter Roeck 	"PCH_DIM3_TEMP",
314ec3e5a16SGuenter Roeck 	"BYTE_TEMP"
315ec3e5a16SGuenter Roeck };
316ec3e5a16SGuenter Roeck 
317ec3e5a16SGuenter Roeck #define NUM_REG_TEMP	ARRAY_SIZE(NCT6775_REG_TEMP)
318d36cf32cSGuenter Roeck 
319bce26c58SGuenter Roeck static inline int is_word_sized(u16 reg)
320bce26c58SGuenter Roeck {
321ec3e5a16SGuenter Roeck 	return ((((reg & 0xff00) == 0x100
322bce26c58SGuenter Roeck 	      || (reg & 0xff00) == 0x200)
323bce26c58SGuenter Roeck 	     && ((reg & 0x00ff) == 0x50
324bce26c58SGuenter Roeck 	      || (reg & 0x00ff) == 0x53
325ec3e5a16SGuenter Roeck 	      || (reg & 0x00ff) == 0x55))
326ec3e5a16SGuenter Roeck 	     || (reg & 0xfff0) == 0x630
327ec3e5a16SGuenter Roeck 	     || reg == 0x640 || reg == 0x642
328ec3e5a16SGuenter Roeck 	     || ((reg & 0xfff0) == 0x650
329ec3e5a16SGuenter Roeck 		 && (reg & 0x000f) >= 0x06)
330ec3e5a16SGuenter Roeck 	     || reg == 0x73 || reg == 0x75 || reg == 0x77
331ec3e5a16SGuenter Roeck 		);
332bce26c58SGuenter Roeck }
333bce26c58SGuenter Roeck 
33408e7e278SJean Delvare /*
33508e7e278SJean Delvare  * Conversions
33608e7e278SJean Delvare  */
33708e7e278SJean Delvare 
33808c79950SRudolf Marek /* 1 is PWM mode, output in ms */
33908c79950SRudolf Marek static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
34008c79950SRudolf Marek {
34108c79950SRudolf Marek 	return mode ? 100 * reg : 400 * reg;
34208c79950SRudolf Marek }
34308c79950SRudolf Marek 
34408c79950SRudolf Marek static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
34508c79950SRudolf Marek {
34608c79950SRudolf Marek 	return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
34708c79950SRudolf Marek 						(msec + 200) / 400), 1, 255);
34808c79950SRudolf Marek }
34908c79950SRudolf Marek 
35026bc440eSGuenter Roeck static unsigned int fan_from_reg8(u16 reg, unsigned int divreg)
35108e7e278SJean Delvare {
35226bc440eSGuenter Roeck 	if (reg == 0 || reg == 255)
35308e7e278SJean Delvare 		return 0;
35426bc440eSGuenter Roeck 	return 1350000U / (reg << divreg);
355ec3e5a16SGuenter Roeck }
35626bc440eSGuenter Roeck 
35726bc440eSGuenter Roeck static unsigned int fan_from_reg13(u16 reg, unsigned int divreg)
35826bc440eSGuenter Roeck {
35926bc440eSGuenter Roeck 	if ((reg & 0xff1f) == 0xff1f)
36026bc440eSGuenter Roeck 		return 0;
36126bc440eSGuenter Roeck 
36226bc440eSGuenter Roeck 	reg = (reg & 0x1f) | ((reg & 0xff00) >> 3);
36326bc440eSGuenter Roeck 
36426bc440eSGuenter Roeck 	if (reg == 0)
36526bc440eSGuenter Roeck 		return 0;
36626bc440eSGuenter Roeck 
36726bc440eSGuenter Roeck 	return 1350000U / reg;
36826bc440eSGuenter Roeck }
36926bc440eSGuenter Roeck 
37026bc440eSGuenter Roeck static unsigned int fan_from_reg16(u16 reg, unsigned int divreg)
37126bc440eSGuenter Roeck {
37226bc440eSGuenter Roeck 	if (reg == 0 || reg == 0xffff)
37326bc440eSGuenter Roeck 		return 0;
37426bc440eSGuenter Roeck 
37526bc440eSGuenter Roeck 	/*
37626bc440eSGuenter Roeck 	 * Even though the registers are 16 bit wide, the fan divisor
37726bc440eSGuenter Roeck 	 * still applies.
37826bc440eSGuenter Roeck 	 */
37926bc440eSGuenter Roeck 	return 1350000U / (reg << divreg);
38008e7e278SJean Delvare }
38108e7e278SJean Delvare 
38208e7e278SJean Delvare static inline unsigned int
38308e7e278SJean Delvare div_from_reg(u8 reg)
38408e7e278SJean Delvare {
38508e7e278SJean Delvare 	return 1 << reg;
38608e7e278SJean Delvare }
38708e7e278SJean Delvare 
38808e7e278SJean Delvare static inline int
389bce26c58SGuenter Roeck temp_from_reg(u16 reg, s16 regval)
39008e7e278SJean Delvare {
391bce26c58SGuenter Roeck 	if (is_word_sized(reg))
392bce26c58SGuenter Roeck 		return LM75_TEMP_FROM_REG(regval);
393bce26c58SGuenter Roeck 	return regval * 1000;
39408e7e278SJean Delvare }
39508e7e278SJean Delvare 
396ec3e5a16SGuenter Roeck static inline u16
397bce26c58SGuenter Roeck temp_to_reg(u16 reg, long temp)
39808e7e278SJean Delvare {
399bce26c58SGuenter Roeck 	if (is_word_sized(reg))
400bce26c58SGuenter Roeck 		return LM75_TEMP_TO_REG(temp);
401bce26c58SGuenter Roeck 	return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, -127000, 128000), 1000);
40208e7e278SJean Delvare }
40308e7e278SJean Delvare 
404cf0676feSRudolf Marek /* Some of analog inputs have internal scaling (2x), 8mV is ADC LSB */
405cf0676feSRudolf Marek 
406cf0676feSRudolf Marek static u8 scale_in[10] = { 8, 8, 16, 16, 8, 8, 8, 16, 16, 8 };
407cf0676feSRudolf Marek 
408cf0676feSRudolf Marek static inline long in_from_reg(u8 reg, u8 nr)
409cf0676feSRudolf Marek {
410cf0676feSRudolf Marek 	return reg * scale_in[nr];
411cf0676feSRudolf Marek }
412cf0676feSRudolf Marek 
413cf0676feSRudolf Marek static inline u8 in_to_reg(u32 val, u8 nr)
414cf0676feSRudolf Marek {
415e7e1ca6eSGuenter Roeck 	return SENSORS_LIMIT(((val + (scale_in[nr] / 2)) / scale_in[nr]), 0,
416e7e1ca6eSGuenter Roeck 			     255);
417cf0676feSRudolf Marek }
418cf0676feSRudolf Marek 
41908e7e278SJean Delvare /*
42008e7e278SJean Delvare  * Data structures and manipulation thereof
42108e7e278SJean Delvare  */
42208e7e278SJean Delvare 
42308e7e278SJean Delvare struct w83627ehf_data {
4241ea6dd38SDavid Hubbard 	int addr;	/* IO base of hw monitor block */
4251ea6dd38SDavid Hubbard 	const char *name;
4261ea6dd38SDavid Hubbard 
4271beeffe4STony Jones 	struct device *hwmon_dev;
4289a61bf63SIngo Molnar 	struct mutex lock;
42908e7e278SJean Delvare 
430ec3e5a16SGuenter Roeck 	u16 reg_temp[NUM_REG_TEMP];
431ec3e5a16SGuenter Roeck 	u16 reg_temp_over[NUM_REG_TEMP];
432ec3e5a16SGuenter Roeck 	u16 reg_temp_hyst[NUM_REG_TEMP];
433ec3e5a16SGuenter Roeck 	u16 reg_temp_config[NUM_REG_TEMP];
434d36cf32cSGuenter Roeck 	u8 temp_src[NUM_REG_TEMP];
435d36cf32cSGuenter Roeck 	const char * const *temp_label;
436d36cf32cSGuenter Roeck 
437279af1a9SGuenter Roeck 	const u16 *REG_PWM;
438279af1a9SGuenter Roeck 	const u16 *REG_TARGET;
439279af1a9SGuenter Roeck 	const u16 *REG_FAN;
440279af1a9SGuenter Roeck 	const u16 *REG_FAN_MIN;
441279af1a9SGuenter Roeck 	const u16 *REG_FAN_START_OUTPUT;
442279af1a9SGuenter Roeck 	const u16 *REG_FAN_STOP_OUTPUT;
443279af1a9SGuenter Roeck 	const u16 *REG_FAN_STOP_TIME;
444279af1a9SGuenter Roeck 	const u16 *REG_FAN_MAX_OUTPUT;
445279af1a9SGuenter Roeck 	const u16 *REG_FAN_STEP_OUTPUT;
446da2e0255SGuenter Roeck 
44726bc440eSGuenter Roeck 	unsigned int (*fan_from_reg)(u16 reg, unsigned int divreg);
44826bc440eSGuenter Roeck 	unsigned int (*fan_from_reg_min)(u16 reg, unsigned int divreg);
44926bc440eSGuenter Roeck 
4509a61bf63SIngo Molnar 	struct mutex update_lock;
45108e7e278SJean Delvare 	char valid;		/* !=0 if following fields are valid */
45208e7e278SJean Delvare 	unsigned long last_updated;	/* In jiffies */
45308e7e278SJean Delvare 
45408e7e278SJean Delvare 	/* Register values */
45583cc8985SGuenter Roeck 	u8 bank;		/* current register bank */
4561ea6dd38SDavid Hubbard 	u8 in_num;		/* number of in inputs we have */
457cf0676feSRudolf Marek 	u8 in[10];		/* Register value */
458cf0676feSRudolf Marek 	u8 in_max[10];		/* Register value */
459cf0676feSRudolf Marek 	u8 in_min[10];		/* Register value */
4603382a918SGuenter Roeck 	unsigned int rpm[5];
461ec3e5a16SGuenter Roeck 	u16 fan_min[5];
46208e7e278SJean Delvare 	u8 fan_div[5];
46308e7e278SJean Delvare 	u8 has_fan;		/* some fan inputs can be disabled */
464ec3e5a16SGuenter Roeck 	u8 has_fan_min;		/* some fans don't have min register */
46526bc440eSGuenter Roeck 	bool has_fan_div;
466da667365SJean Delvare 	u8 temp_type[3];
467ec3e5a16SGuenter Roeck 	s16 temp[9];
468ec3e5a16SGuenter Roeck 	s16 temp_max[9];
469ec3e5a16SGuenter Roeck 	s16 temp_max_hyst[9];
470a4589dbbSJean Delvare 	u32 alarms;
47108c79950SRudolf Marek 
47208c79950SRudolf Marek 	u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
47308c79950SRudolf Marek 	u8 pwm_enable[4]; /* 1->manual
47441e9a062SDaniel J Blueman 			     2->thermal cruise mode (also called SmartFan I)
47541e9a062SDaniel J Blueman 			     3->fan speed cruise mode
476e7e1ca6eSGuenter Roeck 			     4->variable thermal cruise (also called
477b84bb518SGuenter Roeck 				SmartFan III)
478b84bb518SGuenter Roeck 			     5->enhanced variable thermal cruise (also called
479b84bb518SGuenter Roeck 				SmartFan IV) */
480b84bb518SGuenter Roeck 	u8 pwm_enable_orig[4];	/* original value of pwm_enable */
481237c8d2fSGong Jun 	u8 pwm_num;		/* number of pwm */
48208c79950SRudolf Marek 	u8 pwm[4];
48308c79950SRudolf Marek 	u8 target_temp[4];
48408c79950SRudolf Marek 	u8 tolerance[4];
48508c79950SRudolf Marek 
48641e9a062SDaniel J Blueman 	u8 fan_start_output[4]; /* minimum fan speed when spinning up */
48741e9a062SDaniel J Blueman 	u8 fan_stop_output[4]; /* minimum fan speed when spinning down */
48841e9a062SDaniel J Blueman 	u8 fan_stop_time[4]; /* time at minimum before disabling fan */
48941e9a062SDaniel J Blueman 	u8 fan_max_output[4]; /* maximum fan speed */
49041e9a062SDaniel J Blueman 	u8 fan_step_output[4]; /* rate of change output value */
491fc18d6c0SJean Delvare 
492fc18d6c0SJean Delvare 	u8 vid;
493fc18d6c0SJean Delvare 	u8 vrm;
494a157d06dSGong Jun 
495ec3e5a16SGuenter Roeck 	u16 have_temp;
496a157d06dSGong Jun 	u8 in6_skip;
49708e7e278SJean Delvare };
49808e7e278SJean Delvare 
4991ea6dd38SDavid Hubbard struct w83627ehf_sio_data {
5001ea6dd38SDavid Hubbard 	int sioreg;
5011ea6dd38SDavid Hubbard 	enum kinds kind;
5021ea6dd38SDavid Hubbard };
5031ea6dd38SDavid Hubbard 
50483cc8985SGuenter Roeck /*
50583cc8985SGuenter Roeck  * On older chips, only registers 0x50-0x5f are banked.
50683cc8985SGuenter Roeck  * On more recent chips, all registers are banked.
50783cc8985SGuenter Roeck  * Assume that is the case and set the bank number for each access.
50883cc8985SGuenter Roeck  * Cache the bank number so it only needs to be set if it changes.
50983cc8985SGuenter Roeck  */
5101ea6dd38SDavid Hubbard static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
51108e7e278SJean Delvare {
51283cc8985SGuenter Roeck 	u8 bank = reg >> 8;
51383cc8985SGuenter Roeck 	if (data->bank != bank) {
5141ea6dd38SDavid Hubbard 		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
51583cc8985SGuenter Roeck 		outb_p(bank, data->addr + DATA_REG_OFFSET);
51683cc8985SGuenter Roeck 		data->bank = bank;
51708e7e278SJean Delvare 	}
51808e7e278SJean Delvare }
51908e7e278SJean Delvare 
5201ea6dd38SDavid Hubbard static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
52108e7e278SJean Delvare {
52208e7e278SJean Delvare 	int res, word_sized = is_word_sized(reg);
52308e7e278SJean Delvare 
5249a61bf63SIngo Molnar 	mutex_lock(&data->lock);
52508e7e278SJean Delvare 
5261ea6dd38SDavid Hubbard 	w83627ehf_set_bank(data, reg);
5271ea6dd38SDavid Hubbard 	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
5281ea6dd38SDavid Hubbard 	res = inb_p(data->addr + DATA_REG_OFFSET);
52908e7e278SJean Delvare 	if (word_sized) {
53008e7e278SJean Delvare 		outb_p((reg & 0xff) + 1,
5311ea6dd38SDavid Hubbard 		       data->addr + ADDR_REG_OFFSET);
5321ea6dd38SDavid Hubbard 		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
53308e7e278SJean Delvare 	}
53408e7e278SJean Delvare 
5359a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
53608e7e278SJean Delvare 	return res;
53708e7e278SJean Delvare }
53808e7e278SJean Delvare 
539e7e1ca6eSGuenter Roeck static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg,
540e7e1ca6eSGuenter Roeck 				 u16 value)
54108e7e278SJean Delvare {
54208e7e278SJean Delvare 	int word_sized = is_word_sized(reg);
54308e7e278SJean Delvare 
5449a61bf63SIngo Molnar 	mutex_lock(&data->lock);
54508e7e278SJean Delvare 
5461ea6dd38SDavid Hubbard 	w83627ehf_set_bank(data, reg);
5471ea6dd38SDavid Hubbard 	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
54808e7e278SJean Delvare 	if (word_sized) {
5491ea6dd38SDavid Hubbard 		outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
55008e7e278SJean Delvare 		outb_p((reg & 0xff) + 1,
5511ea6dd38SDavid Hubbard 		       data->addr + ADDR_REG_OFFSET);
55208e7e278SJean Delvare 	}
5531ea6dd38SDavid Hubbard 	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
55408e7e278SJean Delvare 
5559a61bf63SIngo Molnar 	mutex_unlock(&data->lock);
55608e7e278SJean Delvare 	return 0;
55708e7e278SJean Delvare }
55808e7e278SJean Delvare 
55908e7e278SJean Delvare /* This function assumes that the caller holds data->update_lock */
560ec3e5a16SGuenter Roeck static void nct6775_write_fan_div(struct w83627ehf_data *data, int nr)
561ec3e5a16SGuenter Roeck {
562ec3e5a16SGuenter Roeck 	u8 reg;
563ec3e5a16SGuenter Roeck 
564ec3e5a16SGuenter Roeck 	switch (nr) {
565ec3e5a16SGuenter Roeck 	case 0:
566ec3e5a16SGuenter Roeck 		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x70)
567ec3e5a16SGuenter Roeck 		    | (data->fan_div[0] & 0x7);
568ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
569ec3e5a16SGuenter Roeck 		break;
570ec3e5a16SGuenter Roeck 	case 1:
571ec3e5a16SGuenter Roeck 		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV1) & 0x7)
572ec3e5a16SGuenter Roeck 		    | ((data->fan_div[1] << 4) & 0x70);
573ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data, NCT6775_REG_FANDIV1, reg);
574ec3e5a16SGuenter Roeck 	case 2:
575ec3e5a16SGuenter Roeck 		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x70)
576ec3e5a16SGuenter Roeck 		    | (data->fan_div[2] & 0x7);
577ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
578ec3e5a16SGuenter Roeck 		break;
579ec3e5a16SGuenter Roeck 	case 3:
580ec3e5a16SGuenter Roeck 		reg = (w83627ehf_read_value(data, NCT6775_REG_FANDIV2) & 0x7)
581ec3e5a16SGuenter Roeck 		    | ((data->fan_div[3] << 4) & 0x70);
582ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data, NCT6775_REG_FANDIV2, reg);
583ec3e5a16SGuenter Roeck 		break;
584ec3e5a16SGuenter Roeck 	}
585ec3e5a16SGuenter Roeck }
586ec3e5a16SGuenter Roeck 
587ec3e5a16SGuenter Roeck /* This function assumes that the caller holds data->update_lock */
5881ea6dd38SDavid Hubbard static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
58908e7e278SJean Delvare {
59008e7e278SJean Delvare 	u8 reg;
59108e7e278SJean Delvare 
59208e7e278SJean Delvare 	switch (nr) {
59308e7e278SJean Delvare 	case 0:
5941ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
59508e7e278SJean Delvare 		    | ((data->fan_div[0] & 0x03) << 4);
59614992c7eSRudolf Marek 		/* fan5 input control bit is write only, compute the value */
59714992c7eSRudolf Marek 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
5981ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
5991ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
60008e7e278SJean Delvare 		    | ((data->fan_div[0] & 0x04) << 3);
6011ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
60208e7e278SJean Delvare 		break;
60308e7e278SJean Delvare 	case 1:
6041ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
60508e7e278SJean Delvare 		    | ((data->fan_div[1] & 0x03) << 6);
60614992c7eSRudolf Marek 		/* fan5 input control bit is write only, compute the value */
60714992c7eSRudolf Marek 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
6081ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
6091ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
61008e7e278SJean Delvare 		    | ((data->fan_div[1] & 0x04) << 4);
6111ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
61208e7e278SJean Delvare 		break;
61308e7e278SJean Delvare 	case 2:
6141ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
61508e7e278SJean Delvare 		    | ((data->fan_div[2] & 0x03) << 6);
6161ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
6171ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
61808e7e278SJean Delvare 		    | ((data->fan_div[2] & 0x04) << 5);
6191ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
62008e7e278SJean Delvare 		break;
62108e7e278SJean Delvare 	case 3:
6221ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
62308e7e278SJean Delvare 		    | (data->fan_div[3] & 0x03);
6241ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
6251ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
62608e7e278SJean Delvare 		    | ((data->fan_div[3] & 0x04) << 5);
6271ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
62808e7e278SJean Delvare 		break;
62908e7e278SJean Delvare 	case 4:
6301ea6dd38SDavid Hubbard 		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
63133725ad3SJean Delvare 		    | ((data->fan_div[4] & 0x03) << 2)
63208e7e278SJean Delvare 		    | ((data->fan_div[4] & 0x04) << 5);
6331ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
63408e7e278SJean Delvare 		break;
63508e7e278SJean Delvare 	}
63608e7e278SJean Delvare }
63708e7e278SJean Delvare 
638ec3e5a16SGuenter Roeck static void w83627ehf_write_fan_div_common(struct device *dev,
639ec3e5a16SGuenter Roeck 					   struct w83627ehf_data *data, int nr)
640ec3e5a16SGuenter Roeck {
641ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
642ec3e5a16SGuenter Roeck 
643ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6776)
644ec3e5a16SGuenter Roeck 		; /* no dividers, do nothing */
645ec3e5a16SGuenter Roeck 	else if (sio_data->kind == nct6775)
646ec3e5a16SGuenter Roeck 		nct6775_write_fan_div(data, nr);
647ec3e5a16SGuenter Roeck 	else
648ec3e5a16SGuenter Roeck 		w83627ehf_write_fan_div(data, nr);
649ec3e5a16SGuenter Roeck }
650ec3e5a16SGuenter Roeck 
651ec3e5a16SGuenter Roeck static void nct6775_update_fan_div(struct w83627ehf_data *data)
652ec3e5a16SGuenter Roeck {
653ec3e5a16SGuenter Roeck 	u8 i;
654ec3e5a16SGuenter Roeck 
655ec3e5a16SGuenter Roeck 	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
656ec3e5a16SGuenter Roeck 	data->fan_div[0] = i & 0x7;
657ec3e5a16SGuenter Roeck 	data->fan_div[1] = (i & 0x70) >> 4;
658ec3e5a16SGuenter Roeck 	i = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
659ec3e5a16SGuenter Roeck 	data->fan_div[2] = i & 0x7;
660ec3e5a16SGuenter Roeck 	if (data->has_fan & (1<<3))
661ec3e5a16SGuenter Roeck 		data->fan_div[3] = (i & 0x70) >> 4;
662ec3e5a16SGuenter Roeck }
663ec3e5a16SGuenter Roeck 
664ea7be66cSMark M. Hoffman static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
66508e7e278SJean Delvare {
66608e7e278SJean Delvare 	int i;
66708e7e278SJean Delvare 
6681ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
66908e7e278SJean Delvare 	data->fan_div[0] = (i >> 4) & 0x03;
67008e7e278SJean Delvare 	data->fan_div[1] = (i >> 6) & 0x03;
6711ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
67208e7e278SJean Delvare 	data->fan_div[2] = (i >> 6) & 0x03;
6731ea6dd38SDavid Hubbard 	i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
67408e7e278SJean Delvare 	data->fan_div[0] |= (i >> 3) & 0x04;
67508e7e278SJean Delvare 	data->fan_div[1] |= (i >> 4) & 0x04;
67608e7e278SJean Delvare 	data->fan_div[2] |= (i >> 5) & 0x04;
67708e7e278SJean Delvare 	if (data->has_fan & ((1 << 3) | (1 << 4))) {
6781ea6dd38SDavid Hubbard 		i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
67908e7e278SJean Delvare 		data->fan_div[3] = i & 0x03;
68008e7e278SJean Delvare 		data->fan_div[4] = ((i >> 2) & 0x03)
68108e7e278SJean Delvare 				 | ((i >> 5) & 0x04);
68208e7e278SJean Delvare 	}
68308e7e278SJean Delvare 	if (data->has_fan & (1 << 3)) {
6841ea6dd38SDavid Hubbard 		i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
68508e7e278SJean Delvare 		data->fan_div[3] |= (i >> 5) & 0x04;
68608e7e278SJean Delvare 	}
687ea7be66cSMark M. Hoffman }
688ea7be66cSMark M. Hoffman 
689ec3e5a16SGuenter Roeck static void w83627ehf_update_fan_div_common(struct device *dev,
690ec3e5a16SGuenter Roeck 					    struct w83627ehf_data *data)
691ec3e5a16SGuenter Roeck {
692ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
693ec3e5a16SGuenter Roeck 
694ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6776)
695ec3e5a16SGuenter Roeck 		; /* no dividers, do nothing */
696ec3e5a16SGuenter Roeck 	else if (sio_data->kind == nct6775)
697ec3e5a16SGuenter Roeck 		nct6775_update_fan_div(data);
698ec3e5a16SGuenter Roeck 	else
699ec3e5a16SGuenter Roeck 		w83627ehf_update_fan_div(data);
700ec3e5a16SGuenter Roeck }
701ec3e5a16SGuenter Roeck 
702ec3e5a16SGuenter Roeck static void nct6775_update_pwm(struct w83627ehf_data *data)
703ec3e5a16SGuenter Roeck {
704ec3e5a16SGuenter Roeck 	int i;
705ec3e5a16SGuenter Roeck 	int pwmcfg, fanmodecfg;
706ec3e5a16SGuenter Roeck 
707ec3e5a16SGuenter Roeck 	for (i = 0; i < data->pwm_num; i++) {
708ec3e5a16SGuenter Roeck 		pwmcfg = w83627ehf_read_value(data,
709ec3e5a16SGuenter Roeck 					      W83627EHF_REG_PWM_ENABLE[i]);
710ec3e5a16SGuenter Roeck 		fanmodecfg = w83627ehf_read_value(data,
711ec3e5a16SGuenter Roeck 						  NCT6775_REG_FAN_MODE[i]);
712ec3e5a16SGuenter Roeck 		data->pwm_mode[i] =
713ec3e5a16SGuenter Roeck 		  ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
714ec3e5a16SGuenter Roeck 		data->pwm_enable[i] = ((fanmodecfg >> 4) & 7) + 1;
715ec3e5a16SGuenter Roeck 		data->tolerance[i] = fanmodecfg & 0x0f;
716ec3e5a16SGuenter Roeck 		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
717ec3e5a16SGuenter Roeck 	}
718ec3e5a16SGuenter Roeck }
719ec3e5a16SGuenter Roeck 
720ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm(struct w83627ehf_data *data)
721ec3e5a16SGuenter Roeck {
722ec3e5a16SGuenter Roeck 	int i;
723ec3e5a16SGuenter Roeck 	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
724ec3e5a16SGuenter Roeck 
725ec3e5a16SGuenter Roeck 	for (i = 0; i < data->pwm_num; i++) {
726ec3e5a16SGuenter Roeck 		if (!(data->has_fan & (1 << i)))
727ec3e5a16SGuenter Roeck 			continue;
728ec3e5a16SGuenter Roeck 
729ec3e5a16SGuenter Roeck 		/* pwmcfg, tolerance mapped for i=0, i=1 to same reg */
730ec3e5a16SGuenter Roeck 		if (i != 1) {
731ec3e5a16SGuenter Roeck 			pwmcfg = w83627ehf_read_value(data,
732ec3e5a16SGuenter Roeck 					W83627EHF_REG_PWM_ENABLE[i]);
733ec3e5a16SGuenter Roeck 			tolerance = w83627ehf_read_value(data,
734ec3e5a16SGuenter Roeck 					W83627EHF_REG_TOLERANCE[i]);
735ec3e5a16SGuenter Roeck 		}
736ec3e5a16SGuenter Roeck 		data->pwm_mode[i] =
737ec3e5a16SGuenter Roeck 			((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1) ? 0 : 1;
738ec3e5a16SGuenter Roeck 		data->pwm_enable[i] = ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
739ec3e5a16SGuenter Roeck 				       & 3) + 1;
740ec3e5a16SGuenter Roeck 		data->pwm[i] = w83627ehf_read_value(data, data->REG_PWM[i]);
741ec3e5a16SGuenter Roeck 
742ec3e5a16SGuenter Roeck 		data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0)) & 0x0f;
743ec3e5a16SGuenter Roeck 	}
744ec3e5a16SGuenter Roeck }
745ec3e5a16SGuenter Roeck 
746ec3e5a16SGuenter Roeck static void w83627ehf_update_pwm_common(struct device *dev,
747ec3e5a16SGuenter Roeck 					struct w83627ehf_data *data)
748ec3e5a16SGuenter Roeck {
749ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
750ec3e5a16SGuenter Roeck 
751ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776)
752ec3e5a16SGuenter Roeck 		nct6775_update_pwm(data);
753ec3e5a16SGuenter Roeck 	else
754ec3e5a16SGuenter Roeck 		w83627ehf_update_pwm(data);
755ec3e5a16SGuenter Roeck }
756ec3e5a16SGuenter Roeck 
757ea7be66cSMark M. Hoffman static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
758ea7be66cSMark M. Hoffman {
759ea7be66cSMark M. Hoffman 	struct w83627ehf_data *data = dev_get_drvdata(dev);
760ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
761ec3e5a16SGuenter Roeck 
762ea7be66cSMark M. Hoffman 	int i;
763ea7be66cSMark M. Hoffman 
764ea7be66cSMark M. Hoffman 	mutex_lock(&data->update_lock);
765ea7be66cSMark M. Hoffman 
766ea7be66cSMark M. Hoffman 	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
767ea7be66cSMark M. Hoffman 	 || !data->valid) {
768ea7be66cSMark M. Hoffman 		/* Fan clock dividers */
769ec3e5a16SGuenter Roeck 		w83627ehf_update_fan_div_common(dev, data);
77008e7e278SJean Delvare 
771cf0676feSRudolf Marek 		/* Measured voltages and limits */
7721ea6dd38SDavid Hubbard 		for (i = 0; i < data->in_num; i++) {
7731ea6dd38SDavid Hubbard 			data->in[i] = w83627ehf_read_value(data,
774cf0676feSRudolf Marek 				      W83627EHF_REG_IN(i));
7751ea6dd38SDavid Hubbard 			data->in_min[i] = w83627ehf_read_value(data,
776cf0676feSRudolf Marek 					  W83627EHF_REG_IN_MIN(i));
7771ea6dd38SDavid Hubbard 			data->in_max[i] = w83627ehf_read_value(data,
778cf0676feSRudolf Marek 					  W83627EHF_REG_IN_MAX(i));
779cf0676feSRudolf Marek 		}
780cf0676feSRudolf Marek 
78108e7e278SJean Delvare 		/* Measured fan speeds and limits */
78208e7e278SJean Delvare 		for (i = 0; i < 5; i++) {
7833382a918SGuenter Roeck 			u16 reg;
7843382a918SGuenter Roeck 
78508e7e278SJean Delvare 			if (!(data->has_fan & (1 << i)))
78608e7e278SJean Delvare 				continue;
78708e7e278SJean Delvare 
7883382a918SGuenter Roeck 			reg = w83627ehf_read_value(data, data->REG_FAN[i]);
7893382a918SGuenter Roeck 			data->rpm[i] = data->fan_from_reg(reg,
7903382a918SGuenter Roeck 							  data->fan_div[i]);
791ec3e5a16SGuenter Roeck 
792ec3e5a16SGuenter Roeck 			if (data->has_fan_min & (1 << i))
7931ea6dd38SDavid Hubbard 				data->fan_min[i] = w83627ehf_read_value(data,
794279af1a9SGuenter Roeck 					   data->REG_FAN_MIN[i]);
79508e7e278SJean Delvare 
79608e7e278SJean Delvare 			/* If we failed to measure the fan speed and clock
79708e7e278SJean Delvare 			   divider can be increased, let's try that for next
79808e7e278SJean Delvare 			   time */
79926bc440eSGuenter Roeck 			if (data->has_fan_div
8003382a918SGuenter Roeck 			    && (reg >= 0xff || (sio_data->kind == nct6775
8013382a918SGuenter Roeck 						&& reg == 0x00))
80208e7e278SJean Delvare 			    && data->fan_div[i] < 0x07) {
8031ea6dd38SDavid Hubbard 				dev_dbg(dev, "Increasing fan%d "
80408e7e278SJean Delvare 					"clock divider from %u to %u\n",
80533725ad3SJean Delvare 					i + 1, div_from_reg(data->fan_div[i]),
80608e7e278SJean Delvare 					div_from_reg(data->fan_div[i] + 1));
80708e7e278SJean Delvare 				data->fan_div[i]++;
808ec3e5a16SGuenter Roeck 				w83627ehf_write_fan_div_common(dev, data, i);
80908e7e278SJean Delvare 				/* Preserve min limit if possible */
810ec3e5a16SGuenter Roeck 				if ((data->has_fan_min & (1 << i))
811ec3e5a16SGuenter Roeck 				 && data->fan_min[i] >= 2
81208e7e278SJean Delvare 				 && data->fan_min[i] != 255)
8131ea6dd38SDavid Hubbard 					w83627ehf_write_value(data,
814279af1a9SGuenter Roeck 						data->REG_FAN_MIN[i],
81508e7e278SJean Delvare 						(data->fan_min[i] /= 2));
81608e7e278SJean Delvare 			}
81708e7e278SJean Delvare 		}
81808e7e278SJean Delvare 
819ec3e5a16SGuenter Roeck 		w83627ehf_update_pwm_common(dev, data);
820ec3e5a16SGuenter Roeck 
821da2e0255SGuenter Roeck 		for (i = 0; i < data->pwm_num; i++) {
822da2e0255SGuenter Roeck 			if (!(data->has_fan & (1 << i)))
823da2e0255SGuenter Roeck 				continue;
824da2e0255SGuenter Roeck 
825ec3e5a16SGuenter Roeck 			data->fan_start_output[i] =
826ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
827279af1a9SGuenter Roeck 					       data->REG_FAN_START_OUTPUT[i]);
828ec3e5a16SGuenter Roeck 			data->fan_stop_output[i] =
829ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
830279af1a9SGuenter Roeck 					       data->REG_FAN_STOP_OUTPUT[i]);
831ec3e5a16SGuenter Roeck 			data->fan_stop_time[i] =
832ec3e5a16SGuenter Roeck 			  w83627ehf_read_value(data,
833279af1a9SGuenter Roeck 					       data->REG_FAN_STOP_TIME[i]);
834da2e0255SGuenter Roeck 
835ec3e5a16SGuenter Roeck 			if (data->REG_FAN_MAX_OUTPUT &&
836ec3e5a16SGuenter Roeck 			    data->REG_FAN_MAX_OUTPUT[i] != 0xff)
837da2e0255SGuenter Roeck 				data->fan_max_output[i] =
838da2e0255SGuenter Roeck 				  w83627ehf_read_value(data,
839da2e0255SGuenter Roeck 						data->REG_FAN_MAX_OUTPUT[i]);
840da2e0255SGuenter Roeck 
841ec3e5a16SGuenter Roeck 			if (data->REG_FAN_STEP_OUTPUT &&
842ec3e5a16SGuenter Roeck 			    data->REG_FAN_STEP_OUTPUT[i] != 0xff)
843da2e0255SGuenter Roeck 				data->fan_step_output[i] =
844da2e0255SGuenter Roeck 				  w83627ehf_read_value(data,
845da2e0255SGuenter Roeck 						data->REG_FAN_STEP_OUTPUT[i]);
846da2e0255SGuenter Roeck 
84708c79950SRudolf Marek 			data->target_temp[i] =
8481ea6dd38SDavid Hubbard 				w83627ehf_read_value(data,
849279af1a9SGuenter Roeck 					data->REG_TARGET[i]) &
85008c79950SRudolf Marek 					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
85108c79950SRudolf Marek 		}
85208c79950SRudolf Marek 
85308e7e278SJean Delvare 		/* Measured temperatures and limits */
854d36cf32cSGuenter Roeck 		for (i = 0; i < NUM_REG_TEMP; i++) {
855d36cf32cSGuenter Roeck 			if (!(data->have_temp & (1 << i)))
856d36cf32cSGuenter Roeck 				continue;
857ec3e5a16SGuenter Roeck 			data->temp[i] = w83627ehf_read_value(data,
858ec3e5a16SGuenter Roeck 						data->reg_temp[i]);
859ec3e5a16SGuenter Roeck 			if (data->reg_temp_over[i])
860d36cf32cSGuenter Roeck 				data->temp_max[i]
861d36cf32cSGuenter Roeck 				  = w83627ehf_read_value(data,
862ec3e5a16SGuenter Roeck 						data->reg_temp_over[i]);
863ec3e5a16SGuenter Roeck 			if (data->reg_temp_hyst[i])
864d36cf32cSGuenter Roeck 				data->temp_max_hyst[i]
865d36cf32cSGuenter Roeck 				  = w83627ehf_read_value(data,
866ec3e5a16SGuenter Roeck 						data->reg_temp_hyst[i]);
86708e7e278SJean Delvare 		}
86808e7e278SJean Delvare 
8691ea6dd38SDavid Hubbard 		data->alarms = w83627ehf_read_value(data,
870a4589dbbSJean Delvare 					W83627EHF_REG_ALARM1) |
8711ea6dd38SDavid Hubbard 			       (w83627ehf_read_value(data,
872a4589dbbSJean Delvare 					W83627EHF_REG_ALARM2) << 8) |
8731ea6dd38SDavid Hubbard 			       (w83627ehf_read_value(data,
874a4589dbbSJean Delvare 					W83627EHF_REG_ALARM3) << 16);
875a4589dbbSJean Delvare 
87608e7e278SJean Delvare 		data->last_updated = jiffies;
87708e7e278SJean Delvare 		data->valid = 1;
87808e7e278SJean Delvare 	}
87908e7e278SJean Delvare 
8809a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
88108e7e278SJean Delvare 	return data;
88208e7e278SJean Delvare }
88308e7e278SJean Delvare 
88408e7e278SJean Delvare /*
88508e7e278SJean Delvare  * Sysfs callback functions
88608e7e278SJean Delvare  */
887cf0676feSRudolf Marek #define show_in_reg(reg) \
888cf0676feSRudolf Marek static ssize_t \
889cf0676feSRudolf Marek show_##reg(struct device *dev, struct device_attribute *attr, \
890cf0676feSRudolf Marek 	   char *buf) \
891cf0676feSRudolf Marek { \
892cf0676feSRudolf Marek 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
893e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
894e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
895cf0676feSRudolf Marek 	int nr = sensor_attr->index; \
896cf0676feSRudolf Marek 	return sprintf(buf, "%ld\n", in_from_reg(data->reg[nr], nr)); \
897cf0676feSRudolf Marek }
898cf0676feSRudolf Marek show_in_reg(in)
899cf0676feSRudolf Marek show_in_reg(in_min)
900cf0676feSRudolf Marek show_in_reg(in_max)
901cf0676feSRudolf Marek 
902cf0676feSRudolf Marek #define store_in_reg(REG, reg) \
903cf0676feSRudolf Marek static ssize_t \
904cf0676feSRudolf Marek store_in_##reg(struct device *dev, struct device_attribute *attr, \
905cf0676feSRudolf Marek 	       const char *buf, size_t count) \
906cf0676feSRudolf Marek { \
9071ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
908e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
909e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
910cf0676feSRudolf Marek 	int nr = sensor_attr->index; \
911bce26c58SGuenter Roeck 	unsigned long val; \
912bce26c58SGuenter Roeck 	int err; \
913bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val); \
914bce26c58SGuenter Roeck 	if (err < 0) \
915bce26c58SGuenter Roeck 		return err; \
916cf0676feSRudolf Marek 	mutex_lock(&data->update_lock); \
917cf0676feSRudolf Marek 	data->in_##reg[nr] = in_to_reg(val, nr); \
9181ea6dd38SDavid Hubbard 	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
919cf0676feSRudolf Marek 			      data->in_##reg[nr]); \
920cf0676feSRudolf Marek 	mutex_unlock(&data->update_lock); \
921cf0676feSRudolf Marek 	return count; \
922cf0676feSRudolf Marek }
923cf0676feSRudolf Marek 
924cf0676feSRudolf Marek store_in_reg(MIN, min)
925cf0676feSRudolf Marek store_in_reg(MAX, max)
926cf0676feSRudolf Marek 
927e7e1ca6eSGuenter Roeck static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
928e7e1ca6eSGuenter Roeck 			  char *buf)
929a4589dbbSJean Delvare {
930a4589dbbSJean Delvare 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
931a4589dbbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
932a4589dbbSJean Delvare 	int nr = sensor_attr->index;
933a4589dbbSJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> nr) & 0x01);
934a4589dbbSJean Delvare }
935a4589dbbSJean Delvare 
936cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_input[] = {
937cf0676feSRudolf Marek 	SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
938cf0676feSRudolf Marek 	SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
939cf0676feSRudolf Marek 	SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
940cf0676feSRudolf Marek 	SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
941cf0676feSRudolf Marek 	SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
942cf0676feSRudolf Marek 	SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
943cf0676feSRudolf Marek 	SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
944cf0676feSRudolf Marek 	SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
945cf0676feSRudolf Marek 	SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
946cf0676feSRudolf Marek 	SENSOR_ATTR(in9_input, S_IRUGO, show_in, NULL, 9),
947cf0676feSRudolf Marek };
948cf0676feSRudolf Marek 
949a4589dbbSJean Delvare static struct sensor_device_attribute sda_in_alarm[] = {
950a4589dbbSJean Delvare 	SENSOR_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0),
951a4589dbbSJean Delvare 	SENSOR_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1),
952a4589dbbSJean Delvare 	SENSOR_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2),
953a4589dbbSJean Delvare 	SENSOR_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3),
954a4589dbbSJean Delvare 	SENSOR_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8),
955a4589dbbSJean Delvare 	SENSOR_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 21),
956a4589dbbSJean Delvare 	SENSOR_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 20),
957a4589dbbSJean Delvare 	SENSOR_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 16),
958a4589dbbSJean Delvare 	SENSOR_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 17),
959a4589dbbSJean Delvare 	SENSOR_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 19),
960a4589dbbSJean Delvare };
961a4589dbbSJean Delvare 
962cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_min[] = {
963cf0676feSRudolf Marek 	SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
964cf0676feSRudolf Marek 	SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
965cf0676feSRudolf Marek 	SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
966cf0676feSRudolf Marek 	SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
967cf0676feSRudolf Marek 	SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
968cf0676feSRudolf Marek 	SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
969cf0676feSRudolf Marek 	SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
970cf0676feSRudolf Marek 	SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
971cf0676feSRudolf Marek 	SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
972cf0676feSRudolf Marek 	SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 9),
973cf0676feSRudolf Marek };
974cf0676feSRudolf Marek 
975cf0676feSRudolf Marek static struct sensor_device_attribute sda_in_max[] = {
976cf0676feSRudolf Marek 	SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
977cf0676feSRudolf Marek 	SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
978cf0676feSRudolf Marek 	SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
979cf0676feSRudolf Marek 	SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
980cf0676feSRudolf Marek 	SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
981cf0676feSRudolf Marek 	SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
982cf0676feSRudolf Marek 	SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
983cf0676feSRudolf Marek 	SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
984cf0676feSRudolf Marek 	SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
985cf0676feSRudolf Marek 	SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
986cf0676feSRudolf Marek };
987cf0676feSRudolf Marek 
988ec3e5a16SGuenter Roeck static ssize_t
989ec3e5a16SGuenter Roeck show_fan(struct device *dev, struct device_attribute *attr, char *buf)
990ec3e5a16SGuenter Roeck {
991ec3e5a16SGuenter Roeck 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
992ec3e5a16SGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
993ec3e5a16SGuenter Roeck 	int nr = sensor_attr->index;
9943382a918SGuenter Roeck 	return sprintf(buf, "%d\n", data->rpm[nr]);
99508e7e278SJean Delvare }
996ec3e5a16SGuenter Roeck 
997ec3e5a16SGuenter Roeck static ssize_t
998ec3e5a16SGuenter Roeck show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
999ec3e5a16SGuenter Roeck {
1000ec3e5a16SGuenter Roeck 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
1001ec3e5a16SGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1002ec3e5a16SGuenter Roeck 	int nr = sensor_attr->index;
1003ec3e5a16SGuenter Roeck 	return sprintf(buf, "%d\n",
100426bc440eSGuenter Roeck 		       data->fan_from_reg_min(data->fan_min[nr],
100526bc440eSGuenter Roeck 					      data->fan_div[nr]));
1006ec3e5a16SGuenter Roeck }
100708e7e278SJean Delvare 
100808e7e278SJean Delvare static ssize_t
1009412fec82SYuan Mu show_fan_div(struct device *dev, struct device_attribute *attr,
1010412fec82SYuan Mu 	     char *buf)
101108e7e278SJean Delvare {
101208e7e278SJean Delvare 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
1013412fec82SYuan Mu 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1014412fec82SYuan Mu 	int nr = sensor_attr->index;
1015412fec82SYuan Mu 	return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
101608e7e278SJean Delvare }
101708e7e278SJean Delvare 
101808e7e278SJean Delvare static ssize_t
1019412fec82SYuan Mu store_fan_min(struct device *dev, struct device_attribute *attr,
1020412fec82SYuan Mu 	      const char *buf, size_t count)
102108e7e278SJean Delvare {
10221ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1023412fec82SYuan Mu 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1024412fec82SYuan Mu 	int nr = sensor_attr->index;
1025bce26c58SGuenter Roeck 	unsigned long val;
1026bce26c58SGuenter Roeck 	int err;
102708e7e278SJean Delvare 	unsigned int reg;
102808e7e278SJean Delvare 	u8 new_div;
102908e7e278SJean Delvare 
1030bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val);
1031bce26c58SGuenter Roeck 	if (err < 0)
1032bce26c58SGuenter Roeck 		return err;
1033bce26c58SGuenter Roeck 
10349a61bf63SIngo Molnar 	mutex_lock(&data->update_lock);
103526bc440eSGuenter Roeck 	if (!data->has_fan_div) {
103626bc440eSGuenter Roeck 		/*
103726bc440eSGuenter Roeck 		 * Only NCT6776F for now, so we know that this is a 13 bit
103826bc440eSGuenter Roeck 		 * register
103926bc440eSGuenter Roeck 		 */
1040ec3e5a16SGuenter Roeck 		if (!val) {
1041ec3e5a16SGuenter Roeck 			val = 0xff1f;
1042ec3e5a16SGuenter Roeck 		} else {
1043ec3e5a16SGuenter Roeck 			if (val > 1350000U)
1044ec3e5a16SGuenter Roeck 				val = 135000U;
1045ec3e5a16SGuenter Roeck 			val = 1350000U / val;
1046ec3e5a16SGuenter Roeck 			val = (val & 0x1f) | ((val << 3) & 0xff00);
1047ec3e5a16SGuenter Roeck 		}
1048ec3e5a16SGuenter Roeck 		data->fan_min[nr] = val;
1049ec3e5a16SGuenter Roeck 		goto done;	/* Leave fan divider alone */
1050ec3e5a16SGuenter Roeck 	}
105108e7e278SJean Delvare 	if (!val) {
105208e7e278SJean Delvare 		/* No min limit, alarm disabled */
105308e7e278SJean Delvare 		data->fan_min[nr] = 255;
105408e7e278SJean Delvare 		new_div = data->fan_div[nr]; /* No change */
105508e7e278SJean Delvare 		dev_info(dev, "fan%u low limit and alarm disabled\n", nr + 1);
105608e7e278SJean Delvare 	} else if ((reg = 1350000U / val) >= 128 * 255) {
105708e7e278SJean Delvare 		/* Speed below this value cannot possibly be represented,
105808e7e278SJean Delvare 		   even with the highest divider (128) */
105908e7e278SJean Delvare 		data->fan_min[nr] = 254;
106008e7e278SJean Delvare 		new_div = 7; /* 128 == (1 << 7) */
1061bce26c58SGuenter Roeck 		dev_warn(dev, "fan%u low limit %lu below minimum %u, set to "
1062ec3e5a16SGuenter Roeck 			 "minimum\n", nr + 1, val,
106326bc440eSGuenter Roeck 			 data->fan_from_reg_min(254, 7));
106408e7e278SJean Delvare 	} else if (!reg) {
106508e7e278SJean Delvare 		/* Speed above this value cannot possibly be represented,
106608e7e278SJean Delvare 		   even with the lowest divider (1) */
106708e7e278SJean Delvare 		data->fan_min[nr] = 1;
106808e7e278SJean Delvare 		new_div = 0; /* 1 == (1 << 0) */
1069bce26c58SGuenter Roeck 		dev_warn(dev, "fan%u low limit %lu above maximum %u, set to "
1070ec3e5a16SGuenter Roeck 			 "maximum\n", nr + 1, val,
107126bc440eSGuenter Roeck 			 data->fan_from_reg_min(1, 0));
107208e7e278SJean Delvare 	} else {
107308e7e278SJean Delvare 		/* Automatically pick the best divider, i.e. the one such
107408e7e278SJean Delvare 		   that the min limit will correspond to a register value
107508e7e278SJean Delvare 		   in the 96..192 range */
107608e7e278SJean Delvare 		new_div = 0;
107708e7e278SJean Delvare 		while (reg > 192 && new_div < 7) {
107808e7e278SJean Delvare 			reg >>= 1;
107908e7e278SJean Delvare 			new_div++;
108008e7e278SJean Delvare 		}
108108e7e278SJean Delvare 		data->fan_min[nr] = reg;
108208e7e278SJean Delvare 	}
108308e7e278SJean Delvare 
108408e7e278SJean Delvare 	/* Write both the fan clock divider (if it changed) and the new
108508e7e278SJean Delvare 	   fan min (unconditionally) */
108608e7e278SJean Delvare 	if (new_div != data->fan_div[nr]) {
108708e7e278SJean Delvare 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
108808e7e278SJean Delvare 			nr + 1, div_from_reg(data->fan_div[nr]),
108908e7e278SJean Delvare 			div_from_reg(new_div));
109008e7e278SJean Delvare 		data->fan_div[nr] = new_div;
1091ec3e5a16SGuenter Roeck 		w83627ehf_write_fan_div_common(dev, data, nr);
10926b3e4645SJean Delvare 		/* Give the chip time to sample a new speed value */
10936b3e4645SJean Delvare 		data->last_updated = jiffies;
109408e7e278SJean Delvare 	}
1095ec3e5a16SGuenter Roeck done:
1096279af1a9SGuenter Roeck 	w83627ehf_write_value(data, data->REG_FAN_MIN[nr],
109708e7e278SJean Delvare 			      data->fan_min[nr]);
10989a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock);
109908e7e278SJean Delvare 
110008e7e278SJean Delvare 	return count;
110108e7e278SJean Delvare }
110208e7e278SJean Delvare 
1103412fec82SYuan Mu static struct sensor_device_attribute sda_fan_input[] = {
1104412fec82SYuan Mu 	SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
1105412fec82SYuan Mu 	SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
1106412fec82SYuan Mu 	SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
1107412fec82SYuan Mu 	SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3),
1108412fec82SYuan Mu 	SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4),
1109412fec82SYuan Mu };
111008e7e278SJean Delvare 
1111a4589dbbSJean Delvare static struct sensor_device_attribute sda_fan_alarm[] = {
1112a4589dbbSJean Delvare 	SENSOR_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6),
1113a4589dbbSJean Delvare 	SENSOR_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7),
1114a4589dbbSJean Delvare 	SENSOR_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11),
1115a4589dbbSJean Delvare 	SENSOR_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 10),
1116a4589dbbSJean Delvare 	SENSOR_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 23),
1117a4589dbbSJean Delvare };
1118a4589dbbSJean Delvare 
1119412fec82SYuan Mu static struct sensor_device_attribute sda_fan_min[] = {
1120412fec82SYuan Mu 	SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min,
1121412fec82SYuan Mu 		    store_fan_min, 0),
1122412fec82SYuan Mu 	SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min,
1123412fec82SYuan Mu 		    store_fan_min, 1),
1124412fec82SYuan Mu 	SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min,
1125412fec82SYuan Mu 		    store_fan_min, 2),
1126412fec82SYuan Mu 	SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min,
1127412fec82SYuan Mu 		    store_fan_min, 3),
1128412fec82SYuan Mu 	SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min,
1129412fec82SYuan Mu 		    store_fan_min, 4),
1130412fec82SYuan Mu };
113108e7e278SJean Delvare 
1132412fec82SYuan Mu static struct sensor_device_attribute sda_fan_div[] = {
1133412fec82SYuan Mu 	SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0),
1134412fec82SYuan Mu 	SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1),
1135412fec82SYuan Mu 	SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2),
1136412fec82SYuan Mu 	SENSOR_ATTR(fan4_div, S_IRUGO, show_fan_div, NULL, 3),
1137412fec82SYuan Mu 	SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
1138412fec82SYuan Mu };
113908e7e278SJean Delvare 
1140d36cf32cSGuenter Roeck static ssize_t
1141d36cf32cSGuenter Roeck show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
1142d36cf32cSGuenter Roeck {
1143d36cf32cSGuenter Roeck 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
1144d36cf32cSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1145d36cf32cSGuenter Roeck 	int nr = sensor_attr->index;
1146d36cf32cSGuenter Roeck 	return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
1147d36cf32cSGuenter Roeck }
1148d36cf32cSGuenter Roeck 
1149ec3e5a16SGuenter Roeck #define show_temp_reg(addr, reg) \
115008e7e278SJean Delvare static ssize_t \
1151412fec82SYuan Mu show_##reg(struct device *dev, struct device_attribute *attr, \
1152412fec82SYuan Mu 	   char *buf) \
115308e7e278SJean Delvare { \
115408e7e278SJean Delvare 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1155e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1156e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
1157412fec82SYuan Mu 	int nr = sensor_attr->index; \
115808e7e278SJean Delvare 	return sprintf(buf, "%d\n", \
1159ec3e5a16SGuenter Roeck 		       temp_from_reg(data->addr[nr], data->reg[nr])); \
116008e7e278SJean Delvare }
1161ec3e5a16SGuenter Roeck show_temp_reg(reg_temp, temp);
1162ec3e5a16SGuenter Roeck show_temp_reg(reg_temp_over, temp_max);
1163ec3e5a16SGuenter Roeck show_temp_reg(reg_temp_hyst, temp_max_hyst);
116408e7e278SJean Delvare 
1165ec3e5a16SGuenter Roeck #define store_temp_reg(addr, reg) \
116608e7e278SJean Delvare static ssize_t \
1167412fec82SYuan Mu store_##reg(struct device *dev, struct device_attribute *attr, \
1168412fec82SYuan Mu 	    const char *buf, size_t count) \
116908e7e278SJean Delvare { \
11701ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
1171e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1172e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
1173412fec82SYuan Mu 	int nr = sensor_attr->index; \
1174bce26c58SGuenter Roeck 	int err; \
1175bce26c58SGuenter Roeck 	long val; \
1176bce26c58SGuenter Roeck 	err = strict_strtol(buf, 10, &val); \
1177bce26c58SGuenter Roeck 	if (err < 0) \
1178bce26c58SGuenter Roeck 		return err; \
11799a61bf63SIngo Molnar 	mutex_lock(&data->update_lock); \
1180ec3e5a16SGuenter Roeck 	data->reg[nr] = temp_to_reg(data->addr[nr], val); \
1181ec3e5a16SGuenter Roeck 	w83627ehf_write_value(data, data->addr[nr], \
118208e7e278SJean Delvare 			      data->reg[nr]); \
11839a61bf63SIngo Molnar 	mutex_unlock(&data->update_lock); \
118408e7e278SJean Delvare 	return count; \
118508e7e278SJean Delvare }
1186ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_over, temp_max);
1187ec3e5a16SGuenter Roeck store_temp_reg(reg_temp_hyst, temp_max_hyst);
118808e7e278SJean Delvare 
1189da667365SJean Delvare static ssize_t
1190da667365SJean Delvare show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
1191da667365SJean Delvare {
1192da667365SJean Delvare 	struct w83627ehf_data *data = w83627ehf_update_device(dev);
1193da667365SJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1194da667365SJean Delvare 	int nr = sensor_attr->index;
1195da667365SJean Delvare 	return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
1196da667365SJean Delvare }
1197da667365SJean Delvare 
1198a157d06dSGong Jun static struct sensor_device_attribute sda_temp_input[] = {
1199bce26c58SGuenter Roeck 	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
1200bce26c58SGuenter Roeck 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
1201bce26c58SGuenter Roeck 	SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
1202d36cf32cSGuenter Roeck 	SENSOR_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3),
1203ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4),
1204ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5),
1205ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6),
1206ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7),
1207ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8),
1208d36cf32cSGuenter Roeck };
1209d36cf32cSGuenter Roeck 
1210d36cf32cSGuenter Roeck static struct sensor_device_attribute sda_temp_label[] = {
1211d36cf32cSGuenter Roeck 	SENSOR_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL, 0),
1212d36cf32cSGuenter Roeck 	SENSOR_ATTR(temp2_label, S_IRUGO, show_temp_label, NULL, 1),
1213d36cf32cSGuenter Roeck 	SENSOR_ATTR(temp3_label, S_IRUGO, show_temp_label, NULL, 2),
1214d36cf32cSGuenter Roeck 	SENSOR_ATTR(temp4_label, S_IRUGO, show_temp_label, NULL, 3),
1215ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp5_label, S_IRUGO, show_temp_label, NULL, 4),
1216ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp6_label, S_IRUGO, show_temp_label, NULL, 5),
1217ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp7_label, S_IRUGO, show_temp_label, NULL, 6),
1218ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp8_label, S_IRUGO, show_temp_label, NULL, 7),
1219ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp9_label, S_IRUGO, show_temp_label, NULL, 8),
1220a157d06dSGong Jun };
1221a157d06dSGong Jun 
1222a157d06dSGong Jun static struct sensor_device_attribute sda_temp_max[] = {
1223bce26c58SGuenter Roeck 	SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp_max,
1224412fec82SYuan Mu 		    store_temp_max, 0),
1225bce26c58SGuenter Roeck 	SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, show_temp_max,
1226412fec82SYuan Mu 		    store_temp_max, 1),
1227bce26c58SGuenter Roeck 	SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, show_temp_max,
1228bce26c58SGuenter Roeck 		    store_temp_max, 2),
1229ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, show_temp_max,
1230ec3e5a16SGuenter Roeck 		    store_temp_max, 3),
1231ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, show_temp_max,
1232ec3e5a16SGuenter Roeck 		    store_temp_max, 4),
1233ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, show_temp_max,
1234ec3e5a16SGuenter Roeck 		    store_temp_max, 5),
1235ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp7_max, S_IRUGO | S_IWUSR, show_temp_max,
1236ec3e5a16SGuenter Roeck 		    store_temp_max, 6),
1237ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp8_max, S_IRUGO | S_IWUSR, show_temp_max,
1238ec3e5a16SGuenter Roeck 		    store_temp_max, 7),
1239ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp9_max, S_IRUGO | S_IWUSR, show_temp_max,
1240ec3e5a16SGuenter Roeck 		    store_temp_max, 8),
1241a157d06dSGong Jun };
1242a157d06dSGong Jun 
1243a157d06dSGong Jun static struct sensor_device_attribute sda_temp_max_hyst[] = {
1244bce26c58SGuenter Roeck 	SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1245412fec82SYuan Mu 		    store_temp_max_hyst, 0),
1246bce26c58SGuenter Roeck 	SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1247412fec82SYuan Mu 		    store_temp_max_hyst, 1),
1248bce26c58SGuenter Roeck 	SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1249bce26c58SGuenter Roeck 		    store_temp_max_hyst, 2),
1250ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp4_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1251ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 3),
1252ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp5_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1253ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 4),
1254ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp6_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1255ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 5),
1256ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp7_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1257ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 6),
1258ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp8_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1259ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 7),
1260ec3e5a16SGuenter Roeck 	SENSOR_ATTR(temp9_max_hyst, S_IRUGO | S_IWUSR, show_temp_max_hyst,
1261ec3e5a16SGuenter Roeck 		    store_temp_max_hyst, 8),
1262a157d06dSGong Jun };
1263a157d06dSGong Jun 
1264a157d06dSGong Jun static struct sensor_device_attribute sda_temp_alarm[] = {
1265a4589dbbSJean Delvare 	SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
1266a4589dbbSJean Delvare 	SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
1267a4589dbbSJean Delvare 	SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
1268a157d06dSGong Jun };
1269a157d06dSGong Jun 
1270a157d06dSGong Jun static struct sensor_device_attribute sda_temp_type[] = {
1271da667365SJean Delvare 	SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
1272da667365SJean Delvare 	SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
1273da667365SJean Delvare 	SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
1274412fec82SYuan Mu };
127508e7e278SJean Delvare 
127608c79950SRudolf Marek #define show_pwm_reg(reg) \
127708c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
127808c79950SRudolf Marek 			  char *buf) \
127908c79950SRudolf Marek { \
128008c79950SRudolf Marek 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1281e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1282e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
128308c79950SRudolf Marek 	int nr = sensor_attr->index; \
128408c79950SRudolf Marek 	return sprintf(buf, "%d\n", data->reg[nr]); \
128508c79950SRudolf Marek }
128608c79950SRudolf Marek 
128708c79950SRudolf Marek show_pwm_reg(pwm_mode)
128808c79950SRudolf Marek show_pwm_reg(pwm_enable)
128908c79950SRudolf Marek show_pwm_reg(pwm)
129008c79950SRudolf Marek 
129108c79950SRudolf Marek static ssize_t
129208c79950SRudolf Marek store_pwm_mode(struct device *dev, struct device_attribute *attr,
129308c79950SRudolf Marek 			const char *buf, size_t count)
129408c79950SRudolf Marek {
12951ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
129608c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
129708c79950SRudolf Marek 	int nr = sensor_attr->index;
1298bce26c58SGuenter Roeck 	unsigned long val;
1299bce26c58SGuenter Roeck 	int err;
130008c79950SRudolf Marek 	u16 reg;
130108c79950SRudolf Marek 
1302bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val);
1303bce26c58SGuenter Roeck 	if (err < 0)
1304bce26c58SGuenter Roeck 		return err;
1305bce26c58SGuenter Roeck 
130608c79950SRudolf Marek 	if (val > 1)
130708c79950SRudolf Marek 		return -EINVAL;
130808c79950SRudolf Marek 	mutex_lock(&data->update_lock);
13091ea6dd38SDavid Hubbard 	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
131008c79950SRudolf Marek 	data->pwm_mode[nr] = val;
131108c79950SRudolf Marek 	reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
131208c79950SRudolf Marek 	if (!val)
131308c79950SRudolf Marek 		reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
13141ea6dd38SDavid Hubbard 	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
131508c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
131608c79950SRudolf Marek 	return count;
131708c79950SRudolf Marek }
131808c79950SRudolf Marek 
131908c79950SRudolf Marek static ssize_t
132008c79950SRudolf Marek store_pwm(struct device *dev, struct device_attribute *attr,
132108c79950SRudolf Marek 			const char *buf, size_t count)
132208c79950SRudolf Marek {
13231ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
132408c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
132508c79950SRudolf Marek 	int nr = sensor_attr->index;
1326bce26c58SGuenter Roeck 	unsigned long val;
1327bce26c58SGuenter Roeck 	int err;
1328bce26c58SGuenter Roeck 
1329bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val);
1330bce26c58SGuenter Roeck 	if (err < 0)
1331bce26c58SGuenter Roeck 		return err;
1332bce26c58SGuenter Roeck 
1333bce26c58SGuenter Roeck 	val = SENSORS_LIMIT(val, 0, 255);
133408c79950SRudolf Marek 
133508c79950SRudolf Marek 	mutex_lock(&data->update_lock);
133608c79950SRudolf Marek 	data->pwm[nr] = val;
1337279af1a9SGuenter Roeck 	w83627ehf_write_value(data, data->REG_PWM[nr], val);
133808c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
133908c79950SRudolf Marek 	return count;
134008c79950SRudolf Marek }
134108c79950SRudolf Marek 
134208c79950SRudolf Marek static ssize_t
134308c79950SRudolf Marek store_pwm_enable(struct device *dev, struct device_attribute *attr,
134408c79950SRudolf Marek 			const char *buf, size_t count)
134508c79950SRudolf Marek {
13461ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1347ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
134808c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
134908c79950SRudolf Marek 	int nr = sensor_attr->index;
1350bce26c58SGuenter Roeck 	unsigned long val;
1351bce26c58SGuenter Roeck 	int err;
135208c79950SRudolf Marek 	u16 reg;
135308c79950SRudolf Marek 
1354bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val);
1355bce26c58SGuenter Roeck 	if (err < 0)
1356bce26c58SGuenter Roeck 		return err;
1357bce26c58SGuenter Roeck 
1358b84bb518SGuenter Roeck 	if (!val || (val > 4 && val != data->pwm_enable_orig[nr]))
135908c79950SRudolf Marek 		return -EINVAL;
1360ec3e5a16SGuenter Roeck 	/* SmartFan III mode is not supported on NCT6776F */
1361ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6776 && val == 4)
1362ec3e5a16SGuenter Roeck 		return -EINVAL;
1363ec3e5a16SGuenter Roeck 
136408c79950SRudolf Marek 	mutex_lock(&data->update_lock);
136508c79950SRudolf Marek 	data->pwm_enable[nr] = val;
1366ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1367ec3e5a16SGuenter Roeck 		reg = w83627ehf_read_value(data,
1368ec3e5a16SGuenter Roeck 					   NCT6775_REG_FAN_MODE[nr]);
1369ec3e5a16SGuenter Roeck 		reg &= 0x0f;
1370ec3e5a16SGuenter Roeck 		reg |= (val - 1) << 4;
1371ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data,
1372ec3e5a16SGuenter Roeck 				      NCT6775_REG_FAN_MODE[nr], reg);
1373ec3e5a16SGuenter Roeck 	} else {
1374ec3e5a16SGuenter Roeck 		reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
137508c79950SRudolf Marek 		reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
137608c79950SRudolf Marek 		reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
13771ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
1378ec3e5a16SGuenter Roeck 	}
137908c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
138008c79950SRudolf Marek 	return count;
138108c79950SRudolf Marek }
138208c79950SRudolf Marek 
138308c79950SRudolf Marek 
138408c79950SRudolf Marek #define show_tol_temp(reg) \
138508c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
138608c79950SRudolf Marek 				char *buf) \
138708c79950SRudolf Marek { \
138808c79950SRudolf Marek 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1389e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1390e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
139108c79950SRudolf Marek 	int nr = sensor_attr->index; \
1392bce26c58SGuenter Roeck 	return sprintf(buf, "%d\n", data->reg[nr] * 1000); \
139308c79950SRudolf Marek }
139408c79950SRudolf Marek 
139508c79950SRudolf Marek show_tol_temp(tolerance)
139608c79950SRudolf Marek show_tol_temp(target_temp)
139708c79950SRudolf Marek 
139808c79950SRudolf Marek static ssize_t
139908c79950SRudolf Marek store_target_temp(struct device *dev, struct device_attribute *attr,
140008c79950SRudolf Marek 			const char *buf, size_t count)
140108c79950SRudolf Marek {
14021ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
140308c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
140408c79950SRudolf Marek 	int nr = sensor_attr->index;
1405bce26c58SGuenter Roeck 	long val;
1406bce26c58SGuenter Roeck 	int err;
1407bce26c58SGuenter Roeck 
1408bce26c58SGuenter Roeck 	err = strict_strtol(buf, 10, &val);
1409bce26c58SGuenter Roeck 	if (err < 0)
1410bce26c58SGuenter Roeck 		return err;
1411bce26c58SGuenter Roeck 
1412bce26c58SGuenter Roeck 	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 127);
141308c79950SRudolf Marek 
141408c79950SRudolf Marek 	mutex_lock(&data->update_lock);
141508c79950SRudolf Marek 	data->target_temp[nr] = val;
1416279af1a9SGuenter Roeck 	w83627ehf_write_value(data, data->REG_TARGET[nr], val);
141708c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
141808c79950SRudolf Marek 	return count;
141908c79950SRudolf Marek }
142008c79950SRudolf Marek 
142108c79950SRudolf Marek static ssize_t
142208c79950SRudolf Marek store_tolerance(struct device *dev, struct device_attribute *attr,
142308c79950SRudolf Marek 			const char *buf, size_t count)
142408c79950SRudolf Marek {
14251ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1426ec3e5a16SGuenter Roeck 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
142708c79950SRudolf Marek 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
142808c79950SRudolf Marek 	int nr = sensor_attr->index;
142908c79950SRudolf Marek 	u16 reg;
1430bce26c58SGuenter Roeck 	long val;
1431bce26c58SGuenter Roeck 	int err;
1432bce26c58SGuenter Roeck 
1433bce26c58SGuenter Roeck 	err = strict_strtol(buf, 10, &val);
1434bce26c58SGuenter Roeck 	if (err < 0)
1435bce26c58SGuenter Roeck 		return err;
1436bce26c58SGuenter Roeck 
143708c79950SRudolf Marek 	/* Limit the temp to 0C - 15C */
1438bce26c58SGuenter Roeck 	val = SENSORS_LIMIT(DIV_ROUND_CLOSEST(val, 1000), 0, 15);
143908c79950SRudolf Marek 
144008c79950SRudolf Marek 	mutex_lock(&data->update_lock);
1441ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1442ec3e5a16SGuenter Roeck 		/* Limit tolerance further for NCT6776F */
1443ec3e5a16SGuenter Roeck 		if (sio_data->kind == nct6776 && val > 7)
1444ec3e5a16SGuenter Roeck 			val = 7;
1445ec3e5a16SGuenter Roeck 		reg = w83627ehf_read_value(data, NCT6775_REG_FAN_MODE[nr]);
1446ec3e5a16SGuenter Roeck 		reg = (reg & 0xf0) | val;
1447ec3e5a16SGuenter Roeck 		w83627ehf_write_value(data, NCT6775_REG_FAN_MODE[nr], reg);
1448ec3e5a16SGuenter Roeck 	} else {
14491ea6dd38SDavid Hubbard 		reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
145008c79950SRudolf Marek 		if (nr == 1)
145108c79950SRudolf Marek 			reg = (reg & 0x0f) | (val << 4);
145208c79950SRudolf Marek 		else
145308c79950SRudolf Marek 			reg = (reg & 0xf0) | val;
14541ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
1455ec3e5a16SGuenter Roeck 	}
1456ec3e5a16SGuenter Roeck 	data->tolerance[nr] = val;
145708c79950SRudolf Marek 	mutex_unlock(&data->update_lock);
145808c79950SRudolf Marek 	return count;
145908c79950SRudolf Marek }
146008c79950SRudolf Marek 
146108c79950SRudolf Marek static struct sensor_device_attribute sda_pwm[] = {
146208c79950SRudolf Marek 	SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
146308c79950SRudolf Marek 	SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
146408c79950SRudolf Marek 	SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
146508c79950SRudolf Marek 	SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
146608c79950SRudolf Marek };
146708c79950SRudolf Marek 
146808c79950SRudolf Marek static struct sensor_device_attribute sda_pwm_mode[] = {
146908c79950SRudolf Marek 	SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
147008c79950SRudolf Marek 		    store_pwm_mode, 0),
147108c79950SRudolf Marek 	SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
147208c79950SRudolf Marek 		    store_pwm_mode, 1),
147308c79950SRudolf Marek 	SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
147408c79950SRudolf Marek 		    store_pwm_mode, 2),
147508c79950SRudolf Marek 	SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
147608c79950SRudolf Marek 		    store_pwm_mode, 3),
147708c79950SRudolf Marek };
147808c79950SRudolf Marek 
147908c79950SRudolf Marek static struct sensor_device_attribute sda_pwm_enable[] = {
148008c79950SRudolf Marek 	SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
148108c79950SRudolf Marek 		    store_pwm_enable, 0),
148208c79950SRudolf Marek 	SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
148308c79950SRudolf Marek 		    store_pwm_enable, 1),
148408c79950SRudolf Marek 	SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
148508c79950SRudolf Marek 		    store_pwm_enable, 2),
148608c79950SRudolf Marek 	SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
148708c79950SRudolf Marek 		    store_pwm_enable, 3),
148808c79950SRudolf Marek };
148908c79950SRudolf Marek 
149008c79950SRudolf Marek static struct sensor_device_attribute sda_target_temp[] = {
149108c79950SRudolf Marek 	SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
149208c79950SRudolf Marek 		    store_target_temp, 0),
149308c79950SRudolf Marek 	SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
149408c79950SRudolf Marek 		    store_target_temp, 1),
149508c79950SRudolf Marek 	SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
149608c79950SRudolf Marek 		    store_target_temp, 2),
149708c79950SRudolf Marek 	SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
149808c79950SRudolf Marek 		    store_target_temp, 3),
149908c79950SRudolf Marek };
150008c79950SRudolf Marek 
150108c79950SRudolf Marek static struct sensor_device_attribute sda_tolerance[] = {
150208c79950SRudolf Marek 	SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
150308c79950SRudolf Marek 		    store_tolerance, 0),
150408c79950SRudolf Marek 	SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
150508c79950SRudolf Marek 		    store_tolerance, 1),
150608c79950SRudolf Marek 	SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
150708c79950SRudolf Marek 		    store_tolerance, 2),
150808c79950SRudolf Marek 	SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
150908c79950SRudolf Marek 		    store_tolerance, 3),
151008c79950SRudolf Marek };
151108c79950SRudolf Marek 
151208c79950SRudolf Marek /* Smart Fan registers */
151308c79950SRudolf Marek 
151408c79950SRudolf Marek #define fan_functions(reg, REG) \
151508c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
151608c79950SRudolf Marek 		       char *buf) \
151708c79950SRudolf Marek { \
151808c79950SRudolf Marek 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1519e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1520e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
152108c79950SRudolf Marek 	int nr = sensor_attr->index; \
152208c79950SRudolf Marek 	return sprintf(buf, "%d\n", data->reg[nr]); \
152308c79950SRudolf Marek } \
152408c79950SRudolf Marek static ssize_t \
152508c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
152608c79950SRudolf Marek 			    const char *buf, size_t count) \
152708c79950SRudolf Marek { \
15281ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
1529e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1530e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
153108c79950SRudolf Marek 	int nr = sensor_attr->index; \
1532bce26c58SGuenter Roeck 	unsigned long val; \
1533bce26c58SGuenter Roeck 	int err; \
1534bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val); \
1535bce26c58SGuenter Roeck 	if (err < 0) \
1536bce26c58SGuenter Roeck 		return err; \
1537bce26c58SGuenter Roeck 	val = SENSORS_LIMIT(val, 1, 255); \
153808c79950SRudolf Marek 	mutex_lock(&data->update_lock); \
153908c79950SRudolf Marek 	data->reg[nr] = val; \
1540da2e0255SGuenter Roeck 	w83627ehf_write_value(data, data->REG_##REG[nr], val); \
154108c79950SRudolf Marek 	mutex_unlock(&data->update_lock); \
154208c79950SRudolf Marek 	return count; \
154308c79950SRudolf Marek }
154408c79950SRudolf Marek 
154541e9a062SDaniel J Blueman fan_functions(fan_start_output, FAN_START_OUTPUT)
154641e9a062SDaniel J Blueman fan_functions(fan_stop_output, FAN_STOP_OUTPUT)
154741e9a062SDaniel J Blueman fan_functions(fan_max_output, FAN_MAX_OUTPUT)
154841e9a062SDaniel J Blueman fan_functions(fan_step_output, FAN_STEP_OUTPUT)
154908c79950SRudolf Marek 
155008c79950SRudolf Marek #define fan_time_functions(reg, REG) \
155108c79950SRudolf Marek static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
155208c79950SRudolf Marek 				char *buf) \
155308c79950SRudolf Marek { \
155408c79950SRudolf Marek 	struct w83627ehf_data *data = w83627ehf_update_device(dev); \
1555e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1556e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
155708c79950SRudolf Marek 	int nr = sensor_attr->index; \
155808c79950SRudolf Marek 	return sprintf(buf, "%d\n", \
1559e7e1ca6eSGuenter Roeck 			step_time_from_reg(data->reg[nr], \
1560e7e1ca6eSGuenter Roeck 					   data->pwm_mode[nr])); \
156108c79950SRudolf Marek } \
156208c79950SRudolf Marek \
156308c79950SRudolf Marek static ssize_t \
156408c79950SRudolf Marek store_##reg(struct device *dev, struct device_attribute *attr, \
156508c79950SRudolf Marek 			const char *buf, size_t count) \
156608c79950SRudolf Marek { \
15671ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev); \
1568e7e1ca6eSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = \
1569e7e1ca6eSGuenter Roeck 		to_sensor_dev_attr(attr); \
157008c79950SRudolf Marek 	int nr = sensor_attr->index; \
1571bce26c58SGuenter Roeck 	unsigned long val; \
1572bce26c58SGuenter Roeck 	int err; \
1573bce26c58SGuenter Roeck 	err = strict_strtoul(buf, 10, &val); \
1574bce26c58SGuenter Roeck 	if (err < 0) \
1575bce26c58SGuenter Roeck 		return err; \
1576bce26c58SGuenter Roeck 	val = step_time_to_reg(val, data->pwm_mode[nr]); \
157708c79950SRudolf Marek 	mutex_lock(&data->update_lock); \
157808c79950SRudolf Marek 	data->reg[nr] = val; \
15791ea6dd38SDavid Hubbard 	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
158008c79950SRudolf Marek 	mutex_unlock(&data->update_lock); \
158108c79950SRudolf Marek 	return count; \
158208c79950SRudolf Marek } \
158308c79950SRudolf Marek 
158408c79950SRudolf Marek fan_time_functions(fan_stop_time, FAN_STOP_TIME)
158508c79950SRudolf Marek 
15861ea6dd38SDavid Hubbard static ssize_t show_name(struct device *dev, struct device_attribute *attr,
15871ea6dd38SDavid Hubbard 			 char *buf)
15881ea6dd38SDavid Hubbard {
15891ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
15901ea6dd38SDavid Hubbard 
15911ea6dd38SDavid Hubbard 	return sprintf(buf, "%s\n", data->name);
15921ea6dd38SDavid Hubbard }
15931ea6dd38SDavid Hubbard static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
159408c79950SRudolf Marek 
159508c79950SRudolf Marek static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
159608c79950SRudolf Marek 	SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
159708c79950SRudolf Marek 		    store_fan_stop_time, 3),
159841e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm4_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
159941e9a062SDaniel J Blueman 		    store_fan_start_output, 3),
160041e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm4_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
160141e9a062SDaniel J Blueman 		    store_fan_stop_output, 3),
160241e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm4_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
160341e9a062SDaniel J Blueman 		    store_fan_max_output, 3),
160441e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm4_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
160541e9a062SDaniel J Blueman 		    store_fan_step_output, 3),
160608c79950SRudolf Marek };
160708c79950SRudolf Marek 
160808c79950SRudolf Marek static struct sensor_device_attribute sda_sf3_arrays[] = {
160908c79950SRudolf Marek 	SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
161008c79950SRudolf Marek 		    store_fan_stop_time, 0),
161108c79950SRudolf Marek 	SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
161208c79950SRudolf Marek 		    store_fan_stop_time, 1),
161308c79950SRudolf Marek 	SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
161408c79950SRudolf Marek 		    store_fan_stop_time, 2),
161541e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm1_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
161641e9a062SDaniel J Blueman 		    store_fan_start_output, 0),
161741e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm2_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
161841e9a062SDaniel J Blueman 		    store_fan_start_output, 1),
161941e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm3_start_output, S_IWUSR | S_IRUGO, show_fan_start_output,
162041e9a062SDaniel J Blueman 		    store_fan_start_output, 2),
162141e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm1_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
162241e9a062SDaniel J Blueman 		    store_fan_stop_output, 0),
162341e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm2_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
162441e9a062SDaniel J Blueman 		    store_fan_stop_output, 1),
162541e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm3_stop_output, S_IWUSR | S_IRUGO, show_fan_stop_output,
162641e9a062SDaniel J Blueman 		    store_fan_stop_output, 2),
1627da2e0255SGuenter Roeck };
162841e9a062SDaniel J Blueman 
1629da2e0255SGuenter Roeck 
1630da2e0255SGuenter Roeck /*
1631da2e0255SGuenter Roeck  * pwm1 and pwm3 don't support max and step settings on all chips.
1632da2e0255SGuenter Roeck  * Need to check support while generating/removing attribute files.
1633da2e0255SGuenter Roeck  */
1634da2e0255SGuenter Roeck static struct sensor_device_attribute sda_sf3_max_step_arrays[] = {
1635da2e0255SGuenter Roeck 	SENSOR_ATTR(pwm1_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1636da2e0255SGuenter Roeck 		    store_fan_max_output, 0),
1637da2e0255SGuenter Roeck 	SENSOR_ATTR(pwm1_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1638da2e0255SGuenter Roeck 		    store_fan_step_output, 0),
163941e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm2_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
164041e9a062SDaniel J Blueman 		    store_fan_max_output, 1),
164141e9a062SDaniel J Blueman 	SENSOR_ATTR(pwm2_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
164241e9a062SDaniel J Blueman 		    store_fan_step_output, 1),
1643da2e0255SGuenter Roeck 	SENSOR_ATTR(pwm3_max_output, S_IWUSR | S_IRUGO, show_fan_max_output,
1644da2e0255SGuenter Roeck 		    store_fan_max_output, 2),
1645da2e0255SGuenter Roeck 	SENSOR_ATTR(pwm3_step_output, S_IWUSR | S_IRUGO, show_fan_step_output,
1646da2e0255SGuenter Roeck 		    store_fan_step_output, 2),
164708c79950SRudolf Marek };
164808c79950SRudolf Marek 
1649fc18d6c0SJean Delvare static ssize_t
1650fc18d6c0SJean Delvare show_vid(struct device *dev, struct device_attribute *attr, char *buf)
1651fc18d6c0SJean Delvare {
1652fc18d6c0SJean Delvare 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1653fc18d6c0SJean Delvare 	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
1654fc18d6c0SJean Delvare }
1655fc18d6c0SJean Delvare static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
1656fc18d6c0SJean Delvare 
165708e7e278SJean Delvare /*
16581ea6dd38SDavid Hubbard  * Driver and device management
165908e7e278SJean Delvare  */
166008e7e278SJean Delvare 
1661c18beb5bSDavid Hubbard static void w83627ehf_device_remove_files(struct device *dev)
1662c18beb5bSDavid Hubbard {
1663c18beb5bSDavid Hubbard 	/* some entries in the following arrays may not have been used in
1664c18beb5bSDavid Hubbard 	 * device_create_file(), but device_remove_file() will ignore them */
1665c18beb5bSDavid Hubbard 	int i;
16661ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = dev_get_drvdata(dev);
1667c18beb5bSDavid Hubbard 
1668c18beb5bSDavid Hubbard 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
1669c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
1670da2e0255SGuenter Roeck 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
1671da2e0255SGuenter Roeck 		struct sensor_device_attribute *attr =
1672da2e0255SGuenter Roeck 		  &sda_sf3_max_step_arrays[i];
1673ec3e5a16SGuenter Roeck 		if (data->REG_FAN_STEP_OUTPUT &&
1674ec3e5a16SGuenter Roeck 		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff)
1675da2e0255SGuenter Roeck 			device_remove_file(dev, &attr->dev_attr);
1676da2e0255SGuenter Roeck 	}
1677c18beb5bSDavid Hubbard 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
1678c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
16791ea6dd38SDavid Hubbard 	for (i = 0; i < data->in_num; i++) {
1680a157d06dSGong Jun 		if ((i == 6) && data->in6_skip)
1681a157d06dSGong Jun 			continue;
1682c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_in_input[i].dev_attr);
1683c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_in_alarm[i].dev_attr);
1684c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_in_min[i].dev_attr);
1685c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_in_max[i].dev_attr);
1686c18beb5bSDavid Hubbard 	}
1687c18beb5bSDavid Hubbard 	for (i = 0; i < 5; i++) {
1688c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_fan_input[i].dev_attr);
1689c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
1690c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_fan_div[i].dev_attr);
1691c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_fan_min[i].dev_attr);
1692c18beb5bSDavid Hubbard 	}
1693237c8d2fSGong Jun 	for (i = 0; i < data->pwm_num; i++) {
1694c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_pwm[i].dev_attr);
1695c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
1696c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
1697c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_target_temp[i].dev_attr);
1698c18beb5bSDavid Hubbard 		device_remove_file(dev, &sda_tolerance[i].dev_attr);
1699c18beb5bSDavid Hubbard 	}
1700d36cf32cSGuenter Roeck 	for (i = 0; i < NUM_REG_TEMP; i++) {
1701d36cf32cSGuenter Roeck 		if (!(data->have_temp & (1 << i)))
1702a157d06dSGong Jun 			continue;
1703a157d06dSGong Jun 		device_remove_file(dev, &sda_temp_input[i].dev_attr);
1704d36cf32cSGuenter Roeck 		device_remove_file(dev, &sda_temp_label[i].dev_attr);
1705a157d06dSGong Jun 		device_remove_file(dev, &sda_temp_max[i].dev_attr);
1706a157d06dSGong Jun 		device_remove_file(dev, &sda_temp_max_hyst[i].dev_attr);
1707ec3e5a16SGuenter Roeck 		if (i > 2)
1708ec3e5a16SGuenter Roeck 			continue;
1709a157d06dSGong Jun 		device_remove_file(dev, &sda_temp_alarm[i].dev_attr);
1710a157d06dSGong Jun 		device_remove_file(dev, &sda_temp_type[i].dev_attr);
1711a157d06dSGong Jun 	}
17121ea6dd38SDavid Hubbard 
17131ea6dd38SDavid Hubbard 	device_remove_file(dev, &dev_attr_name);
1714fc18d6c0SJean Delvare 	device_remove_file(dev, &dev_attr_cpu0_vid);
1715c18beb5bSDavid Hubbard }
1716c18beb5bSDavid Hubbard 
17171ea6dd38SDavid Hubbard /* Get the monitoring functions started */
1718*bf164c58SJean Delvare static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data,
1719*bf164c58SJean Delvare 						   enum kinds kind)
172008e7e278SJean Delvare {
172108e7e278SJean Delvare 	int i;
1722da667365SJean Delvare 	u8 tmp, diode;
172308e7e278SJean Delvare 
172408e7e278SJean Delvare 	/* Start monitoring is needed */
17251ea6dd38SDavid Hubbard 	tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
172608e7e278SJean Delvare 	if (!(tmp & 0x01))
17271ea6dd38SDavid Hubbard 		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
172808e7e278SJean Delvare 				      tmp | 0x01);
172908e7e278SJean Delvare 
1730d36cf32cSGuenter Roeck 	/* Enable temperature sensors if needed */
1731d36cf32cSGuenter Roeck 	for (i = 0; i < NUM_REG_TEMP; i++) {
1732d36cf32cSGuenter Roeck 		if (!(data->have_temp & (1 << i)))
1733d36cf32cSGuenter Roeck 			continue;
1734ec3e5a16SGuenter Roeck 		if (!data->reg_temp_config[i])
1735d36cf32cSGuenter Roeck 			continue;
17361ea6dd38SDavid Hubbard 		tmp = w83627ehf_read_value(data,
1737ec3e5a16SGuenter Roeck 					   data->reg_temp_config[i]);
173808e7e278SJean Delvare 		if (tmp & 0x01)
17391ea6dd38SDavid Hubbard 			w83627ehf_write_value(data,
1740ec3e5a16SGuenter Roeck 					      data->reg_temp_config[i],
174108e7e278SJean Delvare 					      tmp & 0xfe);
174208e7e278SJean Delvare 	}
1743d3130f0eSJean Delvare 
1744d3130f0eSJean Delvare 	/* Enable VBAT monitoring if needed */
1745d3130f0eSJean Delvare 	tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
1746d3130f0eSJean Delvare 	if (!(tmp & 0x01))
1747d3130f0eSJean Delvare 		w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
1748da667365SJean Delvare 
1749da667365SJean Delvare 	/* Get thermal sensor types */
1750*bf164c58SJean Delvare 	switch (kind) {
1751*bf164c58SJean Delvare 	case w83627ehf:
1752da667365SJean Delvare 		diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
1753*bf164c58SJean Delvare 		break;
1754*bf164c58SJean Delvare 	default:
1755*bf164c58SJean Delvare 		diode = 0x70;
1756*bf164c58SJean Delvare 	}
1757da667365SJean Delvare 	for (i = 0; i < 3; i++) {
1758da667365SJean Delvare 		if ((tmp & (0x02 << i)))
1759*bf164c58SJean Delvare 			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3;
1760da667365SJean Delvare 		else
1761da667365SJean Delvare 			data->temp_type[i] = 4; /* thermistor */
1762da667365SJean Delvare 	}
176308e7e278SJean Delvare }
176408e7e278SJean Delvare 
1765ec3e5a16SGuenter Roeck static void w82627ehf_swap_tempreg(struct w83627ehf_data *data,
1766ec3e5a16SGuenter Roeck 				   int r1, int r2)
1767ec3e5a16SGuenter Roeck {
1768ec3e5a16SGuenter Roeck 	u16 tmp;
1769ec3e5a16SGuenter Roeck 
1770ec3e5a16SGuenter Roeck 	tmp = data->temp_src[r1];
1771ec3e5a16SGuenter Roeck 	data->temp_src[r1] = data->temp_src[r2];
1772ec3e5a16SGuenter Roeck 	data->temp_src[r2] = tmp;
1773ec3e5a16SGuenter Roeck 
1774ec3e5a16SGuenter Roeck 	tmp = data->reg_temp[r1];
1775ec3e5a16SGuenter Roeck 	data->reg_temp[r1] = data->reg_temp[r2];
1776ec3e5a16SGuenter Roeck 	data->reg_temp[r2] = tmp;
1777ec3e5a16SGuenter Roeck 
1778ec3e5a16SGuenter Roeck 	tmp = data->reg_temp_over[r1];
1779ec3e5a16SGuenter Roeck 	data->reg_temp_over[r1] = data->reg_temp_over[r2];
1780ec3e5a16SGuenter Roeck 	data->reg_temp_over[r2] = tmp;
1781ec3e5a16SGuenter Roeck 
1782ec3e5a16SGuenter Roeck 	tmp = data->reg_temp_hyst[r1];
1783ec3e5a16SGuenter Roeck 	data->reg_temp_hyst[r1] = data->reg_temp_hyst[r2];
1784ec3e5a16SGuenter Roeck 	data->reg_temp_hyst[r2] = tmp;
1785ec3e5a16SGuenter Roeck 
1786ec3e5a16SGuenter Roeck 	tmp = data->reg_temp_config[r1];
1787ec3e5a16SGuenter Roeck 	data->reg_temp_config[r1] = data->reg_temp_config[r2];
1788ec3e5a16SGuenter Roeck 	data->reg_temp_config[r2] = tmp;
1789ec3e5a16SGuenter Roeck }
1790ec3e5a16SGuenter Roeck 
17911ea6dd38SDavid Hubbard static int __devinit w83627ehf_probe(struct platform_device *pdev)
179208e7e278SJean Delvare {
17931ea6dd38SDavid Hubbard 	struct device *dev = &pdev->dev;
17941ea6dd38SDavid Hubbard 	struct w83627ehf_sio_data *sio_data = dev->platform_data;
179508e7e278SJean Delvare 	struct w83627ehf_data *data;
17961ea6dd38SDavid Hubbard 	struct resource *res;
1797ec3e5a16SGuenter Roeck 	u8 fan3pin, fan4pin, fan4min, fan5pin, en_vrm10;
179808e7e278SJean Delvare 	int i, err = 0;
179908e7e278SJean Delvare 
18001ea6dd38SDavid Hubbard 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
18011ea6dd38SDavid Hubbard 	if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
180208e7e278SJean Delvare 		err = -EBUSY;
18031ea6dd38SDavid Hubbard 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
18041ea6dd38SDavid Hubbard 			(unsigned long)res->start,
18051ea6dd38SDavid Hubbard 			(unsigned long)res->start + IOREGION_LENGTH - 1);
180608e7e278SJean Delvare 		goto exit;
180708e7e278SJean Delvare 	}
180808e7e278SJean Delvare 
1809e7e1ca6eSGuenter Roeck 	data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL);
1810e7e1ca6eSGuenter Roeck 	if (!data) {
181108e7e278SJean Delvare 		err = -ENOMEM;
181208e7e278SJean Delvare 		goto exit_release;
181308e7e278SJean Delvare 	}
181408e7e278SJean Delvare 
18151ea6dd38SDavid Hubbard 	data->addr = res->start;
18169a61bf63SIngo Molnar 	mutex_init(&data->lock);
18179a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
18181ea6dd38SDavid Hubbard 	data->name = w83627ehf_device_names[sio_data->kind];
18191ea6dd38SDavid Hubbard 	platform_set_drvdata(pdev, data);
182008e7e278SJean Delvare 
1821237c8d2fSGong Jun 	/* 627EHG and 627EHF have 10 voltage inputs; 627DHG and 667HG have 9 */
1822237c8d2fSGong Jun 	data->in_num = (sio_data->kind == w83627ehf) ? 10 : 9;
1823ec3e5a16SGuenter Roeck 	/* 667HG, NCT6775F, and NCT6776F have 3 pwms */
1824c39aedafSGuenter Roeck 	data->pwm_num = (sio_data->kind == w83667hg
1825ec3e5a16SGuenter Roeck 			 || sio_data->kind == w83667hg_b
1826ec3e5a16SGuenter Roeck 			 || sio_data->kind == nct6775
1827ec3e5a16SGuenter Roeck 			 || sio_data->kind == nct6776) ? 3 : 4;
182808e7e278SJean Delvare 
1829d36cf32cSGuenter Roeck 	data->have_temp = 0x07;
1830a157d06dSGong Jun 	/* Check temp3 configuration bit for 667HG */
1831d36cf32cSGuenter Roeck 	if (sio_data->kind == w83667hg) {
1832d36cf32cSGuenter Roeck 		u8 reg;
1833d36cf32cSGuenter Roeck 
1834d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1835d36cf32cSGuenter Roeck 		if (reg & 0x01)
1836d36cf32cSGuenter Roeck 			data->have_temp &= ~(1 << 2);
1837d36cf32cSGuenter Roeck 		else
1838ec3e5a16SGuenter Roeck 			data->in6_skip = 1;	/* either temp3 or in6 */
1839ec3e5a16SGuenter Roeck 	}
1840ec3e5a16SGuenter Roeck 
1841ec3e5a16SGuenter Roeck 	/* Deal with temperature register setup first. */
1842ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
1843ec3e5a16SGuenter Roeck 		int mask = 0;
1844ec3e5a16SGuenter Roeck 
1845ec3e5a16SGuenter Roeck 		/*
1846ec3e5a16SGuenter Roeck 		 * Display temperature sensor output only if it monitors
1847ec3e5a16SGuenter Roeck 		 * a source other than one already reported. Always display
1848ec3e5a16SGuenter Roeck 		 * first three temperature registers, though.
1849ec3e5a16SGuenter Roeck 		 */
1850ec3e5a16SGuenter Roeck 		for (i = 0; i < NUM_REG_TEMP; i++) {
1851ec3e5a16SGuenter Roeck 			u8 src;
1852ec3e5a16SGuenter Roeck 
1853ec3e5a16SGuenter Roeck 			data->reg_temp[i] = NCT6775_REG_TEMP[i];
1854ec3e5a16SGuenter Roeck 			data->reg_temp_over[i] = NCT6775_REG_TEMP_OVER[i];
1855ec3e5a16SGuenter Roeck 			data->reg_temp_hyst[i] = NCT6775_REG_TEMP_HYST[i];
1856ec3e5a16SGuenter Roeck 			data->reg_temp_config[i] = NCT6775_REG_TEMP_CONFIG[i];
1857ec3e5a16SGuenter Roeck 
1858ec3e5a16SGuenter Roeck 			src = w83627ehf_read_value(data,
1859ec3e5a16SGuenter Roeck 						   NCT6775_REG_TEMP_SOURCE[i]);
1860ec3e5a16SGuenter Roeck 			src &= 0x1f;
1861ec3e5a16SGuenter Roeck 			if (src && !(mask & (1 << src))) {
1862ec3e5a16SGuenter Roeck 				data->have_temp |= 1 << i;
1863ec3e5a16SGuenter Roeck 				mask |= 1 << src;
1864ec3e5a16SGuenter Roeck 			}
1865ec3e5a16SGuenter Roeck 
1866ec3e5a16SGuenter Roeck 			data->temp_src[i] = src;
1867ec3e5a16SGuenter Roeck 
1868ec3e5a16SGuenter Roeck 			/*
1869ec3e5a16SGuenter Roeck 			 * Now do some register swapping if index 0..2 don't
1870ec3e5a16SGuenter Roeck 			 * point to SYSTIN(1), CPUIN(2), and AUXIN(3).
1871ec3e5a16SGuenter Roeck 			 * Idea is to have the first three attributes
1872ec3e5a16SGuenter Roeck 			 * report SYSTIN, CPUIN, and AUXIN if possible
1873ec3e5a16SGuenter Roeck 			 * without overriding the basic system configuration.
1874ec3e5a16SGuenter Roeck 			 */
1875ec3e5a16SGuenter Roeck 			if (i > 0 && data->temp_src[0] != 1
1876ec3e5a16SGuenter Roeck 			    && data->temp_src[i] == 1)
1877ec3e5a16SGuenter Roeck 				w82627ehf_swap_tempreg(data, 0, i);
1878ec3e5a16SGuenter Roeck 			if (i > 1 && data->temp_src[1] != 2
1879ec3e5a16SGuenter Roeck 			    && data->temp_src[i] == 2)
1880ec3e5a16SGuenter Roeck 				w82627ehf_swap_tempreg(data, 1, i);
1881ec3e5a16SGuenter Roeck 			if (i > 2 && data->temp_src[2] != 3
1882ec3e5a16SGuenter Roeck 			    && data->temp_src[i] == 3)
1883ec3e5a16SGuenter Roeck 				w82627ehf_swap_tempreg(data, 2, i);
1884ec3e5a16SGuenter Roeck 		}
1885ec3e5a16SGuenter Roeck 		if (sio_data->kind == nct6776) {
1886ec3e5a16SGuenter Roeck 			/*
1887ec3e5a16SGuenter Roeck 			 * On NCT6776, AUXTIN and VIN3 pins are shared.
1888ec3e5a16SGuenter Roeck 			 * Only way to detect it is to check if AUXTIN is used
1889ec3e5a16SGuenter Roeck 			 * as a temperature source, and if that source is
1890ec3e5a16SGuenter Roeck 			 * enabled.
1891ec3e5a16SGuenter Roeck 			 *
1892ec3e5a16SGuenter Roeck 			 * If that is the case, disable in6, which reports VIN3.
1893ec3e5a16SGuenter Roeck 			 * Otherwise disable temp3.
1894ec3e5a16SGuenter Roeck 			 */
1895ec3e5a16SGuenter Roeck 			if (data->temp_src[2] == 3) {
1896ec3e5a16SGuenter Roeck 				u8 reg;
1897ec3e5a16SGuenter Roeck 
1898ec3e5a16SGuenter Roeck 				if (data->reg_temp_config[2])
1899ec3e5a16SGuenter Roeck 					reg = w83627ehf_read_value(data,
1900ec3e5a16SGuenter Roeck 						data->reg_temp_config[2]);
1901ec3e5a16SGuenter Roeck 				else
1902ec3e5a16SGuenter Roeck 					reg = 0; /* Assume AUXTIN is used */
1903ec3e5a16SGuenter Roeck 
1904ec3e5a16SGuenter Roeck 				if (reg & 0x01)
1905ec3e5a16SGuenter Roeck 					data->have_temp &= ~(1 << 2);
1906ec3e5a16SGuenter Roeck 				else
1907ec3e5a16SGuenter Roeck 					data->in6_skip = 1;
1908ec3e5a16SGuenter Roeck 			}
1909ec3e5a16SGuenter Roeck 			data->temp_label = nct6776_temp_label;
191002309ad2SGuenter Roeck 		} else {
191102309ad2SGuenter Roeck 			data->temp_label = nct6775_temp_label;
191202309ad2SGuenter Roeck 		}
1913d36cf32cSGuenter Roeck 	} else if (sio_data->kind == w83667hg_b) {
1914d36cf32cSGuenter Roeck 		u8 reg;
1915d36cf32cSGuenter Roeck 
1916ec3e5a16SGuenter Roeck 		/*
1917ec3e5a16SGuenter Roeck 		 * Temperature sources are selected with bank 0, registers 0x49
1918ec3e5a16SGuenter Roeck 		 * and 0x4a.
1919ec3e5a16SGuenter Roeck 		 */
1920ec3e5a16SGuenter Roeck 		for (i = 0; i < ARRAY_SIZE(W83627EHF_REG_TEMP); i++) {
1921ec3e5a16SGuenter Roeck 			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1922ec3e5a16SGuenter Roeck 			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1923ec3e5a16SGuenter Roeck 			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1924ec3e5a16SGuenter Roeck 			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1925ec3e5a16SGuenter Roeck 		}
1926d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x4a);
1927d36cf32cSGuenter Roeck 		data->temp_src[0] = reg >> 5;
1928d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x49);
1929d36cf32cSGuenter Roeck 		data->temp_src[1] = reg & 0x07;
1930d36cf32cSGuenter Roeck 		data->temp_src[2] = (reg >> 4) & 0x07;
1931d36cf32cSGuenter Roeck 
1932d36cf32cSGuenter Roeck 		/*
1933d36cf32cSGuenter Roeck 		 * W83667HG-B has another temperature register at 0x7e.
1934d36cf32cSGuenter Roeck 		 * The temperature source is selected with register 0x7d.
1935d36cf32cSGuenter Roeck 		 * Support it if the source differs from already reported
1936d36cf32cSGuenter Roeck 		 * sources.
1937d36cf32cSGuenter Roeck 		 */
1938d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, 0x7d);
1939d36cf32cSGuenter Roeck 		reg &= 0x07;
1940d36cf32cSGuenter Roeck 		if (reg != data->temp_src[0] && reg != data->temp_src[1]
1941d36cf32cSGuenter Roeck 		    && reg != data->temp_src[2]) {
1942d36cf32cSGuenter Roeck 			data->temp_src[3] = reg;
1943d36cf32cSGuenter Roeck 			data->have_temp |= 1 << 3;
1944d36cf32cSGuenter Roeck 		}
1945d36cf32cSGuenter Roeck 
1946d36cf32cSGuenter Roeck 		/*
1947d36cf32cSGuenter Roeck 		 * Chip supports either AUXTIN or VIN3. Try to find out which
1948d36cf32cSGuenter Roeck 		 * one.
1949d36cf32cSGuenter Roeck 		 */
1950d36cf32cSGuenter Roeck 		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
1951d36cf32cSGuenter Roeck 		if (data->temp_src[2] == 2 && (reg & 0x01))
1952d36cf32cSGuenter Roeck 			data->have_temp &= ~(1 << 2);
1953d36cf32cSGuenter Roeck 
1954d36cf32cSGuenter Roeck 		if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
1955d36cf32cSGuenter Roeck 		    || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
1956d36cf32cSGuenter Roeck 			data->in6_skip = 1;
1957d36cf32cSGuenter Roeck 
1958d36cf32cSGuenter Roeck 		data->temp_label = w83667hg_b_temp_label;
1959ec3e5a16SGuenter Roeck 	} else {
1960ec3e5a16SGuenter Roeck 		/* Temperature sources are fixed */
1961ec3e5a16SGuenter Roeck 		for (i = 0; i < 3; i++) {
1962ec3e5a16SGuenter Roeck 			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
1963ec3e5a16SGuenter Roeck 			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
1964ec3e5a16SGuenter Roeck 			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
1965ec3e5a16SGuenter Roeck 			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
1966ec3e5a16SGuenter Roeck 		}
1967a157d06dSGong Jun 	}
1968a157d06dSGong Jun 
1969ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775) {
197026bc440eSGuenter Roeck 		data->has_fan_div = true;
197126bc440eSGuenter Roeck 		data->fan_from_reg = fan_from_reg16;
197226bc440eSGuenter Roeck 		data->fan_from_reg_min = fan_from_reg8;
1973ec3e5a16SGuenter Roeck 		data->REG_PWM = NCT6775_REG_PWM;
1974ec3e5a16SGuenter Roeck 		data->REG_TARGET = NCT6775_REG_TARGET;
197526bc440eSGuenter Roeck 		data->REG_FAN = NCT6775_REG_FAN;
1976ec3e5a16SGuenter Roeck 		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
1977ec3e5a16SGuenter Roeck 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1978ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1979ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1980ec3e5a16SGuenter Roeck 		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
1981ec3e5a16SGuenter Roeck 		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
1982ec3e5a16SGuenter Roeck 	} else if (sio_data->kind == nct6776) {
198326bc440eSGuenter Roeck 		data->has_fan_div = false;
198426bc440eSGuenter Roeck 		data->fan_from_reg = fan_from_reg13;
198526bc440eSGuenter Roeck 		data->fan_from_reg_min = fan_from_reg13;
1986ec3e5a16SGuenter Roeck 		data->REG_PWM = NCT6775_REG_PWM;
1987ec3e5a16SGuenter Roeck 		data->REG_TARGET = NCT6775_REG_TARGET;
198826bc440eSGuenter Roeck 		data->REG_FAN = NCT6775_REG_FAN;
1989ec3e5a16SGuenter Roeck 		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
1990ec3e5a16SGuenter Roeck 		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
1991ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
1992ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
1993ec3e5a16SGuenter Roeck 	} else if (sio_data->kind == w83667hg_b) {
199426bc440eSGuenter Roeck 		data->has_fan_div = true;
199526bc440eSGuenter Roeck 		data->fan_from_reg = fan_from_reg8;
199626bc440eSGuenter Roeck 		data->fan_from_reg_min = fan_from_reg8;
1997279af1a9SGuenter Roeck 		data->REG_PWM = W83627EHF_REG_PWM;
1998279af1a9SGuenter Roeck 		data->REG_TARGET = W83627EHF_REG_TARGET;
1999279af1a9SGuenter Roeck 		data->REG_FAN = W83627EHF_REG_FAN;
2000279af1a9SGuenter Roeck 		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
2001da2e0255SGuenter Roeck 		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
2002da2e0255SGuenter Roeck 		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
2003279af1a9SGuenter Roeck 		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
2004c39aedafSGuenter Roeck 		data->REG_FAN_MAX_OUTPUT =
2005c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
2006c39aedafSGuenter Roeck 		data->REG_FAN_STEP_OUTPUT =
2007c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
2008c39aedafSGuenter Roeck 	} else {
200926bc440eSGuenter Roeck 		data->has_fan_div = true;
201026bc440eSGuenter Roeck 		data->fan_from_reg = fan_from_reg8;
201126bc440eSGuenter Roeck 		data->fan_from_reg_min = fan_from_reg8;
2012ec3e5a16SGuenter Roeck 		data->REG_PWM = W83627EHF_REG_PWM;
2013ec3e5a16SGuenter Roeck 		data->REG_TARGET = W83627EHF_REG_TARGET;
2014ec3e5a16SGuenter Roeck 		data->REG_FAN = W83627EHF_REG_FAN;
2015ec3e5a16SGuenter Roeck 		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
2016ec3e5a16SGuenter Roeck 		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
2017ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
2018ec3e5a16SGuenter Roeck 		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
2019c39aedafSGuenter Roeck 		data->REG_FAN_MAX_OUTPUT =
2020c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
2021c39aedafSGuenter Roeck 		data->REG_FAN_STEP_OUTPUT =
2022c39aedafSGuenter Roeck 		  W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
2023c39aedafSGuenter Roeck 	}
2024da2e0255SGuenter Roeck 
202508e7e278SJean Delvare 	/* Initialize the chip */
2026*bf164c58SJean Delvare 	w83627ehf_init_device(data, sio_data->kind);
202708e7e278SJean Delvare 
2028fc18d6c0SJean Delvare 	data->vrm = vid_which_vrm();
2029fc18d6c0SJean Delvare 	superio_enter(sio_data->sioreg);
203058e6e781SJean Delvare 	/* Read VID value */
2031ec3e5a16SGuenter Roeck 	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
2032ec3e5a16SGuenter Roeck 	    sio_data->kind == nct6775 || sio_data->kind == nct6776) {
2033237c8d2fSGong Jun 		/* W83667HG has different pins for VID input and output, so
2034237c8d2fSGong Jun 		we can get the VID input values directly at logical device D
2035237c8d2fSGong Jun 		0xe3. */
2036237c8d2fSGong Jun 		superio_select(sio_data->sioreg, W83667HG_LD_VID);
2037237c8d2fSGong Jun 		data->vid = superio_inb(sio_data->sioreg, 0xe3);
2038237c8d2fSGong Jun 		err = device_create_file(dev, &dev_attr_cpu0_vid);
2039237c8d2fSGong Jun 		if (err)
2040237c8d2fSGong Jun 			goto exit_release;
2041237c8d2fSGong Jun 	} else {
204258e6e781SJean Delvare 		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
204358e6e781SJean Delvare 		if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {
2044237c8d2fSGong Jun 			/* Set VID input sensibility if needed. In theory the
2045237c8d2fSGong Jun 			   BIOS should have set it, but in practice it's not
2046237c8d2fSGong Jun 			   always the case. We only do it for the W83627EHF/EHG
2047237c8d2fSGong Jun 			   because the W83627DHG is more complex in this
2048237c8d2fSGong Jun 			   respect. */
204958e6e781SJean Delvare 			if (sio_data->kind == w83627ehf) {
205058e6e781SJean Delvare 				en_vrm10 = superio_inb(sio_data->sioreg,
205158e6e781SJean Delvare 						       SIO_REG_EN_VRM10);
205258e6e781SJean Delvare 				if ((en_vrm10 & 0x08) && data->vrm == 90) {
2053237c8d2fSGong Jun 					dev_warn(dev, "Setting VID input "
2054237c8d2fSGong Jun 						 "voltage to TTL\n");
2055237c8d2fSGong Jun 					superio_outb(sio_data->sioreg,
2056237c8d2fSGong Jun 						     SIO_REG_EN_VRM10,
2057fc18d6c0SJean Delvare 						     en_vrm10 & ~0x08);
2058237c8d2fSGong Jun 				} else if (!(en_vrm10 & 0x08)
2059237c8d2fSGong Jun 					   && data->vrm == 100) {
2060237c8d2fSGong Jun 					dev_warn(dev, "Setting VID input "
2061237c8d2fSGong Jun 						 "voltage to VRM10\n");
2062237c8d2fSGong Jun 					superio_outb(sio_data->sioreg,
2063237c8d2fSGong Jun 						     SIO_REG_EN_VRM10,
2064fc18d6c0SJean Delvare 						     en_vrm10 | 0x08);
2065fc18d6c0SJean Delvare 				}
206658e6e781SJean Delvare 			}
206758e6e781SJean Delvare 
2068237c8d2fSGong Jun 			data->vid = superio_inb(sio_data->sioreg,
2069237c8d2fSGong Jun 						SIO_REG_VID_DATA);
2070cbe311f2SJean Delvare 			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
2071cbe311f2SJean Delvare 				data->vid &= 0x3f;
2072cbe311f2SJean Delvare 
2073cbe311f2SJean Delvare 			err = device_create_file(dev, &dev_attr_cpu0_vid);
2074cbe311f2SJean Delvare 			if (err)
2075cbe311f2SJean Delvare 				goto exit_release;
207658e6e781SJean Delvare 		} else {
2077fc18d6c0SJean Delvare 			dev_info(dev, "VID pins in output mode, CPU VID not "
2078fc18d6c0SJean Delvare 				 "available\n");
2079fc18d6c0SJean Delvare 		}
2080237c8d2fSGong Jun 	}
2081fc18d6c0SJean Delvare 
208208c79950SRudolf Marek 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
2083ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775) {
2084ec3e5a16SGuenter Roeck 		/* On NCT6775, fan4 shares pins with the fdc interface */
2085ec3e5a16SGuenter Roeck 		fan3pin = 1;
2086ec3e5a16SGuenter Roeck 		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
2087ec3e5a16SGuenter Roeck 		fan4min = 0;
2088ec3e5a16SGuenter Roeck 		fan5pin = 0;
2089ec3e5a16SGuenter Roeck 	} else if (sio_data->kind == nct6776) {
2090ec3e5a16SGuenter Roeck 		fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
2091ec3e5a16SGuenter Roeck 		fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
2092ec3e5a16SGuenter Roeck 		fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
2093ec3e5a16SGuenter Roeck 		fan4min = fan4pin;
2094ec3e5a16SGuenter Roeck 	} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
2095ec3e5a16SGuenter Roeck 		fan3pin = 1;
2096237c8d2fSGong Jun 		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
2097ec3e5a16SGuenter Roeck 		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
2098ec3e5a16SGuenter Roeck 		fan4min = fan4pin;
2099237c8d2fSGong Jun 	} else {
2100ec3e5a16SGuenter Roeck 		fan3pin = 1;
2101237c8d2fSGong Jun 		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
2102ec3e5a16SGuenter Roeck 		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
2103ec3e5a16SGuenter Roeck 		fan4min = fan4pin;
2104237c8d2fSGong Jun 	}
2105d42e869aSIan Dobson 
2106d42e869aSIan Dobson 	if (fan_debounce &&
2107d42e869aSIan Dobson 	    (sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
2108d42e869aSIan Dobson 		u8 tmp;
2109d42e869aSIan Dobson 
2110d42e869aSIan Dobson 		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
2111d42e869aSIan Dobson 		tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE);
2112d42e869aSIan Dobson 		if (sio_data->kind == nct6776)
2113d42e869aSIan Dobson 			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
2114d42e869aSIan Dobson 				     0x3e | tmp);
2115d42e869aSIan Dobson 		else
2116d42e869aSIan Dobson 			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
2117d42e869aSIan Dobson 				     0x1e | tmp);
2118d42e869aSIan Dobson 		pr_info("Enabled fan debounce for chip %s\n", data->name);
2119d42e869aSIan Dobson 	}
2120d42e869aSIan Dobson 
21211ea6dd38SDavid Hubbard 	superio_exit(sio_data->sioreg);
212208c79950SRudolf Marek 
212308e7e278SJean Delvare 	/* It looks like fan4 and fan5 pins can be alternatively used
212414992c7eSRudolf Marek 	   as fan on/off switches, but fan5 control is write only :/
212514992c7eSRudolf Marek 	   We assume that if the serial interface is disabled, designers
212614992c7eSRudolf Marek 	   connected fan5 as input unless they are emitting log 1, which
212714992c7eSRudolf Marek 	   is not the default. */
212808c79950SRudolf Marek 
2129ec3e5a16SGuenter Roeck 	data->has_fan = data->has_fan_min = 0x03; /* fan1 and fan2 */
2130ec3e5a16SGuenter Roeck 
2131ec3e5a16SGuenter Roeck 	data->has_fan |= (fan3pin << 2);
2132ec3e5a16SGuenter Roeck 	data->has_fan_min |= (fan3pin << 2);
2133ec3e5a16SGuenter Roeck 
2134ec3e5a16SGuenter Roeck 	/*
2135ec3e5a16SGuenter Roeck 	 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
2136ec3e5a16SGuenter Roeck 	 */
2137ec3e5a16SGuenter Roeck 	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
2138ec3e5a16SGuenter Roeck 		data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
2139ec3e5a16SGuenter Roeck 		data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
2140ec3e5a16SGuenter Roeck 	} else {
21411ea6dd38SDavid Hubbard 		i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
2142ec3e5a16SGuenter Roeck 		if ((i & (1 << 2)) && fan4pin) {
214308e7e278SJean Delvare 			data->has_fan |= (1 << 3);
2144ec3e5a16SGuenter Roeck 			data->has_fan_min |= (1 << 3);
2145ec3e5a16SGuenter Roeck 		}
2146ec3e5a16SGuenter Roeck 		if (!(i & (1 << 1)) && fan5pin) {
214708e7e278SJean Delvare 			data->has_fan |= (1 << 4);
2148ec3e5a16SGuenter Roeck 			data->has_fan_min |= (1 << 4);
2149ec3e5a16SGuenter Roeck 		}
2150ec3e5a16SGuenter Roeck 	}
215108e7e278SJean Delvare 
2152ea7be66cSMark M. Hoffman 	/* Read fan clock dividers immediately */
2153ec3e5a16SGuenter Roeck 	w83627ehf_update_fan_div_common(dev, data);
2154ec3e5a16SGuenter Roeck 
2155ec3e5a16SGuenter Roeck 	/* Read pwm data to save original values */
2156ec3e5a16SGuenter Roeck 	w83627ehf_update_pwm_common(dev, data);
2157ec3e5a16SGuenter Roeck 	for (i = 0; i < data->pwm_num; i++)
2158ec3e5a16SGuenter Roeck 		data->pwm_enable_orig[i] = data->pwm_enable[i];
2159ea7be66cSMark M. Hoffman 
2160b84bb518SGuenter Roeck 	/* Read pwm data to save original values */
2161b84bb518SGuenter Roeck 	w83627ehf_update_pwm_common(dev, data);
2162b84bb518SGuenter Roeck 	for (i = 0; i < data->pwm_num; i++)
2163b84bb518SGuenter Roeck 		data->pwm_enable_orig[i] = data->pwm_enable[i];
2164b84bb518SGuenter Roeck 
216508e7e278SJean Delvare 	/* Register sysfs hooks */
2166e7e1ca6eSGuenter Roeck 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
2167e7e1ca6eSGuenter Roeck 		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
2168e7e1ca6eSGuenter Roeck 		if (err)
2169c18beb5bSDavid Hubbard 			goto exit_remove;
2170e7e1ca6eSGuenter Roeck 	}
217108c79950SRudolf Marek 
2172da2e0255SGuenter Roeck 	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
2173da2e0255SGuenter Roeck 		struct sensor_device_attribute *attr =
2174da2e0255SGuenter Roeck 		  &sda_sf3_max_step_arrays[i];
2175ec3e5a16SGuenter Roeck 		if (data->REG_FAN_STEP_OUTPUT &&
2176ec3e5a16SGuenter Roeck 		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
2177da2e0255SGuenter Roeck 			err = device_create_file(dev, &attr->dev_attr);
2178da2e0255SGuenter Roeck 			if (err)
2179da2e0255SGuenter Roeck 				goto exit_remove;
2180da2e0255SGuenter Roeck 		}
2181da2e0255SGuenter Roeck 	}
218208c79950SRudolf Marek 	/* if fan4 is enabled create the sf3 files for it */
2183237c8d2fSGong Jun 	if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
2184c18beb5bSDavid Hubbard 		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
2185e7e1ca6eSGuenter Roeck 			err = device_create_file(dev,
2186e7e1ca6eSGuenter Roeck 					&sda_sf3_arrays_fan4[i].dev_attr);
2187e7e1ca6eSGuenter Roeck 			if (err)
2188c18beb5bSDavid Hubbard 				goto exit_remove;
2189c18beb5bSDavid Hubbard 		}
219008c79950SRudolf Marek 
2191a157d06dSGong Jun 	for (i = 0; i < data->in_num; i++) {
2192a157d06dSGong Jun 		if ((i == 6) && data->in6_skip)
2193a157d06dSGong Jun 			continue;
2194c18beb5bSDavid Hubbard 		if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
2195c18beb5bSDavid Hubbard 			|| (err = device_create_file(dev,
2196c18beb5bSDavid Hubbard 				&sda_in_alarm[i].dev_attr))
2197c18beb5bSDavid Hubbard 			|| (err = device_create_file(dev,
2198c18beb5bSDavid Hubbard 				&sda_in_min[i].dev_attr))
2199c18beb5bSDavid Hubbard 			|| (err = device_create_file(dev,
2200c18beb5bSDavid Hubbard 				&sda_in_max[i].dev_attr)))
2201c18beb5bSDavid Hubbard 			goto exit_remove;
2202a157d06dSGong Jun 	}
2203cf0676feSRudolf Marek 
2204412fec82SYuan Mu 	for (i = 0; i < 5; i++) {
220508c79950SRudolf Marek 		if (data->has_fan & (1 << i)) {
2206c18beb5bSDavid Hubbard 			if ((err = device_create_file(dev,
2207c18beb5bSDavid Hubbard 					&sda_fan_input[i].dev_attr))
2208c18beb5bSDavid Hubbard 				|| (err = device_create_file(dev,
2209ec3e5a16SGuenter Roeck 					&sda_fan_alarm[i].dev_attr)))
2210c18beb5bSDavid Hubbard 				goto exit_remove;
2211ec3e5a16SGuenter Roeck 			if (sio_data->kind != nct6776) {
2212ec3e5a16SGuenter Roeck 				err = device_create_file(dev,
2213ec3e5a16SGuenter Roeck 						&sda_fan_div[i].dev_attr);
2214ec3e5a16SGuenter Roeck 				if (err)
2215ec3e5a16SGuenter Roeck 					goto exit_remove;
2216ec3e5a16SGuenter Roeck 			}
2217ec3e5a16SGuenter Roeck 			if (data->has_fan_min & (1 << i)) {
2218ec3e5a16SGuenter Roeck 				err = device_create_file(dev,
2219ec3e5a16SGuenter Roeck 						&sda_fan_min[i].dev_attr);
2220ec3e5a16SGuenter Roeck 				if (err)
2221ec3e5a16SGuenter Roeck 					goto exit_remove;
2222ec3e5a16SGuenter Roeck 			}
2223237c8d2fSGong Jun 			if (i < data->pwm_num &&
2224c18beb5bSDavid Hubbard 				((err = device_create_file(dev,
2225c18beb5bSDavid Hubbard 					&sda_pwm[i].dev_attr))
2226c18beb5bSDavid Hubbard 				|| (err = device_create_file(dev,
2227c18beb5bSDavid Hubbard 					&sda_pwm_mode[i].dev_attr))
2228c18beb5bSDavid Hubbard 				|| (err = device_create_file(dev,
2229c18beb5bSDavid Hubbard 					&sda_pwm_enable[i].dev_attr))
2230c18beb5bSDavid Hubbard 				|| (err = device_create_file(dev,
2231c18beb5bSDavid Hubbard 					&sda_target_temp[i].dev_attr))
2232c18beb5bSDavid Hubbard 				|| (err = device_create_file(dev,
2233c18beb5bSDavid Hubbard 					&sda_tolerance[i].dev_attr))))
2234c18beb5bSDavid Hubbard 				goto exit_remove;
223508e7e278SJean Delvare 		}
223608c79950SRudolf Marek 	}
223708c79950SRudolf Marek 
2238d36cf32cSGuenter Roeck 	for (i = 0; i < NUM_REG_TEMP; i++) {
2239d36cf32cSGuenter Roeck 		if (!(data->have_temp & (1 << i)))
2240a157d06dSGong Jun 			continue;
2241d36cf32cSGuenter Roeck 		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
2242d36cf32cSGuenter Roeck 		if (err)
2243d36cf32cSGuenter Roeck 			goto exit_remove;
2244d36cf32cSGuenter Roeck 		if (data->temp_label) {
2245d36cf32cSGuenter Roeck 			err = device_create_file(dev,
2246d36cf32cSGuenter Roeck 						 &sda_temp_label[i].dev_attr);
2247d36cf32cSGuenter Roeck 			if (err)
2248d36cf32cSGuenter Roeck 				goto exit_remove;
2249d36cf32cSGuenter Roeck 		}
2250ec3e5a16SGuenter Roeck 		if (data->reg_temp_over[i]) {
2251ec3e5a16SGuenter Roeck 			err = device_create_file(dev,
2252ec3e5a16SGuenter Roeck 				&sda_temp_max[i].dev_attr);
2253ec3e5a16SGuenter Roeck 			if (err)
2254ec3e5a16SGuenter Roeck 				goto exit_remove;
2255ec3e5a16SGuenter Roeck 		}
2256ec3e5a16SGuenter Roeck 		if (data->reg_temp_hyst[i]) {
2257ec3e5a16SGuenter Roeck 			err = device_create_file(dev,
2258ec3e5a16SGuenter Roeck 				&sda_temp_max_hyst[i].dev_attr);
2259ec3e5a16SGuenter Roeck 			if (err)
2260ec3e5a16SGuenter Roeck 				goto exit_remove;
2261ec3e5a16SGuenter Roeck 		}
2262d36cf32cSGuenter Roeck 		if (i > 2)
2263ec3e5a16SGuenter Roeck 			continue;
2264ec3e5a16SGuenter Roeck 		if ((err = device_create_file(dev,
2265a157d06dSGong Jun 				&sda_temp_alarm[i].dev_attr))
2266a157d06dSGong Jun 			|| (err = device_create_file(dev,
2267a157d06dSGong Jun 				&sda_temp_type[i].dev_attr)))
2268c18beb5bSDavid Hubbard 			goto exit_remove;
2269a157d06dSGong Jun 	}
2270c18beb5bSDavid Hubbard 
22711ea6dd38SDavid Hubbard 	err = device_create_file(dev, &dev_attr_name);
22721ea6dd38SDavid Hubbard 	if (err)
22731ea6dd38SDavid Hubbard 		goto exit_remove;
22741ea6dd38SDavid Hubbard 
22751beeffe4STony Jones 	data->hwmon_dev = hwmon_device_register(dev);
22761beeffe4STony Jones 	if (IS_ERR(data->hwmon_dev)) {
22771beeffe4STony Jones 		err = PTR_ERR(data->hwmon_dev);
2278c18beb5bSDavid Hubbard 		goto exit_remove;
2279c18beb5bSDavid Hubbard 	}
228008e7e278SJean Delvare 
228108e7e278SJean Delvare 	return 0;
228208e7e278SJean Delvare 
2283c18beb5bSDavid Hubbard exit_remove:
2284c18beb5bSDavid Hubbard 	w83627ehf_device_remove_files(dev);
228508e7e278SJean Delvare 	kfree(data);
22861ea6dd38SDavid Hubbard 	platform_set_drvdata(pdev, NULL);
228708e7e278SJean Delvare exit_release:
22881ea6dd38SDavid Hubbard 	release_region(res->start, IOREGION_LENGTH);
228908e7e278SJean Delvare exit:
229008e7e278SJean Delvare 	return err;
229108e7e278SJean Delvare }
229208e7e278SJean Delvare 
22931ea6dd38SDavid Hubbard static int __devexit w83627ehf_remove(struct platform_device *pdev)
229408e7e278SJean Delvare {
22951ea6dd38SDavid Hubbard 	struct w83627ehf_data *data = platform_get_drvdata(pdev);
229608e7e278SJean Delvare 
22971beeffe4STony Jones 	hwmon_device_unregister(data->hwmon_dev);
22981ea6dd38SDavid Hubbard 	w83627ehf_device_remove_files(&pdev->dev);
22991ea6dd38SDavid Hubbard 	release_region(data->addr, IOREGION_LENGTH);
23001ea6dd38SDavid Hubbard 	platform_set_drvdata(pdev, NULL);
2301943b0830SMark M. Hoffman 	kfree(data);
230208e7e278SJean Delvare 
230308e7e278SJean Delvare 	return 0;
230408e7e278SJean Delvare }
230508e7e278SJean Delvare 
23061ea6dd38SDavid Hubbard static struct platform_driver w83627ehf_driver = {
2307cdaf7934SLaurent Riffard 	.driver = {
230887218842SJean Delvare 		.owner	= THIS_MODULE,
23091ea6dd38SDavid Hubbard 		.name	= DRVNAME,
2310cdaf7934SLaurent Riffard 	},
23111ea6dd38SDavid Hubbard 	.probe		= w83627ehf_probe,
23121ea6dd38SDavid Hubbard 	.remove		= __devexit_p(w83627ehf_remove),
231308e7e278SJean Delvare };
231408e7e278SJean Delvare 
23151ea6dd38SDavid Hubbard /* w83627ehf_find() looks for a '627 in the Super-I/O config space */
23161ea6dd38SDavid Hubbard static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
23171ea6dd38SDavid Hubbard 				 struct w83627ehf_sio_data *sio_data)
231808e7e278SJean Delvare {
23191ea6dd38SDavid Hubbard 	static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
23201ea6dd38SDavid Hubbard 	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
23211ea6dd38SDavid Hubbard 	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
2322c1e48dceSJean Delvare 	static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
2323237c8d2fSGong Jun 	static const char __initdata sio_name_W83667HG[] = "W83667HG";
2324c39aedafSGuenter Roeck 	static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
2325ec3e5a16SGuenter Roeck 	static const char __initdata sio_name_NCT6775[] = "NCT6775F";
2326ec3e5a16SGuenter Roeck 	static const char __initdata sio_name_NCT6776[] = "NCT6776F";
23271ea6dd38SDavid Hubbard 
232808e7e278SJean Delvare 	u16 val;
23291ea6dd38SDavid Hubbard 	const char *sio_name;
233008e7e278SJean Delvare 
23311ea6dd38SDavid Hubbard 	superio_enter(sioaddr);
233208e7e278SJean Delvare 
233367b671bcSJean Delvare 	if (force_id)
233467b671bcSJean Delvare 		val = force_id;
233567b671bcSJean Delvare 	else
23361ea6dd38SDavid Hubbard 		val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
23371ea6dd38SDavid Hubbard 		    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
2338657c93b1SDavid Hubbard 	switch (val & SIO_ID_MASK) {
2339657c93b1SDavid Hubbard 	case SIO_W83627EHF_ID:
23401ea6dd38SDavid Hubbard 		sio_data->kind = w83627ehf;
23411ea6dd38SDavid Hubbard 		sio_name = sio_name_W83627EHF;
23421ea6dd38SDavid Hubbard 		break;
2343657c93b1SDavid Hubbard 	case SIO_W83627EHG_ID:
23441ea6dd38SDavid Hubbard 		sio_data->kind = w83627ehf;
23451ea6dd38SDavid Hubbard 		sio_name = sio_name_W83627EHG;
23461ea6dd38SDavid Hubbard 		break;
23471ea6dd38SDavid Hubbard 	case SIO_W83627DHG_ID:
23481ea6dd38SDavid Hubbard 		sio_data->kind = w83627dhg;
23491ea6dd38SDavid Hubbard 		sio_name = sio_name_W83627DHG;
2350657c93b1SDavid Hubbard 		break;
2351c1e48dceSJean Delvare 	case SIO_W83627DHG_P_ID:
2352c1e48dceSJean Delvare 		sio_data->kind = w83627dhg_p;
2353c1e48dceSJean Delvare 		sio_name = sio_name_W83627DHG_P;
2354c1e48dceSJean Delvare 		break;
2355237c8d2fSGong Jun 	case SIO_W83667HG_ID:
2356237c8d2fSGong Jun 		sio_data->kind = w83667hg;
2357237c8d2fSGong Jun 		sio_name = sio_name_W83667HG;
2358237c8d2fSGong Jun 		break;
2359c39aedafSGuenter Roeck 	case SIO_W83667HG_B_ID:
2360c39aedafSGuenter Roeck 		sio_data->kind = w83667hg_b;
2361c39aedafSGuenter Roeck 		sio_name = sio_name_W83667HG_B;
2362c39aedafSGuenter Roeck 		break;
2363ec3e5a16SGuenter Roeck 	case SIO_NCT6775_ID:
2364ec3e5a16SGuenter Roeck 		sio_data->kind = nct6775;
2365ec3e5a16SGuenter Roeck 		sio_name = sio_name_NCT6775;
2366ec3e5a16SGuenter Roeck 		break;
2367ec3e5a16SGuenter Roeck 	case SIO_NCT6776_ID:
2368ec3e5a16SGuenter Roeck 		sio_data->kind = nct6776;
2369ec3e5a16SGuenter Roeck 		sio_name = sio_name_NCT6776;
2370ec3e5a16SGuenter Roeck 		break;
2371657c93b1SDavid Hubbard 	default:
23729f66036bSJean Delvare 		if (val != 0xffff)
2373abdc6fd1SJoe Perches 			pr_debug("unsupported chip ID: 0x%04x\n", val);
23741ea6dd38SDavid Hubbard 		superio_exit(sioaddr);
237508e7e278SJean Delvare 		return -ENODEV;
237608e7e278SJean Delvare 	}
237708e7e278SJean Delvare 
23781ea6dd38SDavid Hubbard 	/* We have a known chip, find the HWM I/O address */
23791ea6dd38SDavid Hubbard 	superio_select(sioaddr, W83627EHF_LD_HWM);
23801ea6dd38SDavid Hubbard 	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
23811ea6dd38SDavid Hubbard 	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
23821a641fceSJean Delvare 	*addr = val & IOREGION_ALIGNMENT;
23832d8672c5SJean Delvare 	if (*addr == 0) {
2384abdc6fd1SJoe Perches 		pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n");
23851ea6dd38SDavid Hubbard 		superio_exit(sioaddr);
238608e7e278SJean Delvare 		return -ENODEV;
238708e7e278SJean Delvare 	}
238808e7e278SJean Delvare 
238908e7e278SJean Delvare 	/* Activate logical device if needed */
23901ea6dd38SDavid Hubbard 	val = superio_inb(sioaddr, SIO_REG_ENABLE);
2391475ef855SDavid Hubbard 	if (!(val & 0x01)) {
2392e7e1ca6eSGuenter Roeck 		pr_warn("Forcibly enabling Super-I/O. "
2393e7e1ca6eSGuenter Roeck 			"Sensor is probably unusable.\n");
23941ea6dd38SDavid Hubbard 		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
2395475ef855SDavid Hubbard 	}
239608e7e278SJean Delvare 
23971ea6dd38SDavid Hubbard 	superio_exit(sioaddr);
2398abdc6fd1SJoe Perches 	pr_info("Found %s chip at %#x\n", sio_name, *addr);
23991ea6dd38SDavid Hubbard 	sio_data->sioreg = sioaddr;
24001ea6dd38SDavid Hubbard 
240108e7e278SJean Delvare 	return 0;
240208e7e278SJean Delvare }
240308e7e278SJean Delvare 
24041ea6dd38SDavid Hubbard /* when Super-I/O functions move to a separate file, the Super-I/O
24051ea6dd38SDavid Hubbard  * bus will manage the lifetime of the device and this module will only keep
24061ea6dd38SDavid Hubbard  * track of the w83627ehf driver. But since we platform_device_alloc(), we
24071ea6dd38SDavid Hubbard  * must keep track of the device */
24081ea6dd38SDavid Hubbard static struct platform_device *pdev;
24091ea6dd38SDavid Hubbard 
241008e7e278SJean Delvare static int __init sensors_w83627ehf_init(void)
241108e7e278SJean Delvare {
24121ea6dd38SDavid Hubbard 	int err;
24131ea6dd38SDavid Hubbard 	unsigned short address;
24141ea6dd38SDavid Hubbard 	struct resource res;
24151ea6dd38SDavid Hubbard 	struct w83627ehf_sio_data sio_data;
24161ea6dd38SDavid Hubbard 
24171ea6dd38SDavid Hubbard 	/* initialize sio_data->kind and sio_data->sioreg.
24181ea6dd38SDavid Hubbard 	 *
24191ea6dd38SDavid Hubbard 	 * when Super-I/O functions move to a separate file, the Super-I/O
24201ea6dd38SDavid Hubbard 	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
24211ea6dd38SDavid Hubbard 	 * w83627ehf hardware monitor, and call probe() */
24221ea6dd38SDavid Hubbard 	if (w83627ehf_find(0x2e, &address, &sio_data) &&
24231ea6dd38SDavid Hubbard 	    w83627ehf_find(0x4e, &address, &sio_data))
242408e7e278SJean Delvare 		return -ENODEV;
242508e7e278SJean Delvare 
24261ea6dd38SDavid Hubbard 	err = platform_driver_register(&w83627ehf_driver);
24271ea6dd38SDavid Hubbard 	if (err)
24281ea6dd38SDavid Hubbard 		goto exit;
24291ea6dd38SDavid Hubbard 
2430e7e1ca6eSGuenter Roeck 	pdev = platform_device_alloc(DRVNAME, address);
2431e7e1ca6eSGuenter Roeck 	if (!pdev) {
24321ea6dd38SDavid Hubbard 		err = -ENOMEM;
2433abdc6fd1SJoe Perches 		pr_err("Device allocation failed\n");
24341ea6dd38SDavid Hubbard 		goto exit_unregister;
24351ea6dd38SDavid Hubbard 	}
24361ea6dd38SDavid Hubbard 
24371ea6dd38SDavid Hubbard 	err = platform_device_add_data(pdev, &sio_data,
24381ea6dd38SDavid Hubbard 				       sizeof(struct w83627ehf_sio_data));
24391ea6dd38SDavid Hubbard 	if (err) {
2440abdc6fd1SJoe Perches 		pr_err("Platform data allocation failed\n");
24411ea6dd38SDavid Hubbard 		goto exit_device_put;
24421ea6dd38SDavid Hubbard 	}
24431ea6dd38SDavid Hubbard 
24441ea6dd38SDavid Hubbard 	memset(&res, 0, sizeof(res));
24451ea6dd38SDavid Hubbard 	res.name = DRVNAME;
24461ea6dd38SDavid Hubbard 	res.start = address + IOREGION_OFFSET;
24471ea6dd38SDavid Hubbard 	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
24481ea6dd38SDavid Hubbard 	res.flags = IORESOURCE_IO;
2449b9acb64aSJean Delvare 
2450b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
2451b9acb64aSJean Delvare 	if (err)
245218632f84SHans de Goede 		goto exit_device_put;
2453b9acb64aSJean Delvare 
24541ea6dd38SDavid Hubbard 	err = platform_device_add_resources(pdev, &res, 1);
24551ea6dd38SDavid Hubbard 	if (err) {
2456abdc6fd1SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
24571ea6dd38SDavid Hubbard 		goto exit_device_put;
24581ea6dd38SDavid Hubbard 	}
24591ea6dd38SDavid Hubbard 
24601ea6dd38SDavid Hubbard 	/* platform_device_add calls probe() */
24611ea6dd38SDavid Hubbard 	err = platform_device_add(pdev);
24621ea6dd38SDavid Hubbard 	if (err) {
2463abdc6fd1SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
24641ea6dd38SDavid Hubbard 		goto exit_device_put;
24651ea6dd38SDavid Hubbard 	}
24661ea6dd38SDavid Hubbard 
24671ea6dd38SDavid Hubbard 	return 0;
24681ea6dd38SDavid Hubbard 
24691ea6dd38SDavid Hubbard exit_device_put:
24701ea6dd38SDavid Hubbard 	platform_device_put(pdev);
24711ea6dd38SDavid Hubbard exit_unregister:
24721ea6dd38SDavid Hubbard 	platform_driver_unregister(&w83627ehf_driver);
24731ea6dd38SDavid Hubbard exit:
24741ea6dd38SDavid Hubbard 	return err;
247508e7e278SJean Delvare }
247608e7e278SJean Delvare 
247708e7e278SJean Delvare static void __exit sensors_w83627ehf_exit(void)
247808e7e278SJean Delvare {
24791ea6dd38SDavid Hubbard 	platform_device_unregister(pdev);
24801ea6dd38SDavid Hubbard 	platform_driver_unregister(&w83627ehf_driver);
248108e7e278SJean Delvare }
248208e7e278SJean Delvare 
248308e7e278SJean Delvare MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
248408e7e278SJean Delvare MODULE_DESCRIPTION("W83627EHF driver");
248508e7e278SJean Delvare MODULE_LICENSE("GPL");
248608e7e278SJean Delvare 
248708e7e278SJean Delvare module_init(sensors_w83627ehf_init);
248808e7e278SJean Delvare module_exit(sensors_w83627ehf_exit);
2489