xref: /openbmc/linux/drivers/hwmon/it87.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28d5d45fbSJean Delvare /*
35f2dc798SJean Delvare  *  it87.c - Part of lm_sensors, Linux kernel modules for hardware
45f2dc798SJean Delvare  *           monitoring.
55f2dc798SJean Delvare  *
65f2dc798SJean Delvare  *  The IT8705F is an LPC-based Super I/O part that contains UARTs, a
75f2dc798SJean Delvare  *  parallel port, an IR port, a MIDI port, a floppy controller, etc., in
85f2dc798SJean Delvare  *  addition to an Environment Controller (Enhanced Hardware Monitor and
95f2dc798SJean Delvare  *  Fan Controller)
105f2dc798SJean Delvare  *
115f2dc798SJean Delvare  *  This driver supports only the Environment Controller in the IT8705F and
125f2dc798SJean Delvare  *  similar parts.  The other devices are supported by different drivers.
135f2dc798SJean Delvare  *
14c145d5c6SRudolf Marek  *  Supports: IT8603E  Super I/O chip w/LPC interface
153ba9d977SGuenter Roeck  *            IT8620E  Super I/O chip w/LPC interface
168af1abaeSGuenter Roeck  *            IT8622E  Super I/O chip w/LPC interface
17574e9bd8SRudolf Marek  *            IT8623E  Super I/O chip w/LPC interface
1871a9c232SGuenter Roeck  *            IT8628E  Super I/O chip w/LPC interface
19c145d5c6SRudolf Marek  *            IT8705F  Super I/O chip w/LPC interface
205f2dc798SJean Delvare  *            IT8712F  Super I/O chip w/LPC interface
215f2dc798SJean Delvare  *            IT8716F  Super I/O chip w/LPC interface
225f2dc798SJean Delvare  *            IT8718F  Super I/O chip w/LPC interface
235f2dc798SJean Delvare  *            IT8720F  Super I/O chip w/LPC interface
2444c1bcd4SJean Delvare  *            IT8721F  Super I/O chip w/LPC interface
255f2dc798SJean Delvare  *            IT8726F  Super I/O chip w/LPC interface
2616b5dda2SJean Delvare  *            IT8728F  Super I/O chip w/LPC interface
27ead80803SJustin Maggard  *            IT8732F  Super I/O chip w/LPC interface
2844c1bcd4SJean Delvare  *            IT8758E  Super I/O chip w/LPC interface
29b0636707SGuenter Roeck  *            IT8771E  Super I/O chip w/LPC interface
30b0636707SGuenter Roeck  *            IT8772E  Super I/O chip w/LPC interface
317bc32d29SGuenter Roeck  *            IT8781F  Super I/O chip w/LPC interface
320531d98bSGuenter Roeck  *            IT8782F  Super I/O chip w/LPC interface
330531d98bSGuenter Roeck  *            IT8783E/F Super I/O chip w/LPC interface
34a0c1424aSThomas Lorblanches  *            IT8786E  Super I/O chip w/LPC interface
354ee07157SGuenter Roeck  *            IT8790E  Super I/O chip w/LPC interface
36e531ffc0SGuenter Roeck  *            IT8792E  Super I/O chip w/LPC interface
37d44cb4cdSFrank Crawford  *            IT87952E  Super I/O chip w/LPC interface
385f2dc798SJean Delvare  *            Sis950   A clone of the IT8705F
395f2dc798SJean Delvare  *
405f2dc798SJean Delvare  *  Copyright (C) 2001 Chris Gauthron
417c81c60fSJean Delvare  *  Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.de>
428d5d45fbSJean Delvare  */
438d5d45fbSJean Delvare 
44a8ca1037SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
45a8ca1037SJoe Perches 
4648b2ae7fSGuenter Roeck #include <linux/bitops.h>
478d5d45fbSJean Delvare #include <linux/module.h>
488d5d45fbSJean Delvare #include <linux/init.h>
498d5d45fbSJean Delvare #include <linux/slab.h>
508d5d45fbSJean Delvare #include <linux/jiffies.h>
51b74f3fddScorentin.labbe #include <linux/platform_device.h>
52943b0830SMark M. Hoffman #include <linux/hwmon.h>
53303760b4SJean Delvare #include <linux/hwmon-sysfs.h>
54303760b4SJean Delvare #include <linux/hwmon-vid.h>
55943b0830SMark M. Hoffman #include <linux/err.h>
569a61bf63SIngo Molnar #include <linux/mutex.h>
5787808be4SJean Delvare #include <linux/sysfs.h>
5898dd22c3SJean Delvare #include <linux/string.h>
5998dd22c3SJean Delvare #include <linux/dmi.h>
60b9acb64aSJean Delvare #include <linux/acpi.h>
616055fae8SH Hartley Sweeten #include <linux/io.h>
628d5d45fbSJean Delvare 
63b74f3fddScorentin.labbe #define DRVNAME "it87"
648d5d45fbSJean Delvare 
65ead80803SJustin Maggard enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
66e531ffc0SGuenter Roeck 	     it8771, it8772, it8781, it8782, it8783, it8786, it8790,
67d44cb4cdSFrank Crawford 	     it8792, it8603, it8620, it8622, it8628, it87952 };
688d5d45fbSJean Delvare 
69e84bd953SGuenter Roeck static struct platform_device *it87_pdev[2];
70b74f3fddScorentin.labbe 
713c2e3512SGuenter Roeck #define	REG_2E	0x2e	/* The register to read/write */
72e84bd953SGuenter Roeck #define	REG_4E	0x4e	/* Secondary register to read/write */
733c2e3512SGuenter Roeck 
748d5d45fbSJean Delvare #define	DEV	0x07	/* Register: Logical device select */
758d5d45fbSJean Delvare #define PME	0x04	/* The device with the fan registers in it */
76b4da93e4SJean-Marc Spaggiari 
77b4da93e4SJean-Marc Spaggiari /* The device with the IT8718F/IT8720F VID value in it */
78b4da93e4SJean-Marc Spaggiari #define GPIO	0x07
79b4da93e4SJean-Marc Spaggiari 
808d5d45fbSJean Delvare #define	DEVID	0x20	/* Register: Device ID */
818d5d45fbSJean Delvare #define	DEVREV	0x22	/* Register: Device Revision */
828d5d45fbSJean Delvare 
__superio_enter(int ioreg)83d47e377cSFrank Crawford static inline void __superio_enter(int ioreg)
84d47e377cSFrank Crawford {
85d47e377cSFrank Crawford 	outb(0x87, ioreg);
86d47e377cSFrank Crawford 	outb(0x01, ioreg);
87d47e377cSFrank Crawford 	outb(0x55, ioreg);
88d47e377cSFrank Crawford 	outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
89d47e377cSFrank Crawford }
90d47e377cSFrank Crawford 
superio_inb(int ioreg,int reg)913c2e3512SGuenter Roeck static inline int superio_inb(int ioreg, int reg)
928d5d45fbSJean Delvare {
933c2e3512SGuenter Roeck 	outb(reg, ioreg);
943c2e3512SGuenter Roeck 	return inb(ioreg + 1);
958d5d45fbSJean Delvare }
968d5d45fbSJean Delvare 
superio_outb(int ioreg,int reg,int val)973c2e3512SGuenter Roeck static inline void superio_outb(int ioreg, int reg, int val)
98436cad2aSJean Delvare {
993c2e3512SGuenter Roeck 	outb(reg, ioreg);
1003c2e3512SGuenter Roeck 	outb(val, ioreg + 1);
101436cad2aSJean Delvare }
102436cad2aSJean Delvare 
superio_inw(int ioreg,int reg)1033c2e3512SGuenter Roeck static int superio_inw(int ioreg, int reg)
1048d5d45fbSJean Delvare {
1058d5d45fbSJean Delvare 	int val;
106c962024eSGuenter Roeck 
1073c2e3512SGuenter Roeck 	outb(reg++, ioreg);
1083c2e3512SGuenter Roeck 	val = inb(ioreg + 1) << 8;
1093c2e3512SGuenter Roeck 	outb(reg, ioreg);
1103c2e3512SGuenter Roeck 	val |= inb(ioreg + 1);
1118d5d45fbSJean Delvare 	return val;
1128d5d45fbSJean Delvare }
1138d5d45fbSJean Delvare 
superio_select(int ioreg,int ldn)1143c2e3512SGuenter Roeck static inline void superio_select(int ioreg, int ldn)
1158d5d45fbSJean Delvare {
1163c2e3512SGuenter Roeck 	outb(DEV, ioreg);
1173c2e3512SGuenter Roeck 	outb(ldn, ioreg + 1);
1188d5d45fbSJean Delvare }
1198d5d45fbSJean Delvare 
superio_enter(int ioreg)1203c2e3512SGuenter Roeck static inline int superio_enter(int ioreg)
1218d5d45fbSJean Delvare {
1225b0380c9SNat Gurumoorthy 	/*
1233c2e3512SGuenter Roeck 	 * Try to reserve ioreg and ioreg + 1 for exclusive access.
1245b0380c9SNat Gurumoorthy 	 */
1253c2e3512SGuenter Roeck 	if (!request_muxed_region(ioreg, 2, DRVNAME))
1265b0380c9SNat Gurumoorthy 		return -EBUSY;
1275b0380c9SNat Gurumoorthy 
128d47e377cSFrank Crawford 	__superio_enter(ioreg);
1295b0380c9SNat Gurumoorthy 	return 0;
1308d5d45fbSJean Delvare }
1318d5d45fbSJean Delvare 
superio_exit(int ioreg,bool noexit)1324119693bSFrank Crawford static inline void superio_exit(int ioreg, bool noexit)
1338d5d45fbSJean Delvare {
1344119693bSFrank Crawford 	if (!noexit) {
1353c2e3512SGuenter Roeck 		outb(0x02, ioreg);
1363c2e3512SGuenter Roeck 		outb(0x02, ioreg + 1);
1374119693bSFrank Crawford 	}
1383c2e3512SGuenter Roeck 	release_region(ioreg, 2);
1398d5d45fbSJean Delvare }
1408d5d45fbSJean Delvare 
14187673dd7SJean Delvare /* Logical device 4 registers */
1428d5d45fbSJean Delvare #define IT8712F_DEVID 0x8712
1438d5d45fbSJean Delvare #define IT8705F_DEVID 0x8705
14417d648bfSJean Delvare #define IT8716F_DEVID 0x8716
14587673dd7SJean Delvare #define IT8718F_DEVID 0x8718
146b4da93e4SJean-Marc Spaggiari #define IT8720F_DEVID 0x8720
14744c1bcd4SJean Delvare #define IT8721F_DEVID 0x8721
14808a8f6e9SRudolf Marek #define IT8726F_DEVID 0x8726
14916b5dda2SJean Delvare #define IT8728F_DEVID 0x8728
150ead80803SJustin Maggard #define IT8732F_DEVID 0x8732
151e531ffc0SGuenter Roeck #define IT8792E_DEVID 0x8733
152b0636707SGuenter Roeck #define IT8771E_DEVID 0x8771
153b0636707SGuenter Roeck #define IT8772E_DEVID 0x8772
1547bc32d29SGuenter Roeck #define IT8781F_DEVID 0x8781
1550531d98bSGuenter Roeck #define IT8782F_DEVID 0x8782
1560531d98bSGuenter Roeck #define IT8783E_DEVID 0x8783
157a0c1424aSThomas Lorblanches #define IT8786E_DEVID 0x8786
1584ee07157SGuenter Roeck #define IT8790E_DEVID 0x8790
1597183ae8cSRudolf Marek #define IT8603E_DEVID 0x8603
1603ba9d977SGuenter Roeck #define IT8620E_DEVID 0x8620
1618af1abaeSGuenter Roeck #define IT8622E_DEVID 0x8622
162574e9bd8SRudolf Marek #define IT8623E_DEVID 0x8623
16371a9c232SGuenter Roeck #define IT8628E_DEVID 0x8628
164d44cb4cdSFrank Crawford #define IT87952E_DEVID 0x8695
1659989b3c0SFrank Crawford 
1669989b3c0SFrank Crawford /* Logical device 4 (Environmental Monitor) registers */
1678d5d45fbSJean Delvare #define IT87_ACT_REG	0x30
1688d5d45fbSJean Delvare #define IT87_BASE_REG	0x60
1699989b3c0SFrank Crawford #define IT87_SPECIAL_CFG_REG	0xf3	/* special configuration register */
1708d5d45fbSJean Delvare 
17187673dd7SJean Delvare /* Logical device 7 registers (IT8712F and later) */
1720531d98bSGuenter Roeck #define IT87_SIO_GPIO1_REG	0x25
1733ba9d977SGuenter Roeck #define IT87_SIO_GPIO2_REG	0x26
174895ff267SJean Delvare #define IT87_SIO_GPIO3_REG	0x27
17536c4d98aSGuenter Roeck #define IT87_SIO_GPIO4_REG	0x28
176591ec650SJean Delvare #define IT87_SIO_GPIO5_REG	0x29
1770531d98bSGuenter Roeck #define IT87_SIO_PINX1_REG	0x2a	/* Pin selection */
17887673dd7SJean Delvare #define IT87_SIO_PINX2_REG	0x2c	/* Pin selection */
1790531d98bSGuenter Roeck #define IT87_SIO_SPI_REG	0xef	/* SPI function pin select */
18087673dd7SJean Delvare #define IT87_SIO_VID_REG	0xfc	/* VID value */
181d9b327c3SJean Delvare #define IT87_SIO_BEEP_PIN_REG	0xf6	/* Beep pin mapping */
18287673dd7SJean Delvare 
1832a64e9d4SFrank Crawford /* Force chip IDs to specified values. Should only be used for testing */
1842a64e9d4SFrank Crawford static unsigned short force_id[2];
1852a64e9d4SFrank Crawford static unsigned int force_id_cnt;
186b361a1cfSFrank Crawford 
187b361a1cfSFrank Crawford /* ACPI resource conflicts are ignored if this parameter is set to 1 */
188b361a1cfSFrank Crawford static bool ignore_resource_conflict;
189b361a1cfSFrank Crawford 
1908d5d45fbSJean Delvare /* Update battery voltage after every reading if true */
19190ab5ee9SRusty Russell static bool update_vbat;
1928d5d45fbSJean Delvare 
1938d5d45fbSJean Delvare /* Not all BIOSes properly configure the PWM registers */
19490ab5ee9SRusty Russell static bool fix_pwm_polarity;
1958d5d45fbSJean Delvare 
1968d5d45fbSJean Delvare /* Many IT87 constants specified below */
1978d5d45fbSJean Delvare 
1988d5d45fbSJean Delvare /* Length of ISA address segment */
1998d5d45fbSJean Delvare #define IT87_EXTENT 8
2008d5d45fbSJean Delvare 
20187b4b663SBjorn Helgaas /* Length of ISA address segment for Environmental Controller */
20287b4b663SBjorn Helgaas #define IT87_EC_EXTENT 2
20387b4b663SBjorn Helgaas 
20487b4b663SBjorn Helgaas /* Offset of EC registers from ISA base address */
20587b4b663SBjorn Helgaas #define IT87_EC_OFFSET 5
20687b4b663SBjorn Helgaas 
20787b4b663SBjorn Helgaas /* Where are the ISA address/data registers relative to the EC base address */
20887b4b663SBjorn Helgaas #define IT87_ADDR_REG_OFFSET 0
20987b4b663SBjorn Helgaas #define IT87_DATA_REG_OFFSET 1
2108d5d45fbSJean Delvare 
2118d5d45fbSJean Delvare /*----- The IT87 registers -----*/
2128d5d45fbSJean Delvare 
2138d5d45fbSJean Delvare #define IT87_REG_CONFIG        0x00
2148d5d45fbSJean Delvare 
2158d5d45fbSJean Delvare #define IT87_REG_ALARM1        0x01
2168d5d45fbSJean Delvare #define IT87_REG_ALARM2        0x02
2178d5d45fbSJean Delvare #define IT87_REG_ALARM3        0x03
2188d5d45fbSJean Delvare 
2194a0d71cfSGuenter Roeck /*
2204a0d71cfSGuenter Roeck  * The IT8718F and IT8720F have the VID value in a different register, in
2214a0d71cfSGuenter Roeck  * Super-I/O configuration space.
2224a0d71cfSGuenter Roeck  */
2238d5d45fbSJean Delvare #define IT87_REG_VID           0x0a
224*6593eac8SFrank Crawford 
225*6593eac8SFrank Crawford /* Interface Selection register on other chips */
226*6593eac8SFrank Crawford #define IT87_REG_IFSEL         0x0a
227*6593eac8SFrank Crawford 
2284a0d71cfSGuenter Roeck /*
2294a0d71cfSGuenter Roeck  * The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
2304a0d71cfSGuenter Roeck  * for fan divisors. Later IT8712F revisions must use 16-bit tachometer
2314a0d71cfSGuenter Roeck  * mode.
2324a0d71cfSGuenter Roeck  */
2338d5d45fbSJean Delvare #define IT87_REG_FAN_DIV       0x0b
23417d648bfSJean Delvare #define IT87_REG_FAN_16BIT     0x0c
2358d5d45fbSJean Delvare 
236f838aa26SGuenter Roeck /*
237f838aa26SGuenter Roeck  * Monitors:
238f838aa26SGuenter Roeck  * - up to 13 voltage (0 to 7, battery, avcc, 10 to 12)
239f838aa26SGuenter Roeck  * - up to 6 temp (1 to 6)
240f838aa26SGuenter Roeck  * - up to 6 fan (1 to 6)
241f838aa26SGuenter Roeck  */
2428d5d45fbSJean Delvare 
243fa3f70d6SGuenter Roeck static const u8 IT87_REG_FAN[]         = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
244fa3f70d6SGuenter Roeck static const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
245fa3f70d6SGuenter Roeck static const u8 IT87_REG_FANX[]        = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d };
246fa3f70d6SGuenter Roeck static const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f };
247161d898aSGuenter Roeck static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
248161d898aSGuenter Roeck 
2498d5d45fbSJean Delvare #define IT87_REG_FAN_MAIN_CTRL 0x13
2508d5d45fbSJean Delvare #define IT87_REG_FAN_CTL       0x14
25136c4d98aSGuenter Roeck static const u8 IT87_REG_PWM[]         = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
25236c4d98aSGuenter Roeck static const u8 IT87_REG_PWM_DUTY[]    = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };
2538d5d45fbSJean Delvare 
254559313c4SGuenter Roeck static const u8 IT87_REG_VIN[]	= { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
255f838aa26SGuenter Roeck 				    0x27, 0x28, 0x2f, 0x2c, 0x2d, 0x2e };
2568d5d45fbSJean Delvare 
257559313c4SGuenter Roeck #define IT87_REG_TEMP(nr)      (0x29 + (nr))
25873055405SGuenter Roeck 
2598d5d45fbSJean Delvare #define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)
2608d5d45fbSJean Delvare #define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)
2618d5d45fbSJean Delvare #define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
2628d5d45fbSJean Delvare #define IT87_REG_TEMP_LOW(nr)  (0x41 + (nr) * 2)
2638d5d45fbSJean Delvare 
2648d5d45fbSJean Delvare #define IT87_REG_VIN_ENABLE    0x50
2658d5d45fbSJean Delvare #define IT87_REG_TEMP_ENABLE   0x51
2664573acbcSGuenter Roeck #define IT87_REG_TEMP_EXTRA    0x55
267d9b327c3SJean Delvare #define IT87_REG_BEEP_ENABLE   0x5c
2688d5d45fbSJean Delvare 
2698d5d45fbSJean Delvare #define IT87_REG_CHIPID        0x58
2708d5d45fbSJean Delvare 
2712cbb9c37SGuenter Roeck static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
2722cbb9c37SGuenter Roeck 
2732cbb9c37SGuenter Roeck #define IT87_REG_AUTO_TEMP(nr, i) (IT87_REG_AUTO_BASE[nr] + (i))
2742cbb9c37SGuenter Roeck #define IT87_REG_AUTO_PWM(nr, i)  (IT87_REG_AUTO_BASE[nr] + 5 + (i))
2754f3f51bcSJean Delvare 
276cc18da79SGuenter Roeck #define IT87_REG_TEMP456_ENABLE	0x77
277cc18da79SGuenter Roeck 
2782310048dSGuenter Roeck #define NUM_VIN			ARRAY_SIZE(IT87_REG_VIN)
2792310048dSGuenter Roeck #define NUM_VIN_LIMIT		8
2802310048dSGuenter Roeck #define NUM_TEMP		6
2812310048dSGuenter Roeck #define NUM_TEMP_OFFSET		ARRAY_SIZE(IT87_REG_TEMP_OFFSET)
2822310048dSGuenter Roeck #define NUM_TEMP_LIMIT		3
2832310048dSGuenter Roeck #define NUM_FAN			ARRAY_SIZE(IT87_REG_FAN)
2842310048dSGuenter Roeck #define NUM_FAN_DIV		3
2852310048dSGuenter Roeck #define NUM_PWM			ARRAY_SIZE(IT87_REG_PWM)
2862310048dSGuenter Roeck #define NUM_AUTO_PWM		ARRAY_SIZE(IT87_REG_PWM)
2872310048dSGuenter Roeck 
288483db43eSGuenter Roeck struct it87_devices {
289483db43eSGuenter Roeck 	const char *name;
2901f21531dSFrank Crawford 	const char * const model;
291cc18da79SGuenter Roeck 	u32 features;
29219529784SGuenter Roeck 	u8 peci_mask;
29319529784SGuenter Roeck 	u8 old_peci_mask;
2949989b3c0SFrank Crawford 	u8 smbus_bitmap;	/* SMBus enable bits in extra config register */
2959989b3c0SFrank Crawford 	u8 ec_special_config;
296483db43eSGuenter Roeck };
297483db43eSGuenter Roeck 
29848b2ae7fSGuenter Roeck #define FEAT_12MV_ADC		BIT(0)
29948b2ae7fSGuenter Roeck #define FEAT_NEWER_AUTOPWM	BIT(1)
30048b2ae7fSGuenter Roeck #define FEAT_OLD_AUTOPWM	BIT(2)
30148b2ae7fSGuenter Roeck #define FEAT_16BIT_FANS		BIT(3)
30248b2ae7fSGuenter Roeck #define FEAT_TEMP_OFFSET	BIT(4)
30348b2ae7fSGuenter Roeck #define FEAT_TEMP_PECI		BIT(5)
30448b2ae7fSGuenter Roeck #define FEAT_TEMP_OLD_PECI	BIT(6)
30548b2ae7fSGuenter Roeck #define FEAT_FAN16_CONFIG	BIT(7)	/* Need to enable 16-bit fans */
30648b2ae7fSGuenter Roeck #define FEAT_FIVE_FANS		BIT(8)	/* Supports five fans */
30748b2ae7fSGuenter Roeck #define FEAT_VID		BIT(9)	/* Set if chip supports VID */
30848b2ae7fSGuenter Roeck #define FEAT_IN7_INTERNAL	BIT(10)	/* Set if in7 is internal */
30948b2ae7fSGuenter Roeck #define FEAT_SIX_FANS		BIT(11)	/* Supports six fans */
31048b2ae7fSGuenter Roeck #define FEAT_10_9MV_ADC		BIT(12)
31148b2ae7fSGuenter Roeck #define FEAT_AVCC3		BIT(13)	/* Chip supports in9/AVCC3 */
312638c1c07SGuenter Roeck #define FEAT_FIVE_PWM		BIT(14)	/* Chip supports 5 pwm chn */
313638c1c07SGuenter Roeck #define FEAT_SIX_PWM		BIT(15)	/* Chip supports 6 pwm chn */
314638c1c07SGuenter Roeck #define FEAT_PWM_FREQ2		BIT(16)	/* Separate pwm freq 2 */
315638c1c07SGuenter Roeck #define FEAT_SIX_TEMP		BIT(17)	/* Up to 6 temp sensors */
316638c1c07SGuenter Roeck #define FEAT_VIN3_5V		BIT(18)	/* VIN3 connected to +5V */
3174119693bSFrank Crawford /*
3184119693bSFrank Crawford  * Disabling configuration mode on some chips can result in system
3194119693bSFrank Crawford  * hang-ups and access failures to the Super-IO chip at the
3204119693bSFrank Crawford  * second SIO address. Never exit configuration mode on these
3214119693bSFrank Crawford  * chips to avoid the problem.
3224119693bSFrank Crawford  */
3234119693bSFrank Crawford #define FEAT_CONF_NOEXIT	BIT(19)	/* Chip should not exit conf mode */
3245a4417bcSFrank Crawford #define FEAT_FOUR_FANS		BIT(20)	/* Supports four fans */
32539a6dcf6SFrank Crawford #define FEAT_FOUR_PWM		BIT(21)	/* Supports four fan controls */
326339c8f24SFrank Crawford #define FEAT_FOUR_TEMP		BIT(22)
327317840cfSFrank Crawford #define FEAT_FANCTL_ONOFF	BIT(23)	/* chip has FAN_CTL ON/OFF */
328483db43eSGuenter Roeck 
329483db43eSGuenter Roeck static const struct it87_devices it87_devices[] = {
330483db43eSGuenter Roeck 	[it87] = {
331483db43eSGuenter Roeck 		.name = "it87",
3321f21531dSFrank Crawford 		.model = "IT87F",
333317840cfSFrank Crawford 		.features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
334317840cfSFrank Crawford 		/* may need to overwrite */
335483db43eSGuenter Roeck 	},
336483db43eSGuenter Roeck 	[it8712] = {
337483db43eSGuenter Roeck 		.name = "it8712",
3381f21531dSFrank Crawford 		.model = "IT8712F",
339317840cfSFrank Crawford 		.features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
34032dd7c40SGuenter Roeck 		/* may need to overwrite */
341483db43eSGuenter Roeck 	},
342483db43eSGuenter Roeck 	[it8716] = {
343483db43eSGuenter Roeck 		.name = "it8716",
3441f21531dSFrank Crawford 		.model = "IT8716F",
34532dd7c40SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
346317840cfSFrank Crawford 		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
347317840cfSFrank Crawford 		  | FEAT_FANCTL_ONOFF,
348483db43eSGuenter Roeck 	},
349483db43eSGuenter Roeck 	[it8718] = {
350483db43eSGuenter Roeck 		.name = "it8718",
3511f21531dSFrank Crawford 		.model = "IT8718F",
35232dd7c40SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
35360878bcfSGuenter Roeck 		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
354317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
35519529784SGuenter Roeck 		.old_peci_mask = 0x4,
356483db43eSGuenter Roeck 	},
357483db43eSGuenter Roeck 	[it8720] = {
358483db43eSGuenter Roeck 		.name = "it8720",
3591f21531dSFrank Crawford 		.model = "IT8720F",
36032dd7c40SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
36160878bcfSGuenter Roeck 		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
362317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
36319529784SGuenter Roeck 		.old_peci_mask = 0x4,
364483db43eSGuenter Roeck 	},
365483db43eSGuenter Roeck 	[it8721] = {
366483db43eSGuenter Roeck 		.name = "it8721",
3671f21531dSFrank Crawford 		.model = "IT8721F",
368483db43eSGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
3699faf28caSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
37060878bcfSGuenter Roeck 		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
371317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
3725d8d2f2bSGuenter Roeck 		.peci_mask = 0x05,
37319529784SGuenter Roeck 		.old_peci_mask = 0x02,	/* Actually reports PCH */
374483db43eSGuenter Roeck 	},
375483db43eSGuenter Roeck 	[it8728] = {
376483db43eSGuenter Roeck 		.name = "it8728",
3771f21531dSFrank Crawford 		.model = "IT8728F",
378483db43eSGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
3797f5726c3SGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
380317840cfSFrank Crawford 		  | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
381317840cfSFrank Crawford 		  | FEAT_FANCTL_ONOFF,
3825d8d2f2bSGuenter Roeck 		.peci_mask = 0x07,
383483db43eSGuenter Roeck 	},
384ead80803SJustin Maggard 	[it8732] = {
385ead80803SJustin Maggard 		.name = "it8732",
3861f21531dSFrank Crawford 		.model = "IT8732F",
387ead80803SJustin Maggard 		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
388ead80803SJustin Maggard 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
389bd594022SFrank Crawford 		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
390317840cfSFrank Crawford 		  | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
391ead80803SJustin Maggard 		.peci_mask = 0x07,
392ead80803SJustin Maggard 		.old_peci_mask = 0x02,	/* Actually reports PCH */
393ead80803SJustin Maggard 	},
394b0636707SGuenter Roeck 	[it8771] = {
395b0636707SGuenter Roeck 		.name = "it8771",
3961f21531dSFrank Crawford 		.model = "IT8771E",
397b0636707SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
39860878bcfSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
399317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
400b0636707SGuenter Roeck 				/* PECI: guesswork */
401b0636707SGuenter Roeck 				/* 12mV ADC (OHM) */
402b0636707SGuenter Roeck 				/* 16 bit fans (OHM) */
4039faf28caSGuenter Roeck 				/* three fans, always 16 bit (guesswork) */
404b0636707SGuenter Roeck 		.peci_mask = 0x07,
405b0636707SGuenter Roeck 	},
406b0636707SGuenter Roeck 	[it8772] = {
407b0636707SGuenter Roeck 		.name = "it8772",
4081f21531dSFrank Crawford 		.model = "IT8772E",
409b0636707SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
41060878bcfSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
411317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
412b0636707SGuenter Roeck 				/* PECI (coreboot) */
413b0636707SGuenter Roeck 				/* 12mV ADC (HWSensors4, OHM) */
414b0636707SGuenter Roeck 				/* 16 bit fans (HWSensors4, OHM) */
4159faf28caSGuenter Roeck 				/* three fans, always 16 bit (datasheet) */
416b0636707SGuenter Roeck 		.peci_mask = 0x07,
417b0636707SGuenter Roeck 	},
4187bc32d29SGuenter Roeck 	[it8781] = {
4197bc32d29SGuenter Roeck 		.name = "it8781",
4201f21531dSFrank Crawford 		.model = "IT8781F",
4217bc32d29SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
422317840cfSFrank Crawford 		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
423317840cfSFrank Crawford 		  | FEAT_FANCTL_ONOFF,
4247bc32d29SGuenter Roeck 		.old_peci_mask = 0x4,
4257bc32d29SGuenter Roeck 	},
426483db43eSGuenter Roeck 	[it8782] = {
427483db43eSGuenter Roeck 		.name = "it8782",
4281f21531dSFrank Crawford 		.model = "IT8782F",
42919529784SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
430317840cfSFrank Crawford 		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
431317840cfSFrank Crawford 		  | FEAT_FANCTL_ONOFF,
43219529784SGuenter Roeck 		.old_peci_mask = 0x4,
433483db43eSGuenter Roeck 	},
434483db43eSGuenter Roeck 	[it8783] = {
435483db43eSGuenter Roeck 		.name = "it8783",
4361f21531dSFrank Crawford 		.model = "IT8783E/F",
43719529784SGuenter Roeck 		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
438317840cfSFrank Crawford 		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
439317840cfSFrank Crawford 		  | FEAT_FANCTL_ONOFF,
44019529784SGuenter Roeck 		.old_peci_mask = 0x4,
441483db43eSGuenter Roeck 	},
442a0c1424aSThomas Lorblanches 	[it8786] = {
443a0c1424aSThomas Lorblanches 		.name = "it8786",
4441f21531dSFrank Crawford 		.model = "IT8786E",
445a0c1424aSThomas Lorblanches 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
44660878bcfSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
447317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
448a0c1424aSThomas Lorblanches 		.peci_mask = 0x07,
449a0c1424aSThomas Lorblanches 	},
4504ee07157SGuenter Roeck 	[it8790] = {
4514ee07157SGuenter Roeck 		.name = "it8790",
4521f21531dSFrank Crawford 		.model = "IT8790E",
4534ee07157SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
45460878bcfSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
455317840cfSFrank Crawford 		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_CONF_NOEXIT,
4564ee07157SGuenter Roeck 		.peci_mask = 0x07,
4574ee07157SGuenter Roeck 	},
458e531ffc0SGuenter Roeck 	[it8792] = {
459e531ffc0SGuenter Roeck 		.name = "it8792",
4601f21531dSFrank Crawford 		.model = "IT8792E/IT8795E",
461e531ffc0SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
462e531ffc0SGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
463317840cfSFrank Crawford 		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
464317840cfSFrank Crawford 		  | FEAT_CONF_NOEXIT,
465e531ffc0SGuenter Roeck 		.peci_mask = 0x07,
466e531ffc0SGuenter Roeck 		.old_peci_mask = 0x02,	/* Actually reports PCH */
467e531ffc0SGuenter Roeck 	},
468c145d5c6SRudolf Marek 	[it8603] = {
469c145d5c6SRudolf Marek 		.name = "it8603",
4701f21531dSFrank Crawford 		.model = "IT8603E",
471c145d5c6SRudolf Marek 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
47273055405SGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
47360878bcfSGuenter Roeck 		  | FEAT_AVCC3 | FEAT_PWM_FREQ2,
474c145d5c6SRudolf Marek 		.peci_mask = 0x07,
475c145d5c6SRudolf Marek 	},
4763ba9d977SGuenter Roeck 	[it8620] = {
4773ba9d977SGuenter Roeck 		.name = "it8620",
4781f21531dSFrank Crawford 		.model = "IT8620E",
4793ba9d977SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
480fa3f70d6SGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
481cc18da79SGuenter Roeck 		  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
482317840cfSFrank Crawford 		  | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
4833ba9d977SGuenter Roeck 		.peci_mask = 0x07,
4843ba9d977SGuenter Roeck 	},
4858af1abaeSGuenter Roeck 	[it8622] = {
4868af1abaeSGuenter Roeck 		.name = "it8622",
4871f21531dSFrank Crawford 		.model = "IT8622E",
4888af1abaeSGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
4898af1abaeSGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
490638c1c07SGuenter Roeck 		  | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
491339c8f24SFrank Crawford 		  | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
4928af1abaeSGuenter Roeck 		.peci_mask = 0x07,
4930be10077SFrank Crawford 		.smbus_bitmap = BIT(1) | BIT(2),
4948af1abaeSGuenter Roeck 	},
49571a9c232SGuenter Roeck 	[it8628] = {
49671a9c232SGuenter Roeck 		.name = "it8628",
4971f21531dSFrank Crawford 		.model = "IT8628E",
49871a9c232SGuenter Roeck 		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
49971a9c232SGuenter Roeck 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
50071a9c232SGuenter Roeck 		  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
501317840cfSFrank Crawford 		  | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
50271a9c232SGuenter Roeck 		.peci_mask = 0x07,
50371a9c232SGuenter Roeck 	},
504d44cb4cdSFrank Crawford 	[it87952] = {
505d44cb4cdSFrank Crawford 		.name = "it87952",
506d44cb4cdSFrank Crawford 		.model = "IT87952E",
507d44cb4cdSFrank Crawford 		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
508d44cb4cdSFrank Crawford 		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
509317840cfSFrank Crawford 		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
510317840cfSFrank Crawford 		  | FEAT_CONF_NOEXIT,
511d44cb4cdSFrank Crawford 		.peci_mask = 0x07,
512d44cb4cdSFrank Crawford 		.old_peci_mask = 0x02,	/* Actually reports PCH */
513d44cb4cdSFrank Crawford 	},
514483db43eSGuenter Roeck };
515483db43eSGuenter Roeck 
516483db43eSGuenter Roeck #define has_16bit_fans(data)	((data)->features & FEAT_16BIT_FANS)
517483db43eSGuenter Roeck #define has_12mv_adc(data)	((data)->features & FEAT_12MV_ADC)
518ead80803SJustin Maggard #define has_10_9mv_adc(data)	((data)->features & FEAT_10_9MV_ADC)
519483db43eSGuenter Roeck #define has_newer_autopwm(data)	((data)->features & FEAT_NEWER_AUTOPWM)
520483db43eSGuenter Roeck #define has_old_autopwm(data)	((data)->features & FEAT_OLD_AUTOPWM)
521483db43eSGuenter Roeck #define has_temp_offset(data)	((data)->features & FEAT_TEMP_OFFSET)
5225d8d2f2bSGuenter Roeck #define has_temp_peci(data, nr)	(((data)->features & FEAT_TEMP_PECI) && \
52348b2ae7fSGuenter Roeck 				 ((data)->peci_mask & BIT(nr)))
52419529784SGuenter Roeck #define has_temp_old_peci(data, nr) \
52519529784SGuenter Roeck 				(((data)->features & FEAT_TEMP_OLD_PECI) && \
52648b2ae7fSGuenter Roeck 				 ((data)->old_peci_mask & BIT(nr)))
5279faf28caSGuenter Roeck #define has_fan16_config(data)	((data)->features & FEAT_FAN16_CONFIG)
5285a4417bcSFrank Crawford #define has_four_fans(data)	((data)->features & (FEAT_FOUR_FANS | \
5295a4417bcSFrank Crawford 						     FEAT_FIVE_FANS | \
5305a4417bcSFrank Crawford 						     FEAT_SIX_FANS))
531fa3f70d6SGuenter Roeck #define has_five_fans(data)	((data)->features & (FEAT_FIVE_FANS | \
532fa3f70d6SGuenter Roeck 						     FEAT_SIX_FANS))
5335a4417bcSFrank Crawford #define has_six_fans(data)	((data)->features & FEAT_SIX_FANS)
53432dd7c40SGuenter Roeck #define has_vid(data)		((data)->features & FEAT_VID)
5357f5726c3SGuenter Roeck #define has_in7_internal(data)	((data)->features & FEAT_IN7_INTERNAL)
53673055405SGuenter Roeck #define has_avcc3(data)		((data)->features & FEAT_AVCC3)
53739a6dcf6SFrank Crawford #define has_four_pwm(data)	((data)->features & (FEAT_FOUR_PWM | \
53839a6dcf6SFrank Crawford 						     FEAT_FIVE_PWM | \
53939a6dcf6SFrank Crawford 						     FEAT_SIX_PWM))
54039a6dcf6SFrank Crawford #define has_five_pwm(data)	((data)->features & (FEAT_FIVE_PWM | \
54139a6dcf6SFrank Crawford 						     FEAT_SIX_PWM))
54236c4d98aSGuenter Roeck #define has_six_pwm(data)	((data)->features & FEAT_SIX_PWM)
54360878bcfSGuenter Roeck #define has_pwm_freq2(data)	((data)->features & FEAT_PWM_FREQ2)
544339c8f24SFrank Crawford #define has_four_temp(data)	((data)->features & FEAT_FOUR_TEMP)
545cc18da79SGuenter Roeck #define has_six_temp(data)	((data)->features & FEAT_SIX_TEMP)
546a9eebd4fSGuenter Roeck #define has_vin3_5v(data)	((data)->features & FEAT_VIN3_5V)
5474119693bSFrank Crawford #define has_conf_noexit(data)	((data)->features & FEAT_CONF_NOEXIT)
548968b66ffSFrank Crawford #define has_scaling(data)	((data)->features & (FEAT_12MV_ADC | \
549968b66ffSFrank Crawford 						     FEAT_10_9MV_ADC))
550317840cfSFrank Crawford #define has_fanctl_onoff(data)	((data)->features & FEAT_FANCTL_ONOFF)
5518d5d45fbSJean Delvare 
552b74f3fddScorentin.labbe struct it87_sio_data {
553384548e5SMaciej S. Szmigiero 	int sioaddr;
554b74f3fddScorentin.labbe 	enum chips type;
555b74f3fddScorentin.labbe 	/* Values read from Super-I/O config space */
5560475169cSAndrew Paprocki 	u8 revision;
557b74f3fddScorentin.labbe 	u8 vid_value;
558d9b327c3SJean Delvare 	u8 beep_pin;
559738e5e05SJean Delvare 	u8 internal;	/* Internal sensors can be labeled */
560384548e5SMaciej S. Szmigiero 	bool need_in7_reroute;
561591ec650SJean Delvare 	/* Features skipped based on config or DMI */
5629172b5d1SGuenter Roeck 	u16 skip_in;
563895ff267SJean Delvare 	u8 skip_vid;
564591ec650SJean Delvare 	u8 skip_fan;
56598dd22c3SJean Delvare 	u8 skip_pwm;
5664573acbcSGuenter Roeck 	u8 skip_temp;
5679989b3c0SFrank Crawford 	u8 smbus_bitmap;
5689989b3c0SFrank Crawford 	u8 ec_special_config;
569b74f3fddScorentin.labbe };
570b74f3fddScorentin.labbe 
5714a0d71cfSGuenter Roeck /*
5724a0d71cfSGuenter Roeck  * For each registered chip, we need to keep some data in memory.
5734a0d71cfSGuenter Roeck  * The structure is dynamically allocated.
5744a0d71cfSGuenter Roeck  */
5758d5d45fbSJean Delvare struct it87_data {
5768638d0afSGuenter Roeck 	const struct attribute_group *groups[7];
577384548e5SMaciej S. Szmigiero 	int sioaddr;
5788d5d45fbSJean Delvare 	enum chips type;
579aa8b187eSGuenter Roeck 	u32 features;
58019529784SGuenter Roeck 	u8 peci_mask;
58119529784SGuenter Roeck 	u8 old_peci_mask;
5828d5d45fbSJean Delvare 
5839989b3c0SFrank Crawford 	u8 smbus_bitmap;	/* !=0 if SMBus needs to be disabled */
5849989b3c0SFrank Crawford 	u8 ec_special_config;	/* EC special config register restore value */
5859989b3c0SFrank Crawford 
586b74f3fddScorentin.labbe 	unsigned short addr;
587b74f3fddScorentin.labbe 	const char *name;
5889a61bf63SIngo Molnar 	struct mutex update_lock;
589952a11caSPaul Fertser 	bool valid;		/* true if following fields are valid */
5908d5d45fbSJean Delvare 	unsigned long last_updated;	/* In jiffies */
5918d5d45fbSJean Delvare 
59244c1bcd4SJean Delvare 	u16 in_scaled;		/* Internal voltage sensors are scaled */
593d3766848SGuenter Roeck 	u16 in_internal;	/* Bitfield, internal sensors (for labels) */
59452929715SGuenter Roeck 	u16 has_in;		/* Bitfield, voltage sensors enabled */
5952310048dSGuenter Roeck 	u8 in[NUM_VIN][3];		/* [nr][0]=in, [1]=min, [2]=max */
596384548e5SMaciej S. Szmigiero 	bool need_in7_reroute;
5979060f8bdSJean Delvare 	u8 has_fan;		/* Bitfield, fans enabled */
5982310048dSGuenter Roeck 	u16 fan[NUM_FAN][2];	/* Register values, [nr][0]=fan, [1]=min */
5994573acbcSGuenter Roeck 	u8 has_temp;		/* Bitfield, temp sensors enabled */
6002310048dSGuenter Roeck 	s8 temp[NUM_TEMP][4];	/* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
60119529784SGuenter Roeck 	u8 sensor;		/* Register value (IT87_REG_TEMP_ENABLE) */
60219529784SGuenter Roeck 	u8 extra;		/* Register value (IT87_REG_TEMP_EXTRA) */
6032310048dSGuenter Roeck 	u8 fan_div[NUM_FAN_DIV];/* Register encoding, shifted right */
604d3766848SGuenter Roeck 	bool has_vid;		/* True if VID supported */
6058d5d45fbSJean Delvare 	u8 vid;			/* Register encoding, combined */
606a7be58a1SJean Delvare 	u8 vrm;
6078d5d45fbSJean Delvare 	u32 alarms;		/* Register encoding, combined */
60852929715SGuenter Roeck 	bool has_beep;		/* true if beep supported */
609d9b327c3SJean Delvare 	u8 beeps;		/* Register encoding */
6108d5d45fbSJean Delvare 	u8 fan_main_ctrl;	/* Register value */
611f8d0c19aSJean Delvare 	u8 fan_ctl;		/* Register value */
612b99883dcSJean Delvare 
6134a0d71cfSGuenter Roeck 	/*
6144a0d71cfSGuenter Roeck 	 * The following 3 arrays correspond to the same registers up to
6156229cdb2SJean Delvare 	 * the IT8720F. The meaning of bits 6-0 depends on the value of bit
6166229cdb2SJean Delvare 	 * 7, and we want to preserve settings on mode changes, so we have
6176229cdb2SJean Delvare 	 * to track all values separately.
6186229cdb2SJean Delvare 	 * Starting with the IT8721F, the manual PWM duty cycles are stored
6196229cdb2SJean Delvare 	 * in separate registers (8-bit values), so the separate tracking
6206229cdb2SJean Delvare 	 * is no longer needed, but it is still done to keep the driver
6214a0d71cfSGuenter Roeck 	 * simple.
6224a0d71cfSGuenter Roeck 	 */
6235c391261SGuenter Roeck 	u8 has_pwm;		/* Bitfield, pwm control enabled */
6242310048dSGuenter Roeck 	u8 pwm_ctrl[NUM_PWM];	/* Register value */
6252310048dSGuenter Roeck 	u8 pwm_duty[NUM_PWM];	/* Manual PWM value set by user */
6262310048dSGuenter Roeck 	u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */
6274f3f51bcSJean Delvare 
6284f3f51bcSJean Delvare 	/* Automatic fan speed control registers */
6292310048dSGuenter Roeck 	u8 auto_pwm[NUM_AUTO_PWM][4];	/* [nr][3] is hard-coded */
6302310048dSGuenter Roeck 	s8 auto_temp[NUM_AUTO_PWM][5];	/* [nr][0] is point1_temp_hyst */
6318d5d45fbSJean Delvare };
6328d5d45fbSJean Delvare 
633a1bedbccSFrank Crawford /* Board specific settings from DMI matching */
634a1bedbccSFrank Crawford struct it87_dmi_data {
635a1bedbccSFrank Crawford 	u8 skip_pwm;		/* pwm channels to skip for this board  */
636a1bedbccSFrank Crawford };
637a1bedbccSFrank Crawford 
638a1bedbccSFrank Crawford /* Global for results from DMI matching, if needed */
639a1bedbccSFrank Crawford static struct it87_dmi_data *dmi_data;
640a1bedbccSFrank Crawford 
adc_lsb(const struct it87_data * data,int nr)6410531d98bSGuenter Roeck static int adc_lsb(const struct it87_data *data, int nr)
6420531d98bSGuenter Roeck {
643ead80803SJustin Maggard 	int lsb;
644ead80803SJustin Maggard 
645ead80803SJustin Maggard 	if (has_12mv_adc(data))
646ead80803SJustin Maggard 		lsb = 120;
647ead80803SJustin Maggard 	else if (has_10_9mv_adc(data))
648ead80803SJustin Maggard 		lsb = 109;
649ead80803SJustin Maggard 	else
650ead80803SJustin Maggard 		lsb = 160;
65148b2ae7fSGuenter Roeck 	if (data->in_scaled & BIT(nr))
6520531d98bSGuenter Roeck 		lsb <<= 1;
6530531d98bSGuenter Roeck 	return lsb;
6540531d98bSGuenter Roeck }
6550531d98bSGuenter Roeck 
in_to_reg(const struct it87_data * data,int nr,long val)65644c1bcd4SJean Delvare static u8 in_to_reg(const struct it87_data *data, int nr, long val)
65744c1bcd4SJean Delvare {
658ead80803SJustin Maggard 	val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr));
6592a844c14SGuenter Roeck 	return clamp_val(val, 0, 255);
66044c1bcd4SJean Delvare }
66144c1bcd4SJean Delvare 
in_from_reg(const struct it87_data * data,int nr,int val)66244c1bcd4SJean Delvare static int in_from_reg(const struct it87_data *data, int nr, int val)
66344c1bcd4SJean Delvare {
664ead80803SJustin Maggard 	return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10);
66544c1bcd4SJean Delvare }
6660df6454dSJean Delvare 
FAN_TO_REG(long rpm,int div)6670df6454dSJean Delvare static inline u8 FAN_TO_REG(long rpm, int div)
6680df6454dSJean Delvare {
6690df6454dSJean Delvare 	if (rpm == 0)
6700df6454dSJean Delvare 		return 255;
6712a844c14SGuenter Roeck 	rpm = clamp_val(rpm, 1, 1000000);
6722a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
6730df6454dSJean Delvare }
6740df6454dSJean Delvare 
FAN16_TO_REG(long rpm)6750df6454dSJean Delvare static inline u16 FAN16_TO_REG(long rpm)
6760df6454dSJean Delvare {
6770df6454dSJean Delvare 	if (rpm == 0)
6780df6454dSJean Delvare 		return 0xffff;
6792a844c14SGuenter Roeck 	return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
6800df6454dSJean Delvare }
6810df6454dSJean Delvare 
6820df6454dSJean Delvare #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
6830df6454dSJean Delvare 				1350000 / ((val) * (div)))
6840df6454dSJean Delvare /* The divider is fixed to 2 in 16-bit mode */
6850df6454dSJean Delvare #define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
6860df6454dSJean Delvare 			     1350000 / ((val) * 2))
6870df6454dSJean Delvare 
6882a844c14SGuenter Roeck #define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
6890df6454dSJean Delvare 				    ((val) + 500) / 1000), -128, 127))
6900df6454dSJean Delvare #define TEMP_FROM_REG(val) ((val) * 1000)
6910df6454dSJean Delvare 
pwm_to_reg(const struct it87_data * data,long val)69244c1bcd4SJean Delvare static u8 pwm_to_reg(const struct it87_data *data, long val)
69344c1bcd4SJean Delvare {
69416b5dda2SJean Delvare 	if (has_newer_autopwm(data))
69544c1bcd4SJean Delvare 		return val;
69644c1bcd4SJean Delvare 	else
69744c1bcd4SJean Delvare 		return val >> 1;
69844c1bcd4SJean Delvare }
69944c1bcd4SJean Delvare 
pwm_from_reg(const struct it87_data * data,u8 reg)70044c1bcd4SJean Delvare static int pwm_from_reg(const struct it87_data *data, u8 reg)
70144c1bcd4SJean Delvare {
70216b5dda2SJean Delvare 	if (has_newer_autopwm(data))
70344c1bcd4SJean Delvare 		return reg;
70444c1bcd4SJean Delvare 	else
70544c1bcd4SJean Delvare 		return (reg & 0x7f) << 1;
70644c1bcd4SJean Delvare }
70744c1bcd4SJean Delvare 
DIV_TO_REG(int val)7080df6454dSJean Delvare static int DIV_TO_REG(int val)
7090df6454dSJean Delvare {
7100df6454dSJean Delvare 	int answer = 0;
711c962024eSGuenter Roeck 
7120df6454dSJean Delvare 	while (answer < 7 && (val >>= 1))
7130df6454dSJean Delvare 		answer++;
7140df6454dSJean Delvare 	return answer;
7150df6454dSJean Delvare }
71648b2ae7fSGuenter Roeck 
71748b2ae7fSGuenter Roeck #define DIV_FROM_REG(val) BIT(val)
7180df6454dSJean Delvare 
719f56c9c0aSGuenter Roeck /*
720f56c9c0aSGuenter Roeck  * PWM base frequencies. The frequency has to be divided by either 128 or 256,
721f56c9c0aSGuenter Roeck  * depending on the chip type, to calculate the actual PWM frequency.
722f56c9c0aSGuenter Roeck  *
723f56c9c0aSGuenter Roeck  * Some of the chip datasheets suggest a base frequency of 51 kHz instead
724f56c9c0aSGuenter Roeck  * of 750 kHz for the slowest base frequency, resulting in a PWM frequency
725f56c9c0aSGuenter Roeck  * of 200 Hz. Sometimes both PWM frequency select registers are affected,
726f56c9c0aSGuenter Roeck  * sometimes just one. It is unknown if this is a datasheet error or real,
727f56c9c0aSGuenter Roeck  * so this is ignored for now.
728f56c9c0aSGuenter Roeck  */
7290df6454dSJean Delvare static const unsigned int pwm_freq[8] = {
730f56c9c0aSGuenter Roeck 	48000000,
731f56c9c0aSGuenter Roeck 	24000000,
732f56c9c0aSGuenter Roeck 	12000000,
733f56c9c0aSGuenter Roeck 	8000000,
734f56c9c0aSGuenter Roeck 	6000000,
735f56c9c0aSGuenter Roeck 	3000000,
736f56c9c0aSGuenter Roeck 	1500000,
737f56c9c0aSGuenter Roeck 	750000,
7380df6454dSJean Delvare };
7390df6454dSJean Delvare 
smbus_disable(struct it87_data * data)7409989b3c0SFrank Crawford static int smbus_disable(struct it87_data *data)
7419989b3c0SFrank Crawford {
7429989b3c0SFrank Crawford 	int err;
7439989b3c0SFrank Crawford 
7449989b3c0SFrank Crawford 	if (data->smbus_bitmap) {
7459989b3c0SFrank Crawford 		err = superio_enter(data->sioaddr);
7469989b3c0SFrank Crawford 		if (err)
7479989b3c0SFrank Crawford 			return err;
7489989b3c0SFrank Crawford 		superio_select(data->sioaddr, PME);
7499989b3c0SFrank Crawford 		superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
7509989b3c0SFrank Crawford 			     data->ec_special_config & ~data->smbus_bitmap);
7519989b3c0SFrank Crawford 		superio_exit(data->sioaddr, has_conf_noexit(data));
7529989b3c0SFrank Crawford 	}
7539989b3c0SFrank Crawford 	return 0;
7549989b3c0SFrank Crawford }
7559989b3c0SFrank Crawford 
smbus_enable(struct it87_data * data)7569989b3c0SFrank Crawford static int smbus_enable(struct it87_data *data)
7579989b3c0SFrank Crawford {
7589989b3c0SFrank Crawford 	int err;
7599989b3c0SFrank Crawford 
7609989b3c0SFrank Crawford 	if (data->smbus_bitmap) {
7619989b3c0SFrank Crawford 		err = superio_enter(data->sioaddr);
7629989b3c0SFrank Crawford 		if (err)
7639989b3c0SFrank Crawford 			return err;
7649989b3c0SFrank Crawford 
7659989b3c0SFrank Crawford 		superio_select(data->sioaddr, PME);
7669989b3c0SFrank Crawford 		superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
7679989b3c0SFrank Crawford 			     data->ec_special_config);
7689989b3c0SFrank Crawford 		superio_exit(data->sioaddr, has_conf_noexit(data));
7699989b3c0SFrank Crawford 	}
7709989b3c0SFrank Crawford 	return 0;
7719989b3c0SFrank Crawford }
7729989b3c0SFrank Crawford 
773c1e7a4caSGuenter Roeck /*
774c1e7a4caSGuenter Roeck  * Must be called with data->update_lock held, except during initialization.
775376e1a93SFrank Crawford  * Must be called with SMBus accesses disabled.
776c1e7a4caSGuenter Roeck  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
777c1e7a4caSGuenter Roeck  * would slow down the IT87 access and should not be necessary.
778c1e7a4caSGuenter Roeck  */
it87_read_value(struct it87_data * data,u8 reg)779c1e7a4caSGuenter Roeck static int it87_read_value(struct it87_data *data, u8 reg)
780c1e7a4caSGuenter Roeck {
781c1e7a4caSGuenter Roeck 	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
782c1e7a4caSGuenter Roeck 	return inb_p(data->addr + IT87_DATA_REG_OFFSET);
783c1e7a4caSGuenter Roeck }
7848d5d45fbSJean Delvare 
785c1e7a4caSGuenter Roeck /*
786c1e7a4caSGuenter Roeck  * Must be called with data->update_lock held, except during initialization.
787376e1a93SFrank Crawford  * Must be called with SMBus accesses disabled.
788c1e7a4caSGuenter Roeck  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
789c1e7a4caSGuenter Roeck  * would slow down the IT87 access and should not be necessary.
790c1e7a4caSGuenter Roeck  */
it87_write_value(struct it87_data * data,u8 reg,u8 value)791c1e7a4caSGuenter Roeck static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
792c1e7a4caSGuenter Roeck {
793c1e7a4caSGuenter Roeck 	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
794c1e7a4caSGuenter Roeck 	outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
795c1e7a4caSGuenter Roeck }
7968d5d45fbSJean Delvare 
it87_update_pwm_ctrl(struct it87_data * data,int nr)797c1e7a4caSGuenter Roeck static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
798c1e7a4caSGuenter Roeck {
799c1e7a4caSGuenter Roeck 	data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
800c1e7a4caSGuenter Roeck 	if (has_newer_autopwm(data)) {
8010624d861SGuenter Roeck 		data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
802c1e7a4caSGuenter Roeck 		data->pwm_duty[nr] = it87_read_value(data,
803c1e7a4caSGuenter Roeck 						     IT87_REG_PWM_DUTY[nr]);
804c1e7a4caSGuenter Roeck 	} else {
805c1e7a4caSGuenter Roeck 		if (data->pwm_ctrl[nr] & 0x80)	/* Automatic mode */
806c1e7a4caSGuenter Roeck 			data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
807c1e7a4caSGuenter Roeck 		else				/* Manual mode */
808c1e7a4caSGuenter Roeck 			data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
809c1e7a4caSGuenter Roeck 	}
8108d5d45fbSJean Delvare 
811c1e7a4caSGuenter Roeck 	if (has_old_autopwm(data)) {
812c1e7a4caSGuenter Roeck 		int i;
813c1e7a4caSGuenter Roeck 
814c1e7a4caSGuenter Roeck 		for (i = 0; i < 5 ; i++)
815c1e7a4caSGuenter Roeck 			data->auto_temp[nr][i] = it87_read_value(data,
816c1e7a4caSGuenter Roeck 						IT87_REG_AUTO_TEMP(nr, i));
817c1e7a4caSGuenter Roeck 		for (i = 0; i < 3 ; i++)
818c1e7a4caSGuenter Roeck 			data->auto_pwm[nr][i] = it87_read_value(data,
819c1e7a4caSGuenter Roeck 						IT87_REG_AUTO_PWM(nr, i));
8202cbb9c37SGuenter Roeck 	} else if (has_newer_autopwm(data)) {
8212cbb9c37SGuenter Roeck 		int i;
8222cbb9c37SGuenter Roeck 
8232cbb9c37SGuenter Roeck 		/*
8242cbb9c37SGuenter Roeck 		 * 0: temperature hysteresis (base + 5)
8252cbb9c37SGuenter Roeck 		 * 1: fan off temperature (base + 0)
8262cbb9c37SGuenter Roeck 		 * 2: fan start temperature (base + 1)
8272cbb9c37SGuenter Roeck 		 * 3: fan max temperature (base + 2)
8282cbb9c37SGuenter Roeck 		 */
8292cbb9c37SGuenter Roeck 		data->auto_temp[nr][0] =
8302cbb9c37SGuenter Roeck 			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 5));
8312cbb9c37SGuenter Roeck 
8322cbb9c37SGuenter Roeck 		for (i = 0; i < 3 ; i++)
8332cbb9c37SGuenter Roeck 			data->auto_temp[nr][i + 1] =
8342cbb9c37SGuenter Roeck 				it87_read_value(data,
8352cbb9c37SGuenter Roeck 						IT87_REG_AUTO_TEMP(nr, i));
8362cbb9c37SGuenter Roeck 		/*
8372cbb9c37SGuenter Roeck 		 * 0: start pwm value (base + 3)
8382cbb9c37SGuenter Roeck 		 * 1: pwm slope (base + 4, 1/8th pwm)
8392cbb9c37SGuenter Roeck 		 */
8402cbb9c37SGuenter Roeck 		data->auto_pwm[nr][0] =
8412cbb9c37SGuenter Roeck 			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 3));
8422cbb9c37SGuenter Roeck 		data->auto_pwm[nr][1] =
8432cbb9c37SGuenter Roeck 			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 4));
844c1e7a4caSGuenter Roeck 	}
845c1e7a4caSGuenter Roeck }
846c1e7a4caSGuenter Roeck 
it87_lock(struct it87_data * data)847376e1a93SFrank Crawford static int it87_lock(struct it87_data *data)
848376e1a93SFrank Crawford {
849376e1a93SFrank Crawford 	int err;
850376e1a93SFrank Crawford 
851376e1a93SFrank Crawford 	mutex_lock(&data->update_lock);
852376e1a93SFrank Crawford 	err = smbus_disable(data);
853376e1a93SFrank Crawford 	if (err)
854376e1a93SFrank Crawford 		mutex_unlock(&data->update_lock);
855376e1a93SFrank Crawford 	return err;
856376e1a93SFrank Crawford }
857376e1a93SFrank Crawford 
it87_unlock(struct it87_data * data)858376e1a93SFrank Crawford static void it87_unlock(struct it87_data *data)
859376e1a93SFrank Crawford {
860376e1a93SFrank Crawford 	smbus_enable(data);
861376e1a93SFrank Crawford 	mutex_unlock(&data->update_lock);
862376e1a93SFrank Crawford }
863376e1a93SFrank Crawford 
it87_update_device(struct device * dev)864c1e7a4caSGuenter Roeck static struct it87_data *it87_update_device(struct device *dev)
865c1e7a4caSGuenter Roeck {
866c1e7a4caSGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
867376e1a93SFrank Crawford 	struct it87_data *ret = data;
868376e1a93SFrank Crawford 	int err;
869c1e7a4caSGuenter Roeck 	int i;
870c1e7a4caSGuenter Roeck 
871c1e7a4caSGuenter Roeck 	mutex_lock(&data->update_lock);
872c1e7a4caSGuenter Roeck 
873c962024eSGuenter Roeck 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
874c962024eSGuenter Roeck 		       !data->valid) {
875376e1a93SFrank Crawford 		err = smbus_disable(data);
876376e1a93SFrank Crawford 		if (err) {
877376e1a93SFrank Crawford 			ret = ERR_PTR(err);
878376e1a93SFrank Crawford 			goto unlock;
879376e1a93SFrank Crawford 		}
880c1e7a4caSGuenter Roeck 		if (update_vbat) {
881c1e7a4caSGuenter Roeck 			/*
882c1e7a4caSGuenter Roeck 			 * Cleared after each update, so reenable.  Value
883c1e7a4caSGuenter Roeck 			 * returned by this read will be previous value
884c1e7a4caSGuenter Roeck 			 */
885c1e7a4caSGuenter Roeck 			it87_write_value(data, IT87_REG_CONFIG,
886c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_CONFIG) | 0x40);
887c1e7a4caSGuenter Roeck 		}
8882310048dSGuenter Roeck 		for (i = 0; i < NUM_VIN; i++) {
88948b2ae7fSGuenter Roeck 			if (!(data->has_in & BIT(i)))
890559313c4SGuenter Roeck 				continue;
891559313c4SGuenter Roeck 
892c1e7a4caSGuenter Roeck 			data->in[i][0] =
893559313c4SGuenter Roeck 				it87_read_value(data, IT87_REG_VIN[i]);
894559313c4SGuenter Roeck 
895559313c4SGuenter Roeck 			/* VBAT and AVCC don't have limit registers */
8962310048dSGuenter Roeck 			if (i >= NUM_VIN_LIMIT)
897559313c4SGuenter Roeck 				continue;
898559313c4SGuenter Roeck 
899c1e7a4caSGuenter Roeck 			data->in[i][1] =
900c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_VIN_MIN(i));
901c1e7a4caSGuenter Roeck 			data->in[i][2] =
902c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_VIN_MAX(i));
903c1e7a4caSGuenter Roeck 		}
904c1e7a4caSGuenter Roeck 
9052310048dSGuenter Roeck 		for (i = 0; i < NUM_FAN; i++) {
906c1e7a4caSGuenter Roeck 			/* Skip disabled fans */
90748b2ae7fSGuenter Roeck 			if (!(data->has_fan & BIT(i)))
908c1e7a4caSGuenter Roeck 				continue;
909c1e7a4caSGuenter Roeck 
910c1e7a4caSGuenter Roeck 			data->fan[i][1] =
911c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_FAN_MIN[i]);
912c1e7a4caSGuenter Roeck 			data->fan[i][0] = it87_read_value(data,
913c1e7a4caSGuenter Roeck 				       IT87_REG_FAN[i]);
914c1e7a4caSGuenter Roeck 			/* Add high byte if in 16-bit mode */
915c1e7a4caSGuenter Roeck 			if (has_16bit_fans(data)) {
916c1e7a4caSGuenter Roeck 				data->fan[i][0] |= it87_read_value(data,
917c1e7a4caSGuenter Roeck 						IT87_REG_FANX[i]) << 8;
918c1e7a4caSGuenter Roeck 				data->fan[i][1] |= it87_read_value(data,
919c1e7a4caSGuenter Roeck 						IT87_REG_FANX_MIN[i]) << 8;
920c1e7a4caSGuenter Roeck 			}
921c1e7a4caSGuenter Roeck 		}
9222310048dSGuenter Roeck 		for (i = 0; i < NUM_TEMP; i++) {
92348b2ae7fSGuenter Roeck 			if (!(data->has_temp & BIT(i)))
924c1e7a4caSGuenter Roeck 				continue;
925c1e7a4caSGuenter Roeck 			data->temp[i][0] =
926c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_TEMP(i));
927cc18da79SGuenter Roeck 
9282310048dSGuenter Roeck 			if (has_temp_offset(data) && i < NUM_TEMP_OFFSET)
9292310048dSGuenter Roeck 				data->temp[i][3] =
9302310048dSGuenter Roeck 				  it87_read_value(data,
9312310048dSGuenter Roeck 						  IT87_REG_TEMP_OFFSET[i]);
9322310048dSGuenter Roeck 
9332310048dSGuenter Roeck 			if (i >= NUM_TEMP_LIMIT)
934cc18da79SGuenter Roeck 				continue;
935cc18da79SGuenter Roeck 
936c1e7a4caSGuenter Roeck 			data->temp[i][1] =
937c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_TEMP_LOW(i));
938c1e7a4caSGuenter Roeck 			data->temp[i][2] =
939c1e7a4caSGuenter Roeck 				it87_read_value(data, IT87_REG_TEMP_HIGH(i));
940c1e7a4caSGuenter Roeck 		}
941c1e7a4caSGuenter Roeck 
942c1e7a4caSGuenter Roeck 		/* Newer chips don't have clock dividers */
943c1e7a4caSGuenter Roeck 		if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
944c1e7a4caSGuenter Roeck 			i = it87_read_value(data, IT87_REG_FAN_DIV);
945c1e7a4caSGuenter Roeck 			data->fan_div[0] = i & 0x07;
946c1e7a4caSGuenter Roeck 			data->fan_div[1] = (i >> 3) & 0x07;
947c1e7a4caSGuenter Roeck 			data->fan_div[2] = (i & 0x40) ? 3 : 1;
948c1e7a4caSGuenter Roeck 		}
949c1e7a4caSGuenter Roeck 
950c1e7a4caSGuenter Roeck 		data->alarms =
951c1e7a4caSGuenter Roeck 			it87_read_value(data, IT87_REG_ALARM1) |
952c1e7a4caSGuenter Roeck 			(it87_read_value(data, IT87_REG_ALARM2) << 8) |
953c1e7a4caSGuenter Roeck 			(it87_read_value(data, IT87_REG_ALARM3) << 16);
954c1e7a4caSGuenter Roeck 		data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
955c1e7a4caSGuenter Roeck 
956c1e7a4caSGuenter Roeck 		data->fan_main_ctrl = it87_read_value(data,
957c1e7a4caSGuenter Roeck 				IT87_REG_FAN_MAIN_CTRL);
958c1e7a4caSGuenter Roeck 		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
9590624d861SGuenter Roeck 		for (i = 0; i < NUM_PWM; i++) {
9600624d861SGuenter Roeck 			if (!(data->has_pwm & BIT(i)))
9610624d861SGuenter Roeck 				continue;
962c1e7a4caSGuenter Roeck 			it87_update_pwm_ctrl(data, i);
9630624d861SGuenter Roeck 		}
964c1e7a4caSGuenter Roeck 
965c1e7a4caSGuenter Roeck 		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
966c1e7a4caSGuenter Roeck 		data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
967c1e7a4caSGuenter Roeck 		/*
968c1e7a4caSGuenter Roeck 		 * The IT8705F does not have VID capability.
969c1e7a4caSGuenter Roeck 		 * The IT8718F and later don't use IT87_REG_VID for the
970c1e7a4caSGuenter Roeck 		 * same purpose.
971c1e7a4caSGuenter Roeck 		 */
972c1e7a4caSGuenter Roeck 		if (data->type == it8712 || data->type == it8716) {
973c1e7a4caSGuenter Roeck 			data->vid = it87_read_value(data, IT87_REG_VID);
974c1e7a4caSGuenter Roeck 			/*
975c1e7a4caSGuenter Roeck 			 * The older IT8712F revisions had only 5 VID pins,
976c1e7a4caSGuenter Roeck 			 * but we assume it is always safe to read 6 bits.
977c1e7a4caSGuenter Roeck 			 */
978c1e7a4caSGuenter Roeck 			data->vid &= 0x3f;
979c1e7a4caSGuenter Roeck 		}
980c1e7a4caSGuenter Roeck 		data->last_updated = jiffies;
981952a11caSPaul Fertser 		data->valid = true;
982376e1a93SFrank Crawford 		smbus_enable(data);
983c1e7a4caSGuenter Roeck 	}
984376e1a93SFrank Crawford unlock:
985c1e7a4caSGuenter Roeck 	mutex_unlock(&data->update_lock);
986376e1a93SFrank Crawford 	return ret;
987c1e7a4caSGuenter Roeck }
988fde09509SJean Delvare 
show_in(struct device * dev,struct device_attribute * attr,char * buf)9898d5d45fbSJean Delvare static ssize_t show_in(struct device *dev, struct device_attribute *attr,
9908d5d45fbSJean Delvare 		       char *buf)
9918d5d45fbSJean Delvare {
992929c6a56SGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
9938d5d45fbSJean Delvare 	struct it87_data *data = it87_update_device(dev);
994c962024eSGuenter Roeck 	int index = sattr->index;
995c962024eSGuenter Roeck 	int nr = sattr->nr;
996c962024eSGuenter Roeck 
9970282ba4aSFrank Crawford 	if (IS_ERR(data))
9980282ba4aSFrank Crawford 		return PTR_ERR(data);
9990282ba4aSFrank Crawford 
1000929c6a56SGuenter Roeck 	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
10018d5d45fbSJean Delvare }
10028d5d45fbSJean Delvare 
set_in(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1003929c6a56SGuenter Roeck static ssize_t set_in(struct device *dev, struct device_attribute *attr,
10048d5d45fbSJean Delvare 		      const char *buf, size_t count)
10058d5d45fbSJean Delvare {
1006929c6a56SGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1007b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1008c962024eSGuenter Roeck 	int index = sattr->index;
1009c962024eSGuenter Roeck 	int nr = sattr->nr;
1010f5f64501SJean Delvare 	unsigned long val;
1011376e1a93SFrank Crawford 	int err;
1012f5f64501SJean Delvare 
1013179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &val) < 0)
1014f5f64501SJean Delvare 		return -EINVAL;
10158d5d45fbSJean Delvare 
1016376e1a93SFrank Crawford 	err = it87_lock(data);
1017376e1a93SFrank Crawford 	if (err)
1018376e1a93SFrank Crawford 		return err;
1019376e1a93SFrank Crawford 
1020929c6a56SGuenter Roeck 	data->in[nr][index] = in_to_reg(data, nr, val);
1021929c6a56SGuenter Roeck 	it87_write_value(data,
1022929c6a56SGuenter Roeck 			 index == 1 ? IT87_REG_VIN_MIN(nr)
1023929c6a56SGuenter Roeck 				    : IT87_REG_VIN_MAX(nr),
1024929c6a56SGuenter Roeck 			 data->in[nr][index]);
1025376e1a93SFrank Crawford 	it87_unlock(data);
10268d5d45fbSJean Delvare 	return count;
10278d5d45fbSJean Delvare }
10288d5d45fbSJean Delvare 
1029929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
1030929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
1031929c6a56SGuenter Roeck 			    0, 1);
1032929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
1033929c6a56SGuenter Roeck 			    0, 2);
10348d5d45fbSJean Delvare 
1035929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
1036929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
1037929c6a56SGuenter Roeck 			    1, 1);
1038929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
1039929c6a56SGuenter Roeck 			    1, 2);
10408d5d45fbSJean Delvare 
1041929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
1042929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
1043929c6a56SGuenter Roeck 			    2, 1);
1044929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
1045929c6a56SGuenter Roeck 			    2, 2);
1046929c6a56SGuenter Roeck 
1047929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
1048929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
1049929c6a56SGuenter Roeck 			    3, 1);
1050929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
1051929c6a56SGuenter Roeck 			    3, 2);
1052929c6a56SGuenter Roeck 
1053929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
1054929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
1055929c6a56SGuenter Roeck 			    4, 1);
1056929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
1057929c6a56SGuenter Roeck 			    4, 2);
1058929c6a56SGuenter Roeck 
1059929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0);
1060929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
1061929c6a56SGuenter Roeck 			    5, 1);
1062929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
1063929c6a56SGuenter Roeck 			    5, 2);
1064929c6a56SGuenter Roeck 
1065929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0);
1066929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in,
1067929c6a56SGuenter Roeck 			    6, 1);
1068929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in,
1069929c6a56SGuenter Roeck 			    6, 2);
1070929c6a56SGuenter Roeck 
1071929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0);
1072929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in,
1073929c6a56SGuenter Roeck 			    7, 1);
1074929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
1075929c6a56SGuenter Roeck 			    7, 2);
1076929c6a56SGuenter Roeck 
1077929c6a56SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
1078c145d5c6SRudolf Marek static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);
1079f838aa26SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 10, 0);
1080f838aa26SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in, NULL, 11, 0);
1081f838aa26SGuenter Roeck static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in, NULL, 12, 0);
10828d5d45fbSJean Delvare 
1083cc18da79SGuenter Roeck /* Up to 6 temperatures */
show_temp(struct device * dev,struct device_attribute * attr,char * buf)10848d5d45fbSJean Delvare static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
10858d5d45fbSJean Delvare 			 char *buf)
10868d5d45fbSJean Delvare {
108760ca385aSGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
108860ca385aSGuenter Roeck 	int nr = sattr->nr;
108960ca385aSGuenter Roeck 	int index = sattr->index;
10908d5d45fbSJean Delvare 	struct it87_data *data = it87_update_device(dev);
10918d5d45fbSJean Delvare 
10920282ba4aSFrank Crawford 	if (IS_ERR(data))
10930282ba4aSFrank Crawford 		return PTR_ERR(data);
10940282ba4aSFrank Crawford 
109560ca385aSGuenter Roeck 	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
10968d5d45fbSJean Delvare }
10978d5d45fbSJean Delvare 
set_temp(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)109860ca385aSGuenter Roeck static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
10998d5d45fbSJean Delvare 			const char *buf, size_t count)
11008d5d45fbSJean Delvare {
110160ca385aSGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
110260ca385aSGuenter Roeck 	int nr = sattr->nr;
110360ca385aSGuenter Roeck 	int index = sattr->index;
1104b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1105f5f64501SJean Delvare 	long val;
1106161d898aSGuenter Roeck 	u8 reg, regval;
1107376e1a93SFrank Crawford 	int err;
1108f5f64501SJean Delvare 
1109179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0)
1110f5f64501SJean Delvare 		return -EINVAL;
11118d5d45fbSJean Delvare 
1112376e1a93SFrank Crawford 	err = it87_lock(data);
1113376e1a93SFrank Crawford 	if (err)
1114376e1a93SFrank Crawford 		return err;
1115161d898aSGuenter Roeck 
1116161d898aSGuenter Roeck 	switch (index) {
1117161d898aSGuenter Roeck 	default:
1118161d898aSGuenter Roeck 	case 1:
1119161d898aSGuenter Roeck 		reg = IT87_REG_TEMP_LOW(nr);
1120161d898aSGuenter Roeck 		break;
1121161d898aSGuenter Roeck 	case 2:
1122161d898aSGuenter Roeck 		reg = IT87_REG_TEMP_HIGH(nr);
1123161d898aSGuenter Roeck 		break;
1124161d898aSGuenter Roeck 	case 3:
1125161d898aSGuenter Roeck 		regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
1126161d898aSGuenter Roeck 		if (!(regval & 0x80)) {
1127161d898aSGuenter Roeck 			regval |= 0x80;
1128161d898aSGuenter Roeck 			it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
1129161d898aSGuenter Roeck 		}
1130952a11caSPaul Fertser 		data->valid = false;
1131161d898aSGuenter Roeck 		reg = IT87_REG_TEMP_OFFSET[nr];
1132161d898aSGuenter Roeck 		break;
1133161d898aSGuenter Roeck 	}
1134161d898aSGuenter Roeck 
113560ca385aSGuenter Roeck 	data->temp[nr][index] = TEMP_TO_REG(val);
1136161d898aSGuenter Roeck 	it87_write_value(data, reg, data->temp[nr][index]);
1137376e1a93SFrank Crawford 	it87_unlock(data);
11388d5d45fbSJean Delvare 	return count;
11398d5d45fbSJean Delvare }
11408d5d45fbSJean Delvare 
114160ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
114260ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
114360ca385aSGuenter Roeck 			    0, 1);
114460ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
114560ca385aSGuenter Roeck 			    0, 2);
1146161d898aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
1147161d898aSGuenter Roeck 			    set_temp, 0, 3);
114860ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
114960ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
115060ca385aSGuenter Roeck 			    1, 1);
115160ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
115260ca385aSGuenter Roeck 			    1, 2);
1153161d898aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
1154161d898aSGuenter Roeck 			    set_temp, 1, 3);
115560ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
115660ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
115760ca385aSGuenter Roeck 			    2, 1);
115860ca385aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
115960ca385aSGuenter Roeck 			    2, 2);
1160161d898aSGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
1161161d898aSGuenter Roeck 			    set_temp, 2, 3);
1162cc18da79SGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
1163cc18da79SGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
1164cc18da79SGuenter Roeck static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
11658d5d45fbSJean Delvare 
get_temp_type(struct it87_data * data,int index)11664018e0a9SFrank Crawford static int get_temp_type(struct it87_data *data, int index)
11678d5d45fbSJean Delvare {
11684018e0a9SFrank Crawford 	/*
11694018e0a9SFrank Crawford 	 * 2 is deprecated;
11704018e0a9SFrank Crawford 	 * 3 = thermal diode;
11714018e0a9SFrank Crawford 	 * 4 = thermistor;
11724018e0a9SFrank Crawford 	 * 5 = AMDTSI;
11734018e0a9SFrank Crawford 	 * 6 = Intel PECI;
11744018e0a9SFrank Crawford 	 * 0 = disabled
11754018e0a9SFrank Crawford 	 */
11760282ba4aSFrank Crawford 	u8 reg, extra;
1177*6593eac8SFrank Crawford 	int ttype, type = 0;
11780282ba4aSFrank Crawford 
1179*6593eac8SFrank Crawford 	/* Detect PECI vs. AMDTSI */
1180*6593eac8SFrank Crawford 	ttype = 6;
1181*6593eac8SFrank Crawford 	if ((has_temp_peci(data, index)) || data->type == it8721 ||
1182*6593eac8SFrank Crawford 	    data->type == it8720) {
1183*6593eac8SFrank Crawford 		extra = it87_read_value(data, IT87_REG_IFSEL);
1184*6593eac8SFrank Crawford 		if ((extra & 0x70) == 0x40)
1185*6593eac8SFrank Crawford 			ttype = 5;
1186*6593eac8SFrank Crawford 	}
1187*6593eac8SFrank Crawford 
1188*6593eac8SFrank Crawford 	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
1189*6593eac8SFrank Crawford 
1190*6593eac8SFrank Crawford 	/* Per chip special detection */
1191*6593eac8SFrank Crawford 	switch (data->type) {
1192*6593eac8SFrank Crawford 	case it8622:
1193*6593eac8SFrank Crawford 		if (!(reg & 0xc0) && index == 3)
1194*6593eac8SFrank Crawford 			type = ttype;
1195*6593eac8SFrank Crawford 		break;
1196*6593eac8SFrank Crawford 	default:
1197*6593eac8SFrank Crawford 		break;
1198*6593eac8SFrank Crawford 	}
1199*6593eac8SFrank Crawford 
1200*6593eac8SFrank Crawford 	if (type || index >= 3)
1201*6593eac8SFrank Crawford 		return type;
1202*6593eac8SFrank Crawford 
1203*6593eac8SFrank Crawford 	extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
12048d5d45fbSJean Delvare 
12054018e0a9SFrank Crawford 	if ((has_temp_peci(data, index) && (reg >> 6 == index + 1)) ||
12064018e0a9SFrank Crawford 	    (has_temp_old_peci(data, index) && (extra & 0x80)))
1207*6593eac8SFrank Crawford 		type = ttype;	/* Intel PECI or AMDTSI */
12084018e0a9SFrank Crawford 	else if (reg & BIT(index))
12094018e0a9SFrank Crawford 		type = 3;	/* thermal diode */
12104018e0a9SFrank Crawford 	else if (reg & BIT(index + 3))
12114018e0a9SFrank Crawford 		type = 4;	/* thermistor */
12124018e0a9SFrank Crawford 
12134018e0a9SFrank Crawford 	return type;
12144018e0a9SFrank Crawford }
12154018e0a9SFrank Crawford 
show_temp_type(struct device * dev,struct device_attribute * attr,char * buf)12164018e0a9SFrank Crawford static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
12174018e0a9SFrank Crawford 			      char *buf)
12184018e0a9SFrank Crawford {
12194018e0a9SFrank Crawford 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
12204018e0a9SFrank Crawford 	struct it87_data *data = it87_update_device(dev);
12214018e0a9SFrank Crawford 
12224018e0a9SFrank Crawford 	if (IS_ERR(data))
12234018e0a9SFrank Crawford 		return PTR_ERR(data);
12244018e0a9SFrank Crawford 
12254018e0a9SFrank Crawford 	return sprintf(buf, "%d\n", get_temp_type(data, sensor_attr->index));
12268d5d45fbSJean Delvare }
12272cece01fSGuenter Roeck 
set_temp_type(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)12282cece01fSGuenter Roeck static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
12298d5d45fbSJean Delvare 			     const char *buf, size_t count)
12308d5d45fbSJean Delvare {
12318d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
12328d5d45fbSJean Delvare 	int nr = sensor_attr->index;
12338d5d45fbSJean Delvare 
1234b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1235f5f64501SJean Delvare 	long val;
123619529784SGuenter Roeck 	u8 reg, extra;
1237376e1a93SFrank Crawford 	int err;
1238f5f64501SJean Delvare 
1239179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0)
1240f5f64501SJean Delvare 		return -EINVAL;
12418d5d45fbSJean Delvare 
1242376e1a93SFrank Crawford 	err = it87_lock(data);
1243376e1a93SFrank Crawford 	if (err)
1244376e1a93SFrank Crawford 		return err;
1245376e1a93SFrank Crawford 
12468acf07c5SJean Delvare 	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
12478acf07c5SJean Delvare 	reg &= ~(1 << nr);
12488acf07c5SJean Delvare 	reg &= ~(8 << nr);
12495d8d2f2bSGuenter Roeck 	if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6))
12505d8d2f2bSGuenter Roeck 		reg &= 0x3f;
125119529784SGuenter Roeck 	extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
125219529784SGuenter Roeck 	if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6))
125319529784SGuenter Roeck 		extra &= 0x7f;
12544ed10779SJean Delvare 	if (val == 2) {	/* backwards compatibility */
12551d9bcf6aSGuenter Roeck 		dev_warn(dev,
12561d9bcf6aSGuenter Roeck 			 "Sensor type 2 is deprecated, please use 4 instead\n");
12574ed10779SJean Delvare 		val = 4;
12584ed10779SJean Delvare 	}
12595d8d2f2bSGuenter Roeck 	/* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */
12608d5d45fbSJean Delvare 	if (val == 3)
12618acf07c5SJean Delvare 		reg |= 1 << nr;
12624ed10779SJean Delvare 	else if (val == 4)
12638acf07c5SJean Delvare 		reg |= 8 << nr;
12645d8d2f2bSGuenter Roeck 	else if (has_temp_peci(data, nr) && val == 6)
12655d8d2f2bSGuenter Roeck 		reg |= (nr + 1) << 6;
126619529784SGuenter Roeck 	else if (has_temp_old_peci(data, nr) && val == 6)
126719529784SGuenter Roeck 		extra |= 0x80;
1268376e1a93SFrank Crawford 	else if (val != 0) {
1269376e1a93SFrank Crawford 		count = -EINVAL;
1270376e1a93SFrank Crawford 		goto unlock;
1271376e1a93SFrank Crawford 	}
12728acf07c5SJean Delvare 
12738acf07c5SJean Delvare 	data->sensor = reg;
127419529784SGuenter Roeck 	data->extra = extra;
1275b74f3fddScorentin.labbe 	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
127619529784SGuenter Roeck 	if (has_temp_old_peci(data, nr))
127719529784SGuenter Roeck 		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
1278952a11caSPaul Fertser 	data->valid = false;	/* Force cache refresh */
1279376e1a93SFrank Crawford unlock:
1280376e1a93SFrank Crawford 	it87_unlock(data);
12818d5d45fbSJean Delvare 	return count;
12828d5d45fbSJean Delvare }
12838d5d45fbSJean Delvare 
12842cece01fSGuenter Roeck static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
12852cece01fSGuenter Roeck 			  set_temp_type, 0);
12862cece01fSGuenter Roeck static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
12872cece01fSGuenter Roeck 			  set_temp_type, 1);
12882cece01fSGuenter Roeck static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
12892cece01fSGuenter Roeck 			  set_temp_type, 2);
12908d5d45fbSJean Delvare 
1291f1bbe618SGuenter Roeck /* 6 Fans */
1292b99883dcSJean Delvare 
pwm_mode(const struct it87_data * data,int nr)1293b99883dcSJean Delvare static int pwm_mode(const struct it87_data *data, int nr)
1294b99883dcSJean Delvare {
1295317840cfSFrank Crawford 	if (has_fanctl_onoff(data) && nr < 3 &&
1296317840cfSFrank Crawford 	    !(data->fan_main_ctrl & BIT(nr)))
1297f1bbe618SGuenter Roeck 		return 0;			/* Full speed */
1298f1bbe618SGuenter Roeck 	if (data->pwm_ctrl[nr] & 0x80)
1299f1bbe618SGuenter Roeck 		return 2;			/* Automatic mode */
1300317840cfSFrank Crawford 	if ((!has_fanctl_onoff(data) || nr >= 3) &&
1301f1bbe618SGuenter Roeck 	    data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
1302f1bbe618SGuenter Roeck 		return 0;			/* Full speed */
1303b99883dcSJean Delvare 
1304f1bbe618SGuenter Roeck 	return 1;				/* Manual mode */
1305b99883dcSJean Delvare }
1306b99883dcSJean Delvare 
show_fan(struct device * dev,struct device_attribute * attr,char * buf)13078d5d45fbSJean Delvare static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
13088d5d45fbSJean Delvare 			char *buf)
13098d5d45fbSJean Delvare {
1310e1169ba0SGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1311e1169ba0SGuenter Roeck 	int nr = sattr->nr;
1312e1169ba0SGuenter Roeck 	int index = sattr->index;
1313e1169ba0SGuenter Roeck 	int speed;
13148d5d45fbSJean Delvare 	struct it87_data *data = it87_update_device(dev);
13158d5d45fbSJean Delvare 
13160282ba4aSFrank Crawford 	if (IS_ERR(data))
13170282ba4aSFrank Crawford 		return PTR_ERR(data);
13180282ba4aSFrank Crawford 
1319e1169ba0SGuenter Roeck 	speed = has_16bit_fans(data) ?
1320e1169ba0SGuenter Roeck 		FAN16_FROM_REG(data->fan[nr][index]) :
1321e1169ba0SGuenter Roeck 		FAN_FROM_REG(data->fan[nr][index],
1322e1169ba0SGuenter Roeck 			     DIV_FROM_REG(data->fan_div[nr]));
1323e1169ba0SGuenter Roeck 	return sprintf(buf, "%d\n", speed);
13248d5d45fbSJean Delvare }
1325e1169ba0SGuenter Roeck 
show_fan_div(struct device * dev,struct device_attribute * attr,char * buf)13268d5d45fbSJean Delvare static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
13278d5d45fbSJean Delvare 			    char *buf)
13288d5d45fbSJean Delvare {
13298d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1330c962024eSGuenter Roeck 	struct it87_data *data = it87_update_device(dev);
13318d5d45fbSJean Delvare 	int nr = sensor_attr->index;
13328d5d45fbSJean Delvare 
13330282ba4aSFrank Crawford 	if (IS_ERR(data))
13340282ba4aSFrank Crawford 		return PTR_ERR(data);
13350282ba4aSFrank Crawford 
133648b2ae7fSGuenter Roeck 	return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
13378d5d45fbSJean Delvare }
1338c962024eSGuenter Roeck 
show_pwm_enable(struct device * dev,struct device_attribute * attr,char * buf)13395f2dc798SJean Delvare static ssize_t show_pwm_enable(struct device *dev,
13405f2dc798SJean Delvare 			       struct device_attribute *attr, char *buf)
13418d5d45fbSJean Delvare {
13428d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1343c962024eSGuenter Roeck 	struct it87_data *data = it87_update_device(dev);
13448d5d45fbSJean Delvare 	int nr = sensor_attr->index;
13458d5d45fbSJean Delvare 
13460282ba4aSFrank Crawford 	if (IS_ERR(data))
13470282ba4aSFrank Crawford 		return PTR_ERR(data);
13480282ba4aSFrank Crawford 
1349b99883dcSJean Delvare 	return sprintf(buf, "%d\n", pwm_mode(data, nr));
13508d5d45fbSJean Delvare }
1351c962024eSGuenter Roeck 
show_pwm(struct device * dev,struct device_attribute * attr,char * buf)13528d5d45fbSJean Delvare static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
13538d5d45fbSJean Delvare 			char *buf)
13548d5d45fbSJean Delvare {
13558d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1356c962024eSGuenter Roeck 	struct it87_data *data = it87_update_device(dev);
13578d5d45fbSJean Delvare 	int nr = sensor_attr->index;
13588d5d45fbSJean Delvare 
13590282ba4aSFrank Crawford 	if (IS_ERR(data))
13600282ba4aSFrank Crawford 		return PTR_ERR(data);
13610282ba4aSFrank Crawford 
136244c1bcd4SJean Delvare 	return sprintf(buf, "%d\n",
136344c1bcd4SJean Delvare 		       pwm_from_reg(data, data->pwm_duty[nr]));
13648d5d45fbSJean Delvare }
1365c962024eSGuenter Roeck 
show_pwm_freq(struct device * dev,struct device_attribute * attr,char * buf)1366f8d0c19aSJean Delvare static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
1367f8d0c19aSJean Delvare 			     char *buf)
1368f8d0c19aSJean Delvare {
136960878bcfSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1370f8d0c19aSJean Delvare 	struct it87_data *data = it87_update_device(dev);
137160878bcfSGuenter Roeck 	int nr = sensor_attr->index;
1372f56c9c0aSGuenter Roeck 	unsigned int freq;
137360878bcfSGuenter Roeck 	int index;
137460878bcfSGuenter Roeck 
13750282ba4aSFrank Crawford 	if (IS_ERR(data))
13760282ba4aSFrank Crawford 		return PTR_ERR(data);
13770282ba4aSFrank Crawford 
137860878bcfSGuenter Roeck 	if (has_pwm_freq2(data) && nr == 1)
137960878bcfSGuenter Roeck 		index = (data->extra >> 4) & 0x07;
138060878bcfSGuenter Roeck 	else
138160878bcfSGuenter Roeck 		index = (data->fan_ctl >> 4) & 0x07;
1382f8d0c19aSJean Delvare 
1383f56c9c0aSGuenter Roeck 	freq = pwm_freq[index] / (has_newer_autopwm(data) ? 256 : 128);
1384f56c9c0aSGuenter Roeck 
1385f56c9c0aSGuenter Roeck 	return sprintf(buf, "%u\n", freq);
1386f8d0c19aSJean Delvare }
1387e1169ba0SGuenter Roeck 
set_fan(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1388e1169ba0SGuenter Roeck static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
13898d5d45fbSJean Delvare 		       const char *buf, size_t count)
13908d5d45fbSJean Delvare {
1391e1169ba0SGuenter Roeck 	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
1392e1169ba0SGuenter Roeck 	int nr = sattr->nr;
1393e1169ba0SGuenter Roeck 	int index = sattr->index;
13948d5d45fbSJean Delvare 
1395b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1396f5f64501SJean Delvare 	long val;
1397376e1a93SFrank Crawford 	int err;
13987f999aa7SJean Delvare 	u8 reg;
13998d5d45fbSJean Delvare 
1400179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0)
1401f5f64501SJean Delvare 		return -EINVAL;
1402f5f64501SJean Delvare 
1403376e1a93SFrank Crawford 	err = it87_lock(data);
1404376e1a93SFrank Crawford 	if (err)
1405376e1a93SFrank Crawford 		return err;
1406e1169ba0SGuenter Roeck 
1407e1169ba0SGuenter Roeck 	if (has_16bit_fans(data)) {
1408e1169ba0SGuenter Roeck 		data->fan[nr][index] = FAN16_TO_REG(val);
1409e1169ba0SGuenter Roeck 		it87_write_value(data, IT87_REG_FAN_MIN[nr],
1410e1169ba0SGuenter Roeck 				 data->fan[nr][index] & 0xff);
1411e1169ba0SGuenter Roeck 		it87_write_value(data, IT87_REG_FANX_MIN[nr],
1412e1169ba0SGuenter Roeck 				 data->fan[nr][index] >> 8);
1413e1169ba0SGuenter Roeck 	} else {
1414b74f3fddScorentin.labbe 		reg = it87_read_value(data, IT87_REG_FAN_DIV);
141507eab46dSJean Delvare 		switch (nr) {
14165f2dc798SJean Delvare 		case 0:
14175f2dc798SJean Delvare 			data->fan_div[nr] = reg & 0x07;
14185f2dc798SJean Delvare 			break;
14195f2dc798SJean Delvare 		case 1:
14205f2dc798SJean Delvare 			data->fan_div[nr] = (reg >> 3) & 0x07;
14215f2dc798SJean Delvare 			break;
14225f2dc798SJean Delvare 		case 2:
14235f2dc798SJean Delvare 			data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
14245f2dc798SJean Delvare 			break;
142507eab46dSJean Delvare 		}
1426e1169ba0SGuenter Roeck 		data->fan[nr][index] =
1427e1169ba0SGuenter Roeck 		  FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
1428e1169ba0SGuenter Roeck 		it87_write_value(data, IT87_REG_FAN_MIN[nr],
1429e1169ba0SGuenter Roeck 				 data->fan[nr][index]);
1430e1169ba0SGuenter Roeck 	}
143107eab46dSJean Delvare 
1432376e1a93SFrank Crawford 	it87_unlock(data);
14338d5d45fbSJean Delvare 	return count;
14348d5d45fbSJean Delvare }
1435e1169ba0SGuenter Roeck 
set_fan_div(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)14368d5d45fbSJean Delvare static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
14378d5d45fbSJean Delvare 			   const char *buf, size_t count)
14388d5d45fbSJean Delvare {
14398d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1440b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1441c962024eSGuenter Roeck 	int nr = sensor_attr->index;
1442f5f64501SJean Delvare 	unsigned long val;
1443376e1a93SFrank Crawford 	int min, err;
14448d5d45fbSJean Delvare 	u8 old;
14458d5d45fbSJean Delvare 
1446179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &val) < 0)
1447f5f64501SJean Delvare 		return -EINVAL;
1448f5f64501SJean Delvare 
1449376e1a93SFrank Crawford 	err = it87_lock(data);
1450376e1a93SFrank Crawford 	if (err)
1451376e1a93SFrank Crawford 		return err;
1452376e1a93SFrank Crawford 
1453b74f3fddScorentin.labbe 	old = it87_read_value(data, IT87_REG_FAN_DIV);
14548d5d45fbSJean Delvare 
14558ab4ec3eSJean Delvare 	/* Save fan min limit */
1456e1169ba0SGuenter Roeck 	min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr]));
14578d5d45fbSJean Delvare 
14588d5d45fbSJean Delvare 	switch (nr) {
14598d5d45fbSJean Delvare 	case 0:
14608d5d45fbSJean Delvare 	case 1:
14618d5d45fbSJean Delvare 		data->fan_div[nr] = DIV_TO_REG(val);
14628d5d45fbSJean Delvare 		break;
14638d5d45fbSJean Delvare 	case 2:
14648d5d45fbSJean Delvare 		if (val < 8)
14658d5d45fbSJean Delvare 			data->fan_div[nr] = 1;
14668d5d45fbSJean Delvare 		else
14678d5d45fbSJean Delvare 			data->fan_div[nr] = 3;
14688d5d45fbSJean Delvare 	}
14698d5d45fbSJean Delvare 	val = old & 0x80;
14708d5d45fbSJean Delvare 	val |= (data->fan_div[0] & 0x07);
14718d5d45fbSJean Delvare 	val |= (data->fan_div[1] & 0x07) << 3;
14728d5d45fbSJean Delvare 	if (data->fan_div[2] == 3)
14738d5d45fbSJean Delvare 		val |= 0x1 << 6;
1474b74f3fddScorentin.labbe 	it87_write_value(data, IT87_REG_FAN_DIV, val);
14758d5d45fbSJean Delvare 
14768ab4ec3eSJean Delvare 	/* Restore fan min limit */
1477e1169ba0SGuenter Roeck 	data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
1478e1169ba0SGuenter Roeck 	it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
14798ab4ec3eSJean Delvare 
1480376e1a93SFrank Crawford 	it87_unlock(data);
14818d5d45fbSJean Delvare 	return count;
14828d5d45fbSJean Delvare }
1483cccfc9c4SJean Delvare 
1484cccfc9c4SJean Delvare /* Returns 0 if OK, -EINVAL otherwise */
check_trip_points(struct device * dev,int nr)1485cccfc9c4SJean Delvare static int check_trip_points(struct device *dev, int nr)
1486cccfc9c4SJean Delvare {
1487cccfc9c4SJean Delvare 	const struct it87_data *data = dev_get_drvdata(dev);
1488cccfc9c4SJean Delvare 	int i, err = 0;
1489cccfc9c4SJean Delvare 
1490cccfc9c4SJean Delvare 	if (has_old_autopwm(data)) {
1491cccfc9c4SJean Delvare 		for (i = 0; i < 3; i++) {
1492cccfc9c4SJean Delvare 			if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
1493cccfc9c4SJean Delvare 				err = -EINVAL;
1494cccfc9c4SJean Delvare 		}
1495cccfc9c4SJean Delvare 		for (i = 0; i < 2; i++) {
1496cccfc9c4SJean Delvare 			if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
1497cccfc9c4SJean Delvare 				err = -EINVAL;
1498cccfc9c4SJean Delvare 		}
14992cbb9c37SGuenter Roeck 	} else if (has_newer_autopwm(data)) {
15002cbb9c37SGuenter Roeck 		for (i = 1; i < 3; i++) {
15012cbb9c37SGuenter Roeck 			if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
15022cbb9c37SGuenter Roeck 				err = -EINVAL;
15032cbb9c37SGuenter Roeck 		}
1504cccfc9c4SJean Delvare 	}
1505cccfc9c4SJean Delvare 
1506cccfc9c4SJean Delvare 	if (err) {
15071d9bcf6aSGuenter Roeck 		dev_err(dev,
15081d9bcf6aSGuenter Roeck 			"Inconsistent trip points, not switching to automatic mode\n");
1509cccfc9c4SJean Delvare 		dev_err(dev, "Adjust the trip points and try again\n");
1510cccfc9c4SJean Delvare 	}
1511cccfc9c4SJean Delvare 	return err;
1512cccfc9c4SJean Delvare }
1513cccfc9c4SJean Delvare 
set_pwm_enable(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1514c962024eSGuenter Roeck static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
1515c962024eSGuenter Roeck 			      const char *buf, size_t count)
15168d5d45fbSJean Delvare {
15178d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1518b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1519c962024eSGuenter Roeck 	int nr = sensor_attr->index;
1520f5f64501SJean Delvare 	long val;
1521376e1a93SFrank Crawford 	int err;
15228d5d45fbSJean Delvare 
1523179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
1524b99883dcSJean Delvare 		return -EINVAL;
1525b99883dcSJean Delvare 
1526cccfc9c4SJean Delvare 	/* Check trip points before switching to automatic mode */
1527cccfc9c4SJean Delvare 	if (val == 2) {
1528cccfc9c4SJean Delvare 		if (check_trip_points(dev, nr) < 0)
1529cccfc9c4SJean Delvare 			return -EINVAL;
1530cccfc9c4SJean Delvare 	}
1531cccfc9c4SJean Delvare 
1532376e1a93SFrank Crawford 	err = it87_lock(data);
1533376e1a93SFrank Crawford 	if (err)
1534376e1a93SFrank Crawford 		return err;
15358d5d45fbSJean Delvare 
15368d5d45fbSJean Delvare 	if (val == 0) {
1537317840cfSFrank Crawford 		if (nr < 3 && has_fanctl_onoff(data)) {
15388d5d45fbSJean Delvare 			int tmp;
15398d5d45fbSJean Delvare 			/* make sure the fan is on when in on/off mode */
1540b74f3fddScorentin.labbe 			tmp = it87_read_value(data, IT87_REG_FAN_CTL);
154148b2ae7fSGuenter Roeck 			it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr));
15428d5d45fbSJean Delvare 			/* set on/off mode */
154348b2ae7fSGuenter Roeck 			data->fan_main_ctrl &= ~BIT(nr);
15445f2dc798SJean Delvare 			it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
15455f2dc798SJean Delvare 					 data->fan_main_ctrl);
1546b99883dcSJean Delvare 		} else {
15474c7b8ca1SGuenter Roeck 			u8 ctrl;
15484c7b8ca1SGuenter Roeck 
1549f1bbe618SGuenter Roeck 			/* No on/off mode, set maximum pwm value */
1550f1bbe618SGuenter Roeck 			data->pwm_duty[nr] = pwm_to_reg(data, 0xff);
1551f1bbe618SGuenter Roeck 			it87_write_value(data, IT87_REG_PWM_DUTY[nr],
1552f1bbe618SGuenter Roeck 					 data->pwm_duty[nr]);
1553f1bbe618SGuenter Roeck 			/* and set manual mode */
15544c7b8ca1SGuenter Roeck 			if (has_newer_autopwm(data)) {
15554c7b8ca1SGuenter Roeck 				ctrl = (data->pwm_ctrl[nr] & 0x7c) |
15564c7b8ca1SGuenter Roeck 					data->pwm_temp_map[nr];
15574c7b8ca1SGuenter Roeck 			} else {
15584c7b8ca1SGuenter Roeck 				ctrl = data->pwm_duty[nr];
15594c7b8ca1SGuenter Roeck 			}
15604c7b8ca1SGuenter Roeck 			data->pwm_ctrl[nr] = ctrl;
15614c7b8ca1SGuenter Roeck 			it87_write_value(data, IT87_REG_PWM[nr], ctrl);
1562f1bbe618SGuenter Roeck 		}
1563f1bbe618SGuenter Roeck 	} else {
15644c7b8ca1SGuenter Roeck 		u8 ctrl;
15654c7b8ca1SGuenter Roeck 
15664c7b8ca1SGuenter Roeck 		if (has_newer_autopwm(data)) {
15674c7b8ca1SGuenter Roeck 			ctrl = (data->pwm_ctrl[nr] & 0x7c) |
15684c7b8ca1SGuenter Roeck 				data->pwm_temp_map[nr];
15694c7b8ca1SGuenter Roeck 			if (val != 1)
15704c7b8ca1SGuenter Roeck 				ctrl |= 0x80;
15714c7b8ca1SGuenter Roeck 		} else {
15724c7b8ca1SGuenter Roeck 			ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80);
15734c7b8ca1SGuenter Roeck 		}
15744c7b8ca1SGuenter Roeck 		data->pwm_ctrl[nr] = ctrl;
15754c7b8ca1SGuenter Roeck 		it87_write_value(data, IT87_REG_PWM[nr], ctrl);
1576c145d5c6SRudolf Marek 
1577317840cfSFrank Crawford 		if (has_fanctl_onoff(data) && nr < 3) {
15788d5d45fbSJean Delvare 			/* set SmartGuardian mode */
157948b2ae7fSGuenter Roeck 			data->fan_main_ctrl |= BIT(nr);
15805f2dc798SJean Delvare 			it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
15815f2dc798SJean Delvare 					 data->fan_main_ctrl);
15828d5d45fbSJean Delvare 		}
1583c145d5c6SRudolf Marek 	}
15848d5d45fbSJean Delvare 
1585376e1a93SFrank Crawford 	it87_unlock(data);
15868d5d45fbSJean Delvare 	return count;
15878d5d45fbSJean Delvare }
1588c962024eSGuenter Roeck 
set_pwm(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)15898d5d45fbSJean Delvare static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
15908d5d45fbSJean Delvare 		       const char *buf, size_t count)
15918d5d45fbSJean Delvare {
15928d5d45fbSJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1593b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
1594c962024eSGuenter Roeck 	int nr = sensor_attr->index;
1595f5f64501SJean Delvare 	long val;
1596376e1a93SFrank Crawford 	int err;
15978d5d45fbSJean Delvare 
1598179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
15998d5d45fbSJean Delvare 		return -EINVAL;
16008d5d45fbSJean Delvare 
1601376e1a93SFrank Crawford 	err = it87_lock(data);
1602376e1a93SFrank Crawford 	if (err)
1603376e1a93SFrank Crawford 		return err;
1604376e1a93SFrank Crawford 
160582dbe987SGuenter Roeck 	it87_update_pwm_ctrl(data, nr);
160616b5dda2SJean Delvare 	if (has_newer_autopwm(data)) {
16074a0d71cfSGuenter Roeck 		/*
16084a0d71cfSGuenter Roeck 		 * If we are in automatic mode, the PWM duty cycle register
16094a0d71cfSGuenter Roeck 		 * is read-only so we can't write the value.
16104a0d71cfSGuenter Roeck 		 */
16116229cdb2SJean Delvare 		if (data->pwm_ctrl[nr] & 0x80) {
1612376e1a93SFrank Crawford 			count = -EBUSY;
1613376e1a93SFrank Crawford 			goto unlock;
16146229cdb2SJean Delvare 		}
16156229cdb2SJean Delvare 		data->pwm_duty[nr] = pwm_to_reg(data, val);
161636c4d98aSGuenter Roeck 		it87_write_value(data, IT87_REG_PWM_DUTY[nr],
16176229cdb2SJean Delvare 				 data->pwm_duty[nr]);
16186229cdb2SJean Delvare 	} else {
161944c1bcd4SJean Delvare 		data->pwm_duty[nr] = pwm_to_reg(data, val);
16204a0d71cfSGuenter Roeck 		/*
16214a0d71cfSGuenter Roeck 		 * If we are in manual mode, write the duty cycle immediately;
16224a0d71cfSGuenter Roeck 		 * otherwise, just store it for later use.
16234a0d71cfSGuenter Roeck 		 */
1624b99883dcSJean Delvare 		if (!(data->pwm_ctrl[nr] & 0x80)) {
1625b99883dcSJean Delvare 			data->pwm_ctrl[nr] = data->pwm_duty[nr];
162636c4d98aSGuenter Roeck 			it87_write_value(data, IT87_REG_PWM[nr],
16276229cdb2SJean Delvare 					 data->pwm_ctrl[nr]);
16286229cdb2SJean Delvare 		}
1629b99883dcSJean Delvare 	}
1630376e1a93SFrank Crawford unlock:
1631376e1a93SFrank Crawford 	it87_unlock(data);
16328d5d45fbSJean Delvare 	return count;
16338d5d45fbSJean Delvare }
1634c962024eSGuenter Roeck 
set_pwm_freq(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1635c962024eSGuenter Roeck static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
1636c962024eSGuenter Roeck 			    const char *buf, size_t count)
1637f8d0c19aSJean Delvare {
163860878bcfSGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
1639b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
164060878bcfSGuenter Roeck 	int nr = sensor_attr->index;
1641f5f64501SJean Delvare 	unsigned long val;
1642376e1a93SFrank Crawford 	int err;
1643f8d0c19aSJean Delvare 	int i;
1644f8d0c19aSJean Delvare 
1645179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &val) < 0)
1646f5f64501SJean Delvare 		return -EINVAL;
1647f5f64501SJean Delvare 
1648f56c9c0aSGuenter Roeck 	val = clamp_val(val, 0, 1000000);
1649f56c9c0aSGuenter Roeck 	val *= has_newer_autopwm(data) ? 256 : 128;
1650f56c9c0aSGuenter Roeck 
1651f8d0c19aSJean Delvare 	/* Search for the nearest available frequency */
1652f8d0c19aSJean Delvare 	for (i = 0; i < 7; i++) {
1653f8d0c19aSJean Delvare 		if (val > (pwm_freq[i] + pwm_freq[i + 1]) / 2)
1654f8d0c19aSJean Delvare 			break;
1655f8d0c19aSJean Delvare 	}
1656f8d0c19aSJean Delvare 
1657376e1a93SFrank Crawford 	err = it87_lock(data);
1658376e1a93SFrank Crawford 	if (err)
1659376e1a93SFrank Crawford 		return err;
1660376e1a93SFrank Crawford 
166160878bcfSGuenter Roeck 	if (nr == 0) {
1662b74f3fddScorentin.labbe 		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
1663f8d0c19aSJean Delvare 		data->fan_ctl |= i << 4;
1664b74f3fddScorentin.labbe 		it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
166560878bcfSGuenter Roeck 	} else {
166660878bcfSGuenter Roeck 		data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x8f;
166760878bcfSGuenter Roeck 		data->extra |= i << 4;
166860878bcfSGuenter Roeck 		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
166960878bcfSGuenter Roeck 	}
1670376e1a93SFrank Crawford 	it87_unlock(data);
1671f8d0c19aSJean Delvare 
1672f8d0c19aSJean Delvare 	return count;
1673f8d0c19aSJean Delvare }
1674c962024eSGuenter Roeck 
show_pwm_temp_map(struct device * dev,struct device_attribute * attr,char * buf)167594ac7ee6SJean Delvare static ssize_t show_pwm_temp_map(struct device *dev,
167694ac7ee6SJean Delvare 				 struct device_attribute *attr, char *buf)
167794ac7ee6SJean Delvare {
167894ac7ee6SJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
167994ac7ee6SJean Delvare 	struct it87_data *data = it87_update_device(dev);
1680c962024eSGuenter Roeck 	int nr = sensor_attr->index;
168194ac7ee6SJean Delvare 	int map;
168294ac7ee6SJean Delvare 
16830282ba4aSFrank Crawford 	if (IS_ERR(data))
16840282ba4aSFrank Crawford 		return PTR_ERR(data);
16850282ba4aSFrank Crawford 
16860624d861SGuenter Roeck 	map = data->pwm_temp_map[nr];
16870624d861SGuenter Roeck 	if (map >= 3)
168894ac7ee6SJean Delvare 		map = 0;	/* Should never happen */
16890624d861SGuenter Roeck 	if (nr >= 3)		/* pwm channels 3..6 map to temp4..6 */
16900624d861SGuenter Roeck 		map += 3;
16910624d861SGuenter Roeck 
16920624d861SGuenter Roeck 	return sprintf(buf, "%d\n", (int)BIT(map));
169394ac7ee6SJean Delvare }
1694c962024eSGuenter Roeck 
set_pwm_temp_map(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)169594ac7ee6SJean Delvare static ssize_t set_pwm_temp_map(struct device *dev,
1696c962024eSGuenter Roeck 				struct device_attribute *attr, const char *buf,
1697c962024eSGuenter Roeck 				size_t count)
169894ac7ee6SJean Delvare {
169994ac7ee6SJean Delvare 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
170094ac7ee6SJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
1701c962024eSGuenter Roeck 	int nr = sensor_attr->index;
170294ac7ee6SJean Delvare 	long val;
1703376e1a93SFrank Crawford 	int err;
170494ac7ee6SJean Delvare 	u8 reg;
170594ac7ee6SJean Delvare 
1706179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0)
170794ac7ee6SJean Delvare 		return -EINVAL;
170894ac7ee6SJean Delvare 
17090624d861SGuenter Roeck 	if (nr >= 3)
17100624d861SGuenter Roeck 		val -= 3;
17110624d861SGuenter Roeck 
171294ac7ee6SJean Delvare 	switch (val) {
171348b2ae7fSGuenter Roeck 	case BIT(0):
171494ac7ee6SJean Delvare 		reg = 0x00;
171594ac7ee6SJean Delvare 		break;
171648b2ae7fSGuenter Roeck 	case BIT(1):
171794ac7ee6SJean Delvare 		reg = 0x01;
171894ac7ee6SJean Delvare 		break;
171948b2ae7fSGuenter Roeck 	case BIT(2):
172094ac7ee6SJean Delvare 		reg = 0x02;
172194ac7ee6SJean Delvare 		break;
172294ac7ee6SJean Delvare 	default:
172394ac7ee6SJean Delvare 		return -EINVAL;
172494ac7ee6SJean Delvare 	}
172594ac7ee6SJean Delvare 
1726376e1a93SFrank Crawford 	err = it87_lock(data);
1727376e1a93SFrank Crawford 	if (err)
1728376e1a93SFrank Crawford 		return err;
1729376e1a93SFrank Crawford 
173082dbe987SGuenter Roeck 	it87_update_pwm_ctrl(data, nr);
173194ac7ee6SJean Delvare 	data->pwm_temp_map[nr] = reg;
17324a0d71cfSGuenter Roeck 	/*
17334a0d71cfSGuenter Roeck 	 * If we are in automatic mode, write the temp mapping immediately;
17344a0d71cfSGuenter Roeck 	 * otherwise, just store it for later use.
17354a0d71cfSGuenter Roeck 	 */
173694ac7ee6SJean Delvare 	if (data->pwm_ctrl[nr] & 0x80) {
17374c7b8ca1SGuenter Roeck 		data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) |
17384c7b8ca1SGuenter Roeck 						data->pwm_temp_map[nr];
173936c4d98aSGuenter Roeck 		it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
174094ac7ee6SJean Delvare 	}
1741376e1a93SFrank Crawford 	it87_unlock(data);
174294ac7ee6SJean Delvare 	return count;
174394ac7ee6SJean Delvare }
17448d5d45fbSJean Delvare 
show_auto_pwm(struct device * dev,struct device_attribute * attr,char * buf)1745c962024eSGuenter Roeck static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
1746c962024eSGuenter Roeck 			     char *buf)
17474f3f51bcSJean Delvare {
17484f3f51bcSJean Delvare 	struct it87_data *data = it87_update_device(dev);
17494f3f51bcSJean Delvare 	struct sensor_device_attribute_2 *sensor_attr =
17504f3f51bcSJean Delvare 			to_sensor_dev_attr_2(attr);
17514f3f51bcSJean Delvare 	int nr = sensor_attr->nr;
17524f3f51bcSJean Delvare 	int point = sensor_attr->index;
17534f3f51bcSJean Delvare 
17540282ba4aSFrank Crawford 	if (IS_ERR(data))
17550282ba4aSFrank Crawford 		return PTR_ERR(data);
17560282ba4aSFrank Crawford 
175744c1bcd4SJean Delvare 	return sprintf(buf, "%d\n",
175844c1bcd4SJean Delvare 		       pwm_from_reg(data, data->auto_pwm[nr][point]));
17594f3f51bcSJean Delvare }
17604f3f51bcSJean Delvare 
set_auto_pwm(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1761c962024eSGuenter Roeck static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
1762c962024eSGuenter Roeck 			    const char *buf, size_t count)
17634f3f51bcSJean Delvare {
17644f3f51bcSJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
17654f3f51bcSJean Delvare 	struct sensor_device_attribute_2 *sensor_attr =
17664f3f51bcSJean Delvare 			to_sensor_dev_attr_2(attr);
17674f3f51bcSJean Delvare 	int nr = sensor_attr->nr;
17684f3f51bcSJean Delvare 	int point = sensor_attr->index;
17692cbb9c37SGuenter Roeck 	int regaddr;
17704f3f51bcSJean Delvare 	long val;
1771376e1a93SFrank Crawford 	int err;
17724f3f51bcSJean Delvare 
1773179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
17744f3f51bcSJean Delvare 		return -EINVAL;
17754f3f51bcSJean Delvare 
1776376e1a93SFrank Crawford 	err = it87_lock(data);
1777376e1a93SFrank Crawford 	if (err)
1778376e1a93SFrank Crawford 		return err;
1779376e1a93SFrank Crawford 
178044c1bcd4SJean Delvare 	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
17812cbb9c37SGuenter Roeck 	if (has_newer_autopwm(data))
17822cbb9c37SGuenter Roeck 		regaddr = IT87_REG_AUTO_TEMP(nr, 3);
17832cbb9c37SGuenter Roeck 	else
17842cbb9c37SGuenter Roeck 		regaddr = IT87_REG_AUTO_PWM(nr, point);
17852cbb9c37SGuenter Roeck 	it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
1786376e1a93SFrank Crawford 	it87_unlock(data);
17872cbb9c37SGuenter Roeck 	return count;
17882cbb9c37SGuenter Roeck }
17892cbb9c37SGuenter Roeck 
show_auto_pwm_slope(struct device * dev,struct device_attribute * attr,char * buf)17902cbb9c37SGuenter Roeck static ssize_t show_auto_pwm_slope(struct device *dev,
17912cbb9c37SGuenter Roeck 				   struct device_attribute *attr, char *buf)
17922cbb9c37SGuenter Roeck {
17932cbb9c37SGuenter Roeck 	struct it87_data *data = it87_update_device(dev);
17942cbb9c37SGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
17952cbb9c37SGuenter Roeck 	int nr = sensor_attr->index;
17962cbb9c37SGuenter Roeck 
17970282ba4aSFrank Crawford 	if (IS_ERR(data))
17980282ba4aSFrank Crawford 		return PTR_ERR(data);
17990282ba4aSFrank Crawford 
18002cbb9c37SGuenter Roeck 	return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f);
18012cbb9c37SGuenter Roeck }
18022cbb9c37SGuenter Roeck 
set_auto_pwm_slope(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)18032cbb9c37SGuenter Roeck static ssize_t set_auto_pwm_slope(struct device *dev,
18042cbb9c37SGuenter Roeck 				  struct device_attribute *attr,
18052cbb9c37SGuenter Roeck 				  const char *buf, size_t count)
18062cbb9c37SGuenter Roeck {
18072cbb9c37SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
18082cbb9c37SGuenter Roeck 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
18092cbb9c37SGuenter Roeck 	int nr = sensor_attr->index;
18102cbb9c37SGuenter Roeck 	unsigned long val;
1811376e1a93SFrank Crawford 	int err;
18122cbb9c37SGuenter Roeck 
18132cbb9c37SGuenter Roeck 	if (kstrtoul(buf, 10, &val) < 0 || val > 127)
18142cbb9c37SGuenter Roeck 		return -EINVAL;
18152cbb9c37SGuenter Roeck 
1816376e1a93SFrank Crawford 	err = it87_lock(data);
1817376e1a93SFrank Crawford 	if (err)
1818376e1a93SFrank Crawford 		return err;
1819376e1a93SFrank Crawford 
18202cbb9c37SGuenter Roeck 	data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
18212cbb9c37SGuenter Roeck 	it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
18222cbb9c37SGuenter Roeck 			 data->auto_pwm[nr][1]);
1823376e1a93SFrank Crawford 	it87_unlock(data);
18244f3f51bcSJean Delvare 	return count;
18254f3f51bcSJean Delvare }
18264f3f51bcSJean Delvare 
show_auto_temp(struct device * dev,struct device_attribute * attr,char * buf)1827c962024eSGuenter Roeck static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
1828c962024eSGuenter Roeck 			      char *buf)
18294f3f51bcSJean Delvare {
18304f3f51bcSJean Delvare 	struct it87_data *data = it87_update_device(dev);
18314f3f51bcSJean Delvare 	struct sensor_device_attribute_2 *sensor_attr =
18324f3f51bcSJean Delvare 			to_sensor_dev_attr_2(attr);
18334f3f51bcSJean Delvare 	int nr = sensor_attr->nr;
18344f3f51bcSJean Delvare 	int point = sensor_attr->index;
18352cbb9c37SGuenter Roeck 	int reg;
18364f3f51bcSJean Delvare 
18370282ba4aSFrank Crawford 	if (IS_ERR(data))
18380282ba4aSFrank Crawford 		return PTR_ERR(data);
18390282ba4aSFrank Crawford 
18402cbb9c37SGuenter Roeck 	if (has_old_autopwm(data) || point)
18412cbb9c37SGuenter Roeck 		reg = data->auto_temp[nr][point];
18422cbb9c37SGuenter Roeck 	else
18432cbb9c37SGuenter Roeck 		reg = data->auto_temp[nr][1] - (data->auto_temp[nr][0] & 0x1f);
18442cbb9c37SGuenter Roeck 
18452cbb9c37SGuenter Roeck 	return sprintf(buf, "%d\n", TEMP_FROM_REG(reg));
18464f3f51bcSJean Delvare }
18474f3f51bcSJean Delvare 
set_auto_temp(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1848c962024eSGuenter Roeck static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
1849c962024eSGuenter Roeck 			     const char *buf, size_t count)
18504f3f51bcSJean Delvare {
18514f3f51bcSJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
18524f3f51bcSJean Delvare 	struct sensor_device_attribute_2 *sensor_attr =
18534f3f51bcSJean Delvare 			to_sensor_dev_attr_2(attr);
18544f3f51bcSJean Delvare 	int nr = sensor_attr->nr;
18554f3f51bcSJean Delvare 	int point = sensor_attr->index;
18564f3f51bcSJean Delvare 	long val;
18572cbb9c37SGuenter Roeck 	int reg;
1858376e1a93SFrank Crawford 	int err;
18594f3f51bcSJean Delvare 
1860179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
18614f3f51bcSJean Delvare 		return -EINVAL;
18624f3f51bcSJean Delvare 
1863376e1a93SFrank Crawford 	err = it87_lock(data);
1864376e1a93SFrank Crawford 	if (err)
1865376e1a93SFrank Crawford 		return err;
1866376e1a93SFrank Crawford 
18672cbb9c37SGuenter Roeck 	if (has_newer_autopwm(data) && !point) {
18682cbb9c37SGuenter Roeck 		reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
18692cbb9c37SGuenter Roeck 		reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
18702cbb9c37SGuenter Roeck 		data->auto_temp[nr][0] = reg;
18712cbb9c37SGuenter Roeck 		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 5), reg);
18722cbb9c37SGuenter Roeck 	} else {
18732cbb9c37SGuenter Roeck 		reg = TEMP_TO_REG(val);
18742cbb9c37SGuenter Roeck 		data->auto_temp[nr][point] = reg;
18752cbb9c37SGuenter Roeck 		if (has_newer_autopwm(data))
18762cbb9c37SGuenter Roeck 			point--;
18772cbb9c37SGuenter Roeck 		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
18782cbb9c37SGuenter Roeck 	}
1879376e1a93SFrank Crawford 	it87_unlock(data);
18804f3f51bcSJean Delvare 	return count;
18814f3f51bcSJean Delvare }
18824f3f51bcSJean Delvare 
1883e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0);
1884e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1885e1169ba0SGuenter Roeck 			    0, 1);
1886e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div,
1887e1169ba0SGuenter Roeck 			  set_fan_div, 0);
18888d5d45fbSJean Delvare 
1889e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0);
1890e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1891e1169ba0SGuenter Roeck 			    1, 1);
1892e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div,
1893e1169ba0SGuenter Roeck 			  set_fan_div, 1);
1894e1169ba0SGuenter Roeck 
1895e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0);
1896e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1897e1169ba0SGuenter Roeck 			    2, 1);
1898e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div,
1899e1169ba0SGuenter Roeck 			  set_fan_div, 2);
1900e1169ba0SGuenter Roeck 
1901e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0);
1902e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1903e1169ba0SGuenter Roeck 			    3, 1);
1904e1169ba0SGuenter Roeck 
1905e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0);
1906e1169ba0SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1907e1169ba0SGuenter Roeck 			    4, 1);
19088d5d45fbSJean Delvare 
1909fa3f70d6SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan6_input, S_IRUGO, show_fan, NULL, 5, 0);
1910fa3f70d6SGuenter Roeck static SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
1911fa3f70d6SGuenter Roeck 			    5, 1);
1912fa3f70d6SGuenter Roeck 
1913c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
1914c4458db3SGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 0);
1915c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
191660878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq,
191760878bcfSGuenter Roeck 			  set_pwm_freq, 0);
19185c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
1919c4458db3SGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 0);
1920c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
1921c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 0, 0);
1922c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
1923c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 0, 1);
1924c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
1925c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 0, 2);
1926c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO,
1927c4458db3SGuenter Roeck 			    show_auto_pwm, NULL, 0, 3);
1928c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
1929c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 0, 1);
1930c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
1931c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 0, 0);
1932c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
1933c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 0, 2);
1934c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
1935c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 0, 3);
1936c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
1937c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 0, 4);
19382cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm1_auto_start, S_IRUGO | S_IWUSR,
19392cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 0, 0);
19402cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm1_auto_slope, S_IRUGO | S_IWUSR,
19412cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 0);
19428d5d45fbSJean Delvare 
1943c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
1944c4458db3SGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 1);
1945c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
194660878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1);
19475c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO,
1948c4458db3SGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 1);
1949c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
1950c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 1, 0);
1951c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
1952c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 1, 1);
1953c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
1954c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 1, 2);
1955c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO,
1956c4458db3SGuenter Roeck 			    show_auto_pwm, NULL, 1, 3);
1957c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
1958c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 1, 1);
1959c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
1960c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 1, 0);
1961c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
1962c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 1, 2);
1963c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
1964c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 1, 3);
1965c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
1966c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 1, 4);
19672cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm2_auto_start, S_IRUGO | S_IWUSR,
19682cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 1, 0);
19692cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm2_auto_slope, S_IRUGO | S_IWUSR,
19702cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 1);
1971c4458db3SGuenter Roeck 
1972c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
1973c4458db3SGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 2);
1974c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
197560878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2);
19765c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO,
1977c4458db3SGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 2);
1978c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
1979c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 2, 0);
1980c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
1981c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 2, 1);
1982c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
1983c4458db3SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 2, 2);
1984c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO,
1985c4458db3SGuenter Roeck 			    show_auto_pwm, NULL, 2, 3);
1986c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
1987c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 1);
1988c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
1989c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 0);
1990c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
1991c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 2);
1992c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
1993c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 3);
1994c4458db3SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
1995c4458db3SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 4);
19962cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm3_auto_start, S_IRUGO | S_IWUSR,
19972cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 2, 0);
19982cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm3_auto_slope, S_IRUGO | S_IWUSR,
19992cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 2);
20008d5d45fbSJean Delvare 
200136c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
200236c4d98aSGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 3);
200336c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
200460878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
20055c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO,
200636c4d98aSGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 3);
20072cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp, S_IRUGO | S_IWUSR,
20082cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 1);
20092cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
20102cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 0);
20112cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm4_auto_point2_temp, S_IRUGO | S_IWUSR,
20122cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 2);
20132cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm4_auto_point3_temp, S_IRUGO | S_IWUSR,
20142cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 3);
20152cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm4_auto_start, S_IRUGO | S_IWUSR,
20162cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 3, 0);
20172cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm4_auto_slope, S_IRUGO | S_IWUSR,
20182cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 3);
201936c4d98aSGuenter Roeck 
202036c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
202136c4d98aSGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 4);
202236c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
202360878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
20245c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO,
202536c4d98aSGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 4);
20262cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp, S_IRUGO | S_IWUSR,
20272cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 1);
20282cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
20292cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 0);
20302cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm5_auto_point2_temp, S_IRUGO | S_IWUSR,
20312cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 2);
20322cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm5_auto_point3_temp, S_IRUGO | S_IWUSR,
20332cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 3);
20342cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm5_auto_start, S_IRUGO | S_IWUSR,
20352cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 4, 0);
20362cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm5_auto_slope, S_IRUGO | S_IWUSR,
20372cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 4);
203836c4d98aSGuenter Roeck 
203936c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
204036c4d98aSGuenter Roeck 			  show_pwm_enable, set_pwm_enable, 5);
204136c4d98aSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
204260878bcfSGuenter Roeck static SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
20435c391261SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO,
204436c4d98aSGuenter Roeck 			  show_pwm_temp_map, set_pwm_temp_map, 5);
20452cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp, S_IRUGO | S_IWUSR,
20462cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 1);
20472cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
20482cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 0);
20492cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm6_auto_point2_temp, S_IRUGO | S_IWUSR,
20502cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 2);
20512cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm6_auto_point3_temp, S_IRUGO | S_IWUSR,
20522cbb9c37SGuenter Roeck 			    show_auto_temp, set_auto_temp, 2, 3);
20532cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR_2(pwm6_auto_start, S_IRUGO | S_IWUSR,
20542cbb9c37SGuenter Roeck 			    show_auto_pwm, set_auto_pwm, 5, 0);
20552cbb9c37SGuenter Roeck static SENSOR_DEVICE_ATTR(pwm6_auto_slope, S_IRUGO | S_IWUSR,
20562cbb9c37SGuenter Roeck 			  show_auto_pwm_slope, set_auto_pwm_slope, 5);
205736c4d98aSGuenter Roeck 
20588d5d45fbSJean Delvare /* Alarms */
alarms_show(struct device * dev,struct device_attribute * attr,char * buf)2059ddc64ae8SJulia Lawall static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
20605f2dc798SJean Delvare 			   char *buf)
20618d5d45fbSJean Delvare {
20628d5d45fbSJean Delvare 	struct it87_data *data = it87_update_device(dev);
2063c962024eSGuenter Roeck 
20640282ba4aSFrank Crawford 	if (IS_ERR(data))
20650282ba4aSFrank Crawford 		return PTR_ERR(data);
20660282ba4aSFrank Crawford 
20678d5d45fbSJean Delvare 	return sprintf(buf, "%u\n", data->alarms);
20688d5d45fbSJean Delvare }
2069ddc64ae8SJulia Lawall static DEVICE_ATTR_RO(alarms);
20708d5d45fbSJean Delvare 
show_alarm(struct device * dev,struct device_attribute * attr,char * buf)20710124dd78SJean Delvare static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
20720124dd78SJean Delvare 			  char *buf)
20730124dd78SJean Delvare {
20740124dd78SJean Delvare 	struct it87_data *data = it87_update_device(dev);
2075c962024eSGuenter Roeck 	int bitnr = to_sensor_dev_attr(attr)->index;
2076c962024eSGuenter Roeck 
20770282ba4aSFrank Crawford 	if (IS_ERR(data))
20780282ba4aSFrank Crawford 		return PTR_ERR(data);
20790282ba4aSFrank Crawford 
20800124dd78SJean Delvare 	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
20810124dd78SJean Delvare }
20823d30f9e6SJean Delvare 
clear_intrusion(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2083c962024eSGuenter Roeck static ssize_t clear_intrusion(struct device *dev,
2084c962024eSGuenter Roeck 			       struct device_attribute *attr, const char *buf,
2085c962024eSGuenter Roeck 			       size_t count)
20863d30f9e6SJean Delvare {
20873d30f9e6SJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
2088376e1a93SFrank Crawford 	int err, config;
2089c962024eSGuenter Roeck 	long val;
20903d30f9e6SJean Delvare 
2091179c4fdbSFrans Meulenbroeks 	if (kstrtol(buf, 10, &val) < 0 || val != 0)
20923d30f9e6SJean Delvare 		return -EINVAL;
20933d30f9e6SJean Delvare 
2094376e1a93SFrank Crawford 	err = it87_lock(data);
2095376e1a93SFrank Crawford 	if (err)
2096376e1a93SFrank Crawford 		return err;
2097376e1a93SFrank Crawford 
20983d30f9e6SJean Delvare 	config = it87_read_value(data, IT87_REG_CONFIG);
20993d30f9e6SJean Delvare 	if (config < 0) {
21003d30f9e6SJean Delvare 		count = config;
21013d30f9e6SJean Delvare 	} else {
210248b2ae7fSGuenter Roeck 		config |= BIT(5);
21033d30f9e6SJean Delvare 		it87_write_value(data, IT87_REG_CONFIG, config);
21043d30f9e6SJean Delvare 		/* Invalidate cache to force re-read */
2105952a11caSPaul Fertser 		data->valid = false;
21063d30f9e6SJean Delvare 	}
2107376e1a93SFrank Crawford 	it87_unlock(data);
21083d30f9e6SJean Delvare 	return count;
21093d30f9e6SJean Delvare }
21103d30f9e6SJean Delvare 
21110124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
21120124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
21130124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
21140124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
21150124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
21160124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
21170124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
21180124dd78SJean Delvare static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
21190124dd78SJean Delvare static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
21200124dd78SJean Delvare static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1);
21210124dd78SJean Delvare static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2);
21220124dd78SJean Delvare static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3);
21230124dd78SJean Delvare static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6);
2124fa3f70d6SGuenter Roeck static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 7);
21250124dd78SJean Delvare static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
21260124dd78SJean Delvare static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
21270124dd78SJean Delvare static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
21283d30f9e6SJean Delvare static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
21293d30f9e6SJean Delvare 			  show_alarm, clear_intrusion, 4);
21300124dd78SJean Delvare 
show_beep(struct device * dev,struct device_attribute * attr,char * buf)2131d9b327c3SJean Delvare static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
2132d9b327c3SJean Delvare 			 char *buf)
2133d9b327c3SJean Delvare {
2134d9b327c3SJean Delvare 	struct it87_data *data = it87_update_device(dev);
2135c962024eSGuenter Roeck 	int bitnr = to_sensor_dev_attr(attr)->index;
2136c962024eSGuenter Roeck 
21370282ba4aSFrank Crawford 	if (IS_ERR(data))
21380282ba4aSFrank Crawford 		return PTR_ERR(data);
21390282ba4aSFrank Crawford 
2140d9b327c3SJean Delvare 	return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
2141d9b327c3SJean Delvare }
2142c962024eSGuenter Roeck 
set_beep(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2143d9b327c3SJean Delvare static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
2144d9b327c3SJean Delvare 			const char *buf, size_t count)
2145d9b327c3SJean Delvare {
2146d9b327c3SJean Delvare 	int bitnr = to_sensor_dev_attr(attr)->index;
2147d9b327c3SJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
2148d9b327c3SJean Delvare 	long val;
2149376e1a93SFrank Crawford 	int err;
2150d9b327c3SJean Delvare 
2151c962024eSGuenter Roeck 	if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
2152d9b327c3SJean Delvare 		return -EINVAL;
2153d9b327c3SJean Delvare 
2154376e1a93SFrank Crawford 	err = it87_lock(data);
2155376e1a93SFrank Crawford 	if (err)
2156376e1a93SFrank Crawford 		return err;
2157376e1a93SFrank Crawford 
2158d9b327c3SJean Delvare 	data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
2159d9b327c3SJean Delvare 	if (val)
216048b2ae7fSGuenter Roeck 		data->beeps |= BIT(bitnr);
2161d9b327c3SJean Delvare 	else
216248b2ae7fSGuenter Roeck 		data->beeps &= ~BIT(bitnr);
2163d9b327c3SJean Delvare 	it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
2164376e1a93SFrank Crawford 	it87_unlock(data);
2165d9b327c3SJean Delvare 	return count;
2166d9b327c3SJean Delvare }
2167d9b327c3SJean Delvare 
2168d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
2169d9b327c3SJean Delvare 			  show_beep, set_beep, 1);
2170d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO, show_beep, NULL, 1);
2171d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO, show_beep, NULL, 1);
2172d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO, show_beep, NULL, 1);
2173d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO, show_beep, NULL, 1);
2174d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO, show_beep, NULL, 1);
2175d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO, show_beep, NULL, 1);
2176d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO, show_beep, NULL, 1);
2177d9b327c3SJean Delvare /* fanX_beep writability is set later */
2178d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO, show_beep, set_beep, 0);
2179d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO, show_beep, set_beep, 0);
2180d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO, show_beep, set_beep, 0);
2181d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(fan4_beep, S_IRUGO, show_beep, set_beep, 0);
2182d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(fan5_beep, S_IRUGO, show_beep, set_beep, 0);
2183fa3f70d6SGuenter Roeck static SENSOR_DEVICE_ATTR(fan6_beep, S_IRUGO, show_beep, set_beep, 0);
2184d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
2185d9b327c3SJean Delvare 			  show_beep, set_beep, 2);
2186d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
2187d9b327c3SJean Delvare static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);
2188d9b327c3SJean Delvare 
vrm_show(struct device * dev,struct device_attribute * attr,char * buf)2189ddc64ae8SJulia Lawall static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
21905f2dc798SJean Delvare 			char *buf)
21918d5d45fbSJean Delvare {
219290d6619aSJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
2193c962024eSGuenter Roeck 
2194a7be58a1SJean Delvare 	return sprintf(buf, "%u\n", data->vrm);
21958d5d45fbSJean Delvare }
2196c962024eSGuenter Roeck 
vrm_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2197ddc64ae8SJulia Lawall static ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
21985f2dc798SJean Delvare 			 const char *buf, size_t count)
21998d5d45fbSJean Delvare {
2200b74f3fddScorentin.labbe 	struct it87_data *data = dev_get_drvdata(dev);
2201f5f64501SJean Delvare 	unsigned long val;
22028d5d45fbSJean Delvare 
2203179c4fdbSFrans Meulenbroeks 	if (kstrtoul(buf, 10, &val) < 0)
2204f5f64501SJean Delvare 		return -EINVAL;
2205f5f64501SJean Delvare 
22068d5d45fbSJean Delvare 	data->vrm = val;
22078d5d45fbSJean Delvare 
22088d5d45fbSJean Delvare 	return count;
22098d5d45fbSJean Delvare }
2210ddc64ae8SJulia Lawall static DEVICE_ATTR_RW(vrm);
22118d5d45fbSJean Delvare 
cpu0_vid_show(struct device * dev,struct device_attribute * attr,char * buf)2212ddc64ae8SJulia Lawall static ssize_t cpu0_vid_show(struct device *dev,
2213ddc64ae8SJulia Lawall 			     struct device_attribute *attr, char *buf)
22148d5d45fbSJean Delvare {
22158d5d45fbSJean Delvare 	struct it87_data *data = it87_update_device(dev);
2216c962024eSGuenter Roeck 
22170282ba4aSFrank Crawford 	if (IS_ERR(data))
22180282ba4aSFrank Crawford 		return PTR_ERR(data);
22190282ba4aSFrank Crawford 
22208d5d45fbSJean Delvare 	return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm));
22218d5d45fbSJean Delvare }
2222ddc64ae8SJulia Lawall static DEVICE_ATTR_RO(cpu0_vid);
222387808be4SJean Delvare 
show_label(struct device * dev,struct device_attribute * attr,char * buf)2224738e5e05SJean Delvare static ssize_t show_label(struct device *dev, struct device_attribute *attr,
2225738e5e05SJean Delvare 			  char *buf)
2226738e5e05SJean Delvare {
22273c4c4971SGuenter Roeck 	static const char * const labels[] = {
2228738e5e05SJean Delvare 		"+5V",
2229738e5e05SJean Delvare 		"5VSB",
2230738e5e05SJean Delvare 		"Vbat",
2231638c1c07SGuenter Roeck 		"AVCC",
2232738e5e05SJean Delvare 	};
22333c4c4971SGuenter Roeck 	static const char * const labels_it8721[] = {
223444c1bcd4SJean Delvare 		"+3.3V",
223544c1bcd4SJean Delvare 		"3VSB",
223644c1bcd4SJean Delvare 		"Vbat",
2237638c1c07SGuenter Roeck 		"+3.3V",
223844c1bcd4SJean Delvare 	};
223944c1bcd4SJean Delvare 	struct it87_data *data = dev_get_drvdata(dev);
2240738e5e05SJean Delvare 	int nr = to_sensor_dev_attr(attr)->index;
2241ead80803SJustin Maggard 	const char *label;
2242738e5e05SJean Delvare 
2243a9eebd4fSGuenter Roeck 	if (has_vin3_5v(data) && nr == 0)
2244a9eebd4fSGuenter Roeck 		label = labels[0];
2245dedbe4c1SFrank Crawford 	else if (has_scaling(data))
2246ead80803SJustin Maggard 		label = labels_it8721[nr];
2247ead80803SJustin Maggard 	else
2248ead80803SJustin Maggard 		label = labels[nr];
2249ead80803SJustin Maggard 
2250ead80803SJustin Maggard 	return sprintf(buf, "%s\n", label);
2251738e5e05SJean Delvare }
2252738e5e05SJean Delvare static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
2253738e5e05SJean Delvare static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
2254738e5e05SJean Delvare static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
225573055405SGuenter Roeck /* AVCC3 */
2256638c1c07SGuenter Roeck static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3);
2257738e5e05SJean Delvare 
it87_in_is_visible(struct kobject * kobj,struct attribute * attr,int index)225852929715SGuenter Roeck static umode_t it87_in_is_visible(struct kobject *kobj,
225952929715SGuenter Roeck 				  struct attribute *attr, int index)
22609172b5d1SGuenter Roeck {
22619d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
226252929715SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
226352929715SGuenter Roeck 	int i = index / 5;	/* voltage index */
226452929715SGuenter Roeck 	int a = index % 5;	/* attribute index */
226552929715SGuenter Roeck 
2266f838aa26SGuenter Roeck 	if (index >= 40) {	/* in8 and higher only have input attributes */
226752929715SGuenter Roeck 		i = index - 40 + 8;
226852929715SGuenter Roeck 		a = 0;
226952929715SGuenter Roeck 	}
227052929715SGuenter Roeck 
227148b2ae7fSGuenter Roeck 	if (!(data->has_in & BIT(i)))
227252929715SGuenter Roeck 		return 0;
227352929715SGuenter Roeck 
227452929715SGuenter Roeck 	if (a == 4 && !data->has_beep)
227552929715SGuenter Roeck 		return 0;
227652929715SGuenter Roeck 
227752929715SGuenter Roeck 	return attr->mode;
227852929715SGuenter Roeck }
227952929715SGuenter Roeck 
228052929715SGuenter Roeck static struct attribute *it87_attributes_in[] = {
228187808be4SJean Delvare 	&sensor_dev_attr_in0_input.dev_attr.attr,
228287808be4SJean Delvare 	&sensor_dev_attr_in0_min.dev_attr.attr,
228387808be4SJean Delvare 	&sensor_dev_attr_in0_max.dev_attr.attr,
22840124dd78SJean Delvare 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
228552929715SGuenter Roeck 	&sensor_dev_attr_in0_beep.dev_attr.attr,	/* 4 */
228652929715SGuenter Roeck 
22879172b5d1SGuenter Roeck 	&sensor_dev_attr_in1_input.dev_attr.attr,
22889172b5d1SGuenter Roeck 	&sensor_dev_attr_in1_min.dev_attr.attr,
22899172b5d1SGuenter Roeck 	&sensor_dev_attr_in1_max.dev_attr.attr,
22900124dd78SJean Delvare 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
229152929715SGuenter Roeck 	&sensor_dev_attr_in1_beep.dev_attr.attr,	/* 9 */
229252929715SGuenter Roeck 
22939172b5d1SGuenter Roeck 	&sensor_dev_attr_in2_input.dev_attr.attr,
22949172b5d1SGuenter Roeck 	&sensor_dev_attr_in2_min.dev_attr.attr,
22959172b5d1SGuenter Roeck 	&sensor_dev_attr_in2_max.dev_attr.attr,
22960124dd78SJean Delvare 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
229752929715SGuenter Roeck 	&sensor_dev_attr_in2_beep.dev_attr.attr,	/* 14 */
229852929715SGuenter Roeck 
22999172b5d1SGuenter Roeck 	&sensor_dev_attr_in3_input.dev_attr.attr,
23009172b5d1SGuenter Roeck 	&sensor_dev_attr_in3_min.dev_attr.attr,
23019172b5d1SGuenter Roeck 	&sensor_dev_attr_in3_max.dev_attr.attr,
23020124dd78SJean Delvare 	&sensor_dev_attr_in3_alarm.dev_attr.attr,
230352929715SGuenter Roeck 	&sensor_dev_attr_in3_beep.dev_attr.attr,	/* 19 */
230452929715SGuenter Roeck 
23059172b5d1SGuenter Roeck 	&sensor_dev_attr_in4_input.dev_attr.attr,
23069172b5d1SGuenter Roeck 	&sensor_dev_attr_in4_min.dev_attr.attr,
23079172b5d1SGuenter Roeck 	&sensor_dev_attr_in4_max.dev_attr.attr,
23080124dd78SJean Delvare 	&sensor_dev_attr_in4_alarm.dev_attr.attr,
230952929715SGuenter Roeck 	&sensor_dev_attr_in4_beep.dev_attr.attr,	/* 24 */
231052929715SGuenter Roeck 
23119172b5d1SGuenter Roeck 	&sensor_dev_attr_in5_input.dev_attr.attr,
23129172b5d1SGuenter Roeck 	&sensor_dev_attr_in5_min.dev_attr.attr,
23139172b5d1SGuenter Roeck 	&sensor_dev_attr_in5_max.dev_attr.attr,
23140124dd78SJean Delvare 	&sensor_dev_attr_in5_alarm.dev_attr.attr,
231552929715SGuenter Roeck 	&sensor_dev_attr_in5_beep.dev_attr.attr,	/* 29 */
231652929715SGuenter Roeck 
23179172b5d1SGuenter Roeck 	&sensor_dev_attr_in6_input.dev_attr.attr,
23189172b5d1SGuenter Roeck 	&sensor_dev_attr_in6_min.dev_attr.attr,
23199172b5d1SGuenter Roeck 	&sensor_dev_attr_in6_max.dev_attr.attr,
23200124dd78SJean Delvare 	&sensor_dev_attr_in6_alarm.dev_attr.attr,
232152929715SGuenter Roeck 	&sensor_dev_attr_in6_beep.dev_attr.attr,	/* 34 */
232252929715SGuenter Roeck 
23239172b5d1SGuenter Roeck 	&sensor_dev_attr_in7_input.dev_attr.attr,
23249172b5d1SGuenter Roeck 	&sensor_dev_attr_in7_min.dev_attr.attr,
23259172b5d1SGuenter Roeck 	&sensor_dev_attr_in7_max.dev_attr.attr,
23260124dd78SJean Delvare 	&sensor_dev_attr_in7_alarm.dev_attr.attr,
232752929715SGuenter Roeck 	&sensor_dev_attr_in7_beep.dev_attr.attr,	/* 39 */
232887808be4SJean Delvare 
232952929715SGuenter Roeck 	&sensor_dev_attr_in8_input.dev_attr.attr,	/* 40 */
2330d5f3f6c8SJean Delvare 	&sensor_dev_attr_in9_input.dev_attr.attr,
2331d5f3f6c8SJean Delvare 	&sensor_dev_attr_in10_input.dev_attr.attr,
2332d5f3f6c8SJean Delvare 	&sensor_dev_attr_in11_input.dev_attr.attr,
2333d5f3f6c8SJean Delvare 	&sensor_dev_attr_in12_input.dev_attr.attr,
23343c329263SJean Delvare 	NULL
233552929715SGuenter Roeck };
233652929715SGuenter Roeck 
233752929715SGuenter Roeck static const struct attribute_group it87_group_in = {
233852929715SGuenter Roeck 	.attrs = it87_attributes_in,
233952929715SGuenter Roeck 	.is_visible = it87_in_is_visible,
23409172b5d1SGuenter Roeck };
23419172b5d1SGuenter Roeck 
it87_temp_is_visible(struct kobject * kobj,struct attribute * attr,int index)234287533770SGuenter Roeck static umode_t it87_temp_is_visible(struct kobject *kobj,
234387533770SGuenter Roeck 				    struct attribute *attr, int index)
23444573acbcSGuenter Roeck {
23459d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
234687533770SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
234787533770SGuenter Roeck 	int i = index / 7;	/* temperature index */
234887533770SGuenter Roeck 	int a = index % 7;	/* attribute index */
234987533770SGuenter Roeck 
2350cc18da79SGuenter Roeck 	if (index >= 21) {
2351cc18da79SGuenter Roeck 		i = index - 21 + 3;
2352cc18da79SGuenter Roeck 		a = 0;
2353cc18da79SGuenter Roeck 	}
2354cc18da79SGuenter Roeck 
235548b2ae7fSGuenter Roeck 	if (!(data->has_temp & BIT(i)))
235687533770SGuenter Roeck 		return 0;
235787533770SGuenter Roeck 
23582f60e593SFrank Crawford 	if (a == 3) {
23592f60e593SFrank Crawford 		if (get_temp_type(data, i) == 0)
23602f60e593SFrank Crawford 			return 0;
23612f60e593SFrank Crawford 		return attr->mode;
23622f60e593SFrank Crawford 	}
23632f60e593SFrank Crawford 
236487533770SGuenter Roeck 	if (a == 5 && !has_temp_offset(data))
236587533770SGuenter Roeck 		return 0;
236687533770SGuenter Roeck 
236787533770SGuenter Roeck 	if (a == 6 && !data->has_beep)
236887533770SGuenter Roeck 		return 0;
236987533770SGuenter Roeck 
237087533770SGuenter Roeck 	return attr->mode;
237187533770SGuenter Roeck }
237287533770SGuenter Roeck 
237387533770SGuenter Roeck static struct attribute *it87_attributes_temp[] = {
237487808be4SJean Delvare 	&sensor_dev_attr_temp1_input.dev_attr.attr,
237587808be4SJean Delvare 	&sensor_dev_attr_temp1_max.dev_attr.attr,
237687808be4SJean Delvare 	&sensor_dev_attr_temp1_min.dev_attr.attr,
237787808be4SJean Delvare 	&sensor_dev_attr_temp1_type.dev_attr.attr,
23780124dd78SJean Delvare 	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
237987533770SGuenter Roeck 	&sensor_dev_attr_temp1_offset.dev_attr.attr,	/* 5 */
238087533770SGuenter Roeck 	&sensor_dev_attr_temp1_beep.dev_attr.attr,	/* 6 */
238187533770SGuenter Roeck 
2382cc18da79SGuenter Roeck 	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 7 */
23834573acbcSGuenter Roeck 	&sensor_dev_attr_temp2_max.dev_attr.attr,
23844573acbcSGuenter Roeck 	&sensor_dev_attr_temp2_min.dev_attr.attr,
23854573acbcSGuenter Roeck 	&sensor_dev_attr_temp2_type.dev_attr.attr,
23860124dd78SJean Delvare 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
238787533770SGuenter Roeck 	&sensor_dev_attr_temp2_offset.dev_attr.attr,
238887533770SGuenter Roeck 	&sensor_dev_attr_temp2_beep.dev_attr.attr,
238987533770SGuenter Roeck 
2390cc18da79SGuenter Roeck 	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 14 */
23914573acbcSGuenter Roeck 	&sensor_dev_attr_temp3_max.dev_attr.attr,
23924573acbcSGuenter Roeck 	&sensor_dev_attr_temp3_min.dev_attr.attr,
23934573acbcSGuenter Roeck 	&sensor_dev_attr_temp3_type.dev_attr.attr,
23940124dd78SJean Delvare 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
239587533770SGuenter Roeck 	&sensor_dev_attr_temp3_offset.dev_attr.attr,
239687533770SGuenter Roeck 	&sensor_dev_attr_temp3_beep.dev_attr.attr,
239787808be4SJean Delvare 
2398cc18da79SGuenter Roeck 	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 21 */
2399cc18da79SGuenter Roeck 	&sensor_dev_attr_temp5_input.dev_attr.attr,
2400cc18da79SGuenter Roeck 	&sensor_dev_attr_temp6_input.dev_attr.attr,
240187533770SGuenter Roeck 	NULL
24024573acbcSGuenter Roeck };
24034573acbcSGuenter Roeck 
240487533770SGuenter Roeck static const struct attribute_group it87_group_temp = {
240587533770SGuenter Roeck 	.attrs = it87_attributes_temp,
240687533770SGuenter Roeck 	.is_visible = it87_temp_is_visible,
2407161d898aSGuenter Roeck };
2408161d898aSGuenter Roeck 
it87_is_visible(struct kobject * kobj,struct attribute * attr,int index)2409d3766848SGuenter Roeck static umode_t it87_is_visible(struct kobject *kobj,
2410d3766848SGuenter Roeck 			       struct attribute *attr, int index)
2411d3766848SGuenter Roeck {
24129d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
2413d3766848SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
2414d3766848SGuenter Roeck 
24158638d0afSGuenter Roeck 	if ((index == 2 || index == 3) && !data->has_vid)
2416d3766848SGuenter Roeck 		return 0;
2417d3766848SGuenter Roeck 
241848b2ae7fSGuenter Roeck 	if (index > 3 && !(data->in_internal & BIT(index - 4)))
2419d3766848SGuenter Roeck 		return 0;
2420d3766848SGuenter Roeck 
2421d3766848SGuenter Roeck 	return attr->mode;
2422d3766848SGuenter Roeck }
2423d3766848SGuenter Roeck 
24244573acbcSGuenter Roeck static struct attribute *it87_attributes[] = {
242587808be4SJean Delvare 	&dev_attr_alarms.attr,
24263d30f9e6SJean Delvare 	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
24278638d0afSGuenter Roeck 	&dev_attr_vrm.attr,				/* 2 */
24288638d0afSGuenter Roeck 	&dev_attr_cpu0_vid.attr,			/* 3 */
24298638d0afSGuenter Roeck 	&sensor_dev_attr_in3_label.dev_attr.attr,	/* 4 .. 7 */
2430d3766848SGuenter Roeck 	&sensor_dev_attr_in7_label.dev_attr.attr,
2431d3766848SGuenter Roeck 	&sensor_dev_attr_in8_label.dev_attr.attr,
2432d3766848SGuenter Roeck 	&sensor_dev_attr_in9_label.dev_attr.attr,
243387808be4SJean Delvare 	NULL
243487808be4SJean Delvare };
243587808be4SJean Delvare 
243687808be4SJean Delvare static const struct attribute_group it87_group = {
243787808be4SJean Delvare 	.attrs = it87_attributes,
2438d3766848SGuenter Roeck 	.is_visible = it87_is_visible,
243987808be4SJean Delvare };
244087808be4SJean Delvare 
it87_fan_is_visible(struct kobject * kobj,struct attribute * attr,int index)24419a70ee81SGuenter Roeck static umode_t it87_fan_is_visible(struct kobject *kobj,
24429a70ee81SGuenter Roeck 				   struct attribute *attr, int index)
24439a70ee81SGuenter Roeck {
24449d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
24459a70ee81SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
24469a70ee81SGuenter Roeck 	int i = index / 5;	/* fan index */
24479a70ee81SGuenter Roeck 	int a = index % 5;	/* attribute index */
24489a70ee81SGuenter Roeck 
24499a70ee81SGuenter Roeck 	if (index >= 15) {	/* fan 4..6 don't have divisor attributes */
24509a70ee81SGuenter Roeck 		i = (index - 15) / 4 + 3;
24519a70ee81SGuenter Roeck 		a = (index - 15) % 4;
24529a70ee81SGuenter Roeck 	}
24539a70ee81SGuenter Roeck 
245448b2ae7fSGuenter Roeck 	if (!(data->has_fan & BIT(i)))
24559a70ee81SGuenter Roeck 		return 0;
24569a70ee81SGuenter Roeck 
24579a70ee81SGuenter Roeck 	if (a == 3) {				/* beep */
24589a70ee81SGuenter Roeck 		if (!data->has_beep)
24599a70ee81SGuenter Roeck 			return 0;
24609a70ee81SGuenter Roeck 		/* first fan beep attribute is writable */
24619a70ee81SGuenter Roeck 		if (i == __ffs(data->has_fan))
24629a70ee81SGuenter Roeck 			return attr->mode | S_IWUSR;
24639a70ee81SGuenter Roeck 	}
24649a70ee81SGuenter Roeck 
24659a70ee81SGuenter Roeck 	if (a == 4 && has_16bit_fans(data))	/* divisor */
24669a70ee81SGuenter Roeck 		return 0;
24679a70ee81SGuenter Roeck 
24689a70ee81SGuenter Roeck 	return attr->mode;
24699a70ee81SGuenter Roeck }
24709a70ee81SGuenter Roeck 
24719a70ee81SGuenter Roeck static struct attribute *it87_attributes_fan[] = {
247287808be4SJean Delvare 	&sensor_dev_attr_fan1_input.dev_attr.attr,
247387808be4SJean Delvare 	&sensor_dev_attr_fan1_min.dev_attr.attr,
2474723a0aa0SJean Delvare 	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
24759a70ee81SGuenter Roeck 	&sensor_dev_attr_fan1_beep.dev_attr.attr,	/* 3 */
24769a70ee81SGuenter Roeck 	&sensor_dev_attr_fan1_div.dev_attr.attr,	/* 4 */
24779a70ee81SGuenter Roeck 
247887808be4SJean Delvare 	&sensor_dev_attr_fan2_input.dev_attr.attr,
247987808be4SJean Delvare 	&sensor_dev_attr_fan2_min.dev_attr.attr,
2480723a0aa0SJean Delvare 	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
24819a70ee81SGuenter Roeck 	&sensor_dev_attr_fan2_beep.dev_attr.attr,
24829a70ee81SGuenter Roeck 	&sensor_dev_attr_fan2_div.dev_attr.attr,	/* 9 */
24839a70ee81SGuenter Roeck 
248487808be4SJean Delvare 	&sensor_dev_attr_fan3_input.dev_attr.attr,
248587808be4SJean Delvare 	&sensor_dev_attr_fan3_min.dev_attr.attr,
24860124dd78SJean Delvare 	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
24879a70ee81SGuenter Roeck 	&sensor_dev_attr_fan3_beep.dev_attr.attr,
24889a70ee81SGuenter Roeck 	&sensor_dev_attr_fan3_div.dev_attr.attr,	/* 14 */
24899a70ee81SGuenter Roeck 
24909a70ee81SGuenter Roeck 	&sensor_dev_attr_fan4_input.dev_attr.attr,	/* 15 */
2491e1169ba0SGuenter Roeck 	&sensor_dev_attr_fan4_min.dev_attr.attr,
2492e1169ba0SGuenter Roeck 	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
24939a70ee81SGuenter Roeck 	&sensor_dev_attr_fan4_beep.dev_attr.attr,
24949a70ee81SGuenter Roeck 
24959a70ee81SGuenter Roeck 	&sensor_dev_attr_fan5_input.dev_attr.attr,	/* 19 */
2496e1169ba0SGuenter Roeck 	&sensor_dev_attr_fan5_min.dev_attr.attr,
2497e1169ba0SGuenter Roeck 	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
24989a70ee81SGuenter Roeck 	&sensor_dev_attr_fan5_beep.dev_attr.attr,
24999a70ee81SGuenter Roeck 
25009a70ee81SGuenter Roeck 	&sensor_dev_attr_fan6_input.dev_attr.attr,	/* 23 */
2501fa3f70d6SGuenter Roeck 	&sensor_dev_attr_fan6_min.dev_attr.attr,
2502fa3f70d6SGuenter Roeck 	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
25039a70ee81SGuenter Roeck 	&sensor_dev_attr_fan6_beep.dev_attr.attr,
2504fa3f70d6SGuenter Roeck 	NULL
2505723a0aa0SJean Delvare };
2506723a0aa0SJean Delvare 
25079a70ee81SGuenter Roeck static const struct attribute_group it87_group_fan = {
25089a70ee81SGuenter Roeck 	.attrs = it87_attributes_fan,
25099a70ee81SGuenter Roeck 	.is_visible = it87_fan_is_visible,
2510e1169ba0SGuenter Roeck };
2511723a0aa0SJean Delvare 
it87_pwm_is_visible(struct kobject * kobj,struct attribute * attr,int index)25125c391261SGuenter Roeck static umode_t it87_pwm_is_visible(struct kobject *kobj,
25135c391261SGuenter Roeck 				   struct attribute *attr, int index)
251460878bcfSGuenter Roeck {
25159d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
251660878bcfSGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
25175c391261SGuenter Roeck 	int i = index / 4;	/* pwm index */
25185c391261SGuenter Roeck 	int a = index % 4;	/* attribute index */
251960878bcfSGuenter Roeck 
252048b2ae7fSGuenter Roeck 	if (!(data->has_pwm & BIT(i)))
25215c391261SGuenter Roeck 		return 0;
25225c391261SGuenter Roeck 
25232cbb9c37SGuenter Roeck 	/* pwmX_auto_channels_temp is only writable if auto pwm is supported */
25242cbb9c37SGuenter Roeck 	if (a == 3 && (has_old_autopwm(data) || has_newer_autopwm(data)))
25255c391261SGuenter Roeck 		return attr->mode | S_IWUSR;
25265c391261SGuenter Roeck 
25275c391261SGuenter Roeck 	/* pwm2_freq is writable if there are two pwm frequency selects */
25285c391261SGuenter Roeck 	if (has_pwm_freq2(data) && i == 1 && a == 2)
252960878bcfSGuenter Roeck 		return attr->mode | S_IWUSR;
253060878bcfSGuenter Roeck 
253160878bcfSGuenter Roeck 	return attr->mode;
253260878bcfSGuenter Roeck }
253360878bcfSGuenter Roeck 
25345c391261SGuenter Roeck static struct attribute *it87_attributes_pwm[] = {
25355c391261SGuenter Roeck 	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
25365c391261SGuenter Roeck 	&sensor_dev_attr_pwm1.dev_attr.attr,
25375c391261SGuenter Roeck 	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
25385c391261SGuenter Roeck 	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
25395c391261SGuenter Roeck 
25405c391261SGuenter Roeck 	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
25415c391261SGuenter Roeck 	&sensor_dev_attr_pwm2.dev_attr.attr,
25425c391261SGuenter Roeck 	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
25435c391261SGuenter Roeck 	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
25445c391261SGuenter Roeck 
25455c391261SGuenter Roeck 	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
25465c391261SGuenter Roeck 	&sensor_dev_attr_pwm3.dev_attr.attr,
25475c391261SGuenter Roeck 	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
25485c391261SGuenter Roeck 	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
25495c391261SGuenter Roeck 
25505c391261SGuenter Roeck 	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
25515c391261SGuenter Roeck 	&sensor_dev_attr_pwm4.dev_attr.attr,
25525c391261SGuenter Roeck 	&sensor_dev_attr_pwm4_freq.dev_attr.attr,
25535c391261SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
25545c391261SGuenter Roeck 
25555c391261SGuenter Roeck 	&sensor_dev_attr_pwm5_enable.dev_attr.attr,
25565c391261SGuenter Roeck 	&sensor_dev_attr_pwm5.dev_attr.attr,
25575c391261SGuenter Roeck 	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
25585c391261SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
25595c391261SGuenter Roeck 
25605c391261SGuenter Roeck 	&sensor_dev_attr_pwm6_enable.dev_attr.attr,
25615c391261SGuenter Roeck 	&sensor_dev_attr_pwm6.dev_attr.attr,
25625c391261SGuenter Roeck 	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
25635c391261SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
25645c391261SGuenter Roeck 
25655c391261SGuenter Roeck 	NULL
2566723a0aa0SJean Delvare };
2567723a0aa0SJean Delvare 
25685c391261SGuenter Roeck static const struct attribute_group it87_group_pwm = {
25695c391261SGuenter Roeck 	.attrs = it87_attributes_pwm,
25705c391261SGuenter Roeck 	.is_visible = it87_pwm_is_visible,
25715c391261SGuenter Roeck };
25725c391261SGuenter Roeck 
it87_auto_pwm_is_visible(struct kobject * kobj,struct attribute * attr,int index)25735c391261SGuenter Roeck static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
25745c391261SGuenter Roeck 					struct attribute *attr, int index)
25755c391261SGuenter Roeck {
25769d2227bbSGuenter Roeck 	struct device *dev = kobj_to_dev(kobj);
25775c391261SGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
25782cbb9c37SGuenter Roeck 	int i = index / 11;	/* pwm index */
25792cbb9c37SGuenter Roeck 	int a = index % 11;	/* attribute index */
25802cbb9c37SGuenter Roeck 
25812cbb9c37SGuenter Roeck 	if (index >= 33) {	/* pwm 4..6 */
25822cbb9c37SGuenter Roeck 		i = (index - 33) / 6 + 3;
25832cbb9c37SGuenter Roeck 		a = (index - 33) % 6 + 4;
25842cbb9c37SGuenter Roeck 	}
25855c391261SGuenter Roeck 
258648b2ae7fSGuenter Roeck 	if (!(data->has_pwm & BIT(i)))
25875c391261SGuenter Roeck 		return 0;
25885c391261SGuenter Roeck 
25892cbb9c37SGuenter Roeck 	if (has_newer_autopwm(data)) {
25902cbb9c37SGuenter Roeck 		if (a < 4)	/* no auto point pwm */
25912cbb9c37SGuenter Roeck 			return 0;
25922cbb9c37SGuenter Roeck 		if (a == 8)	/* no auto_point4 */
25932cbb9c37SGuenter Roeck 			return 0;
25942cbb9c37SGuenter Roeck 	}
25952cbb9c37SGuenter Roeck 	if (has_old_autopwm(data)) {
25962cbb9c37SGuenter Roeck 		if (a >= 9)	/* no pwm_auto_start, pwm_auto_slope */
25972cbb9c37SGuenter Roeck 			return 0;
25982cbb9c37SGuenter Roeck 	}
25992cbb9c37SGuenter Roeck 
26005c391261SGuenter Roeck 	return attr->mode;
26015c391261SGuenter Roeck }
26025c391261SGuenter Roeck 
26035c391261SGuenter Roeck static struct attribute *it87_attributes_auto_pwm[] = {
26044f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
26054f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
26064f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
26074f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
26084f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
26094f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
26104f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
26114f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
26124f3f51bcSJean Delvare 	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
26132cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm1_auto_start.dev_attr.attr,
26142cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm1_auto_slope.dev_attr.attr,
26155c391261SGuenter Roeck 
26162cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,	/* 11 */
26174f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
26184f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
26194f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
26204f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
26214f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr,
26224f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
26234f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
26244f3f51bcSJean Delvare 	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
26252cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm2_auto_start.dev_attr.attr,
26262cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm2_auto_slope.dev_attr.attr,
26275c391261SGuenter Roeck 
26282cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,	/* 22 */
26294f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
26304f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
26314f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
26324f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
26334f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr,
26344f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
26354f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
26364f3f51bcSJean Delvare 	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
26372cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm3_auto_start.dev_attr.attr,
26382cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm3_auto_slope.dev_attr.attr,
26392cbb9c37SGuenter Roeck 
26402cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,	/* 33 */
26412cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_point1_temp_hyst.dev_attr.attr,
26422cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
26432cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_point3_temp.dev_attr.attr,
26442cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_start.dev_attr.attr,
26452cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm4_auto_slope.dev_attr.attr,
26462cbb9c37SGuenter Roeck 
26472cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_point1_temp.dev_attr.attr,
26482cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_point1_temp_hyst.dev_attr.attr,
26492cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_point2_temp.dev_attr.attr,
26502cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_point3_temp.dev_attr.attr,
26512cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_start.dev_attr.attr,
26522cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm5_auto_slope.dev_attr.attr,
26532cbb9c37SGuenter Roeck 
26542cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_point1_temp.dev_attr.attr,
26552cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_point1_temp_hyst.dev_attr.attr,
26562cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_point2_temp.dev_attr.attr,
26572cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_point3_temp.dev_attr.attr,
26582cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_start.dev_attr.attr,
26592cbb9c37SGuenter Roeck 	&sensor_dev_attr_pwm6_auto_slope.dev_attr.attr,
26604f3f51bcSJean Delvare 
26615c391261SGuenter Roeck 	NULL,
26625c391261SGuenter Roeck };
26635c391261SGuenter Roeck 
26645c391261SGuenter Roeck static const struct attribute_group it87_group_auto_pwm = {
26655c391261SGuenter Roeck 	.attrs = it87_attributes_auto_pwm,
26665c391261SGuenter Roeck 	.is_visible = it87_auto_pwm_is_visible,
26674f3f51bcSJean Delvare };
26684f3f51bcSJean Delvare 
26692d8672c5SJean Delvare /* SuperIO detection - will change isa_address if a chip is found */
it87_find(int sioaddr,unsigned short * address,struct it87_sio_data * sio_data,int chip_cnt)26703c2e3512SGuenter Roeck static int __init it87_find(int sioaddr, unsigned short *address,
26712a64e9d4SFrank Crawford 			    struct it87_sio_data *sio_data, int chip_cnt)
26728d5d45fbSJean Delvare {
26735b0380c9SNat Gurumoorthy 	int err;
2674b74f3fddScorentin.labbe 	u16 chip_type;
26754119693bSFrank Crawford 	const struct it87_devices *config = NULL;
26768d5d45fbSJean Delvare 
26773c2e3512SGuenter Roeck 	err = superio_enter(sioaddr);
26785b0380c9SNat Gurumoorthy 	if (err)
26795b0380c9SNat Gurumoorthy 		return err;
26805b0380c9SNat Gurumoorthy 
26815b0380c9SNat Gurumoorthy 	err = -ENODEV;
2682b3b19931SAhmad Khalifa 	chip_type = superio_inw(sioaddr, DEVID);
2683b3b19931SAhmad Khalifa 	/* check first for a valid chip before forcing chip id */
2684b3b19931SAhmad Khalifa 	if (chip_type == 0xffff)
2685b3b19931SAhmad Khalifa 		goto exit;
2686b3b19931SAhmad Khalifa 
26872a64e9d4SFrank Crawford 	if (force_id_cnt == 1) {
26882a64e9d4SFrank Crawford 		/* If only one value given use for all chips */
26892a64e9d4SFrank Crawford 		if (force_id[0])
26902a64e9d4SFrank Crawford 			chip_type = force_id[0];
26912a64e9d4SFrank Crawford 	} else if (force_id[chip_cnt])
26922a64e9d4SFrank Crawford 		chip_type = force_id[chip_cnt];
2693b74f3fddScorentin.labbe 
2694b74f3fddScorentin.labbe 	switch (chip_type) {
2695b74f3fddScorentin.labbe 	case IT8705F_DEVID:
2696b74f3fddScorentin.labbe 		sio_data->type = it87;
2697b74f3fddScorentin.labbe 		break;
2698b74f3fddScorentin.labbe 	case IT8712F_DEVID:
2699b74f3fddScorentin.labbe 		sio_data->type = it8712;
2700b74f3fddScorentin.labbe 		break;
2701b74f3fddScorentin.labbe 	case IT8716F_DEVID:
2702b74f3fddScorentin.labbe 	case IT8726F_DEVID:
2703b74f3fddScorentin.labbe 		sio_data->type = it8716;
2704b74f3fddScorentin.labbe 		break;
2705b74f3fddScorentin.labbe 	case IT8718F_DEVID:
2706b74f3fddScorentin.labbe 		sio_data->type = it8718;
2707b74f3fddScorentin.labbe 		break;
2708b4da93e4SJean-Marc Spaggiari 	case IT8720F_DEVID:
2709b4da93e4SJean-Marc Spaggiari 		sio_data->type = it8720;
2710b4da93e4SJean-Marc Spaggiari 		break;
271144c1bcd4SJean Delvare 	case IT8721F_DEVID:
271244c1bcd4SJean Delvare 		sio_data->type = it8721;
271344c1bcd4SJean Delvare 		break;
271416b5dda2SJean Delvare 	case IT8728F_DEVID:
271516b5dda2SJean Delvare 		sio_data->type = it8728;
271616b5dda2SJean Delvare 		break;
2717ead80803SJustin Maggard 	case IT8732F_DEVID:
2718ead80803SJustin Maggard 		sio_data->type = it8732;
2719ead80803SJustin Maggard 		break;
2720e531ffc0SGuenter Roeck 	case IT8792E_DEVID:
2721e531ffc0SGuenter Roeck 		sio_data->type = it8792;
2722e531ffc0SGuenter Roeck 		break;
2723b0636707SGuenter Roeck 	case IT8771E_DEVID:
2724b0636707SGuenter Roeck 		sio_data->type = it8771;
2725b0636707SGuenter Roeck 		break;
2726b0636707SGuenter Roeck 	case IT8772E_DEVID:
2727b0636707SGuenter Roeck 		sio_data->type = it8772;
2728b0636707SGuenter Roeck 		break;
27297bc32d29SGuenter Roeck 	case IT8781F_DEVID:
27307bc32d29SGuenter Roeck 		sio_data->type = it8781;
27317bc32d29SGuenter Roeck 		break;
27320531d98bSGuenter Roeck 	case IT8782F_DEVID:
27330531d98bSGuenter Roeck 		sio_data->type = it8782;
27340531d98bSGuenter Roeck 		break;
27350531d98bSGuenter Roeck 	case IT8783E_DEVID:
27360531d98bSGuenter Roeck 		sio_data->type = it8783;
27370531d98bSGuenter Roeck 		break;
2738a0c1424aSThomas Lorblanches 	case IT8786E_DEVID:
2739a0c1424aSThomas Lorblanches 		sio_data->type = it8786;
2740a0c1424aSThomas Lorblanches 		break;
27414ee07157SGuenter Roeck 	case IT8790E_DEVID:
27424ee07157SGuenter Roeck 		sio_data->type = it8790;
27434ee07157SGuenter Roeck 		break;
27447183ae8cSRudolf Marek 	case IT8603E_DEVID:
2745574e9bd8SRudolf Marek 	case IT8623E_DEVID:
2746c145d5c6SRudolf Marek 		sio_data->type = it8603;
2747c145d5c6SRudolf Marek 		break;
27483ba9d977SGuenter Roeck 	case IT8620E_DEVID:
27493ba9d977SGuenter Roeck 		sio_data->type = it8620;
27503ba9d977SGuenter Roeck 		break;
27518af1abaeSGuenter Roeck 	case IT8622E_DEVID:
27528af1abaeSGuenter Roeck 		sio_data->type = it8622;
27538af1abaeSGuenter Roeck 		break;
275471a9c232SGuenter Roeck 	case IT8628E_DEVID:
275571a9c232SGuenter Roeck 		sio_data->type = it8628;
275671a9c232SGuenter Roeck 		break;
2757d44cb4cdSFrank Crawford 	case IT87952E_DEVID:
2758d44cb4cdSFrank Crawford 		sio_data->type = it87952;
2759d44cb4cdSFrank Crawford 		break;
2760b74f3fddScorentin.labbe 	case 0xffff:	/* No device at all */
27618d5d45fbSJean Delvare 		goto exit;
2762b74f3fddScorentin.labbe 	default:
2763a8ca1037SJoe Perches 		pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type);
2764b74f3fddScorentin.labbe 		goto exit;
2765b74f3fddScorentin.labbe 	}
27668d5d45fbSJean Delvare 
27674119693bSFrank Crawford 	config = &it87_devices[sio_data->type];
27684119693bSFrank Crawford 
27693c2e3512SGuenter Roeck 	superio_select(sioaddr, PME);
27703c2e3512SGuenter Roeck 	if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
2771f09c7965SFrank Crawford 		pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
2772f09c7965SFrank Crawford 			config->model, sioaddr);
27738d5d45fbSJean Delvare 		goto exit;
27748d5d45fbSJean Delvare 	}
27758d5d45fbSJean Delvare 
27763c2e3512SGuenter Roeck 	*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
27778d5d45fbSJean Delvare 	if (*address == 0) {
2778f09c7965SFrank Crawford 		pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n",
2779f09c7965SFrank Crawford 			config->model, sioaddr);
27808d5d45fbSJean Delvare 		goto exit;
27818d5d45fbSJean Delvare 	}
27828d5d45fbSJean Delvare 
27838d5d45fbSJean Delvare 	err = 0;
2784384548e5SMaciej S. Szmigiero 	sio_data->sioaddr = sioaddr;
27853c2e3512SGuenter Roeck 	sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
27861f21531dSFrank Crawford 	pr_info("Found %s chip at 0x%x, revision %d\n",
27871f21531dSFrank Crawford 		it87_devices[sio_data->type].model,
2788a0c1424aSThomas Lorblanches 		*address, sio_data->revision);
27898d5d45fbSJean Delvare 
27907f5726c3SGuenter Roeck 	/* in7 (VSB or VCCH5V) is always internal on some chips */
2791f83a9cb6SGuenter Roeck 	if (has_in7_internal(config))
279248b2ae7fSGuenter Roeck 		sio_data->internal |= BIT(1);
27937f5726c3SGuenter Roeck 
2794738e5e05SJean Delvare 	/* in8 (Vbat) is always internal */
279548b2ae7fSGuenter Roeck 	sio_data->internal |= BIT(2);
27967f5726c3SGuenter Roeck 
279773055405SGuenter Roeck 	/* in9 (AVCC3), always internal if supported */
279873055405SGuenter Roeck 	if (has_avcc3(config))
279948b2ae7fSGuenter Roeck 		sio_data->internal |= BIT(3); /* in9 is AVCC */
280073055405SGuenter Roeck 	else
280148b2ae7fSGuenter Roeck 		sio_data->skip_in |= BIT(9);
2802738e5e05SJean Delvare 
280339a6dcf6SFrank Crawford 	if (!has_four_pwm(config))
280448b2ae7fSGuenter Roeck 		sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
280539a6dcf6SFrank Crawford 	else if (!has_five_pwm(config))
280639a6dcf6SFrank Crawford 		sio_data->skip_pwm |= BIT(4) | BIT(5);
2807638c1c07SGuenter Roeck 	else if (!has_six_pwm(config))
2808638c1c07SGuenter Roeck 		sio_data->skip_pwm |= BIT(5);
280936c4d98aSGuenter Roeck 
2810f83a9cb6SGuenter Roeck 	if (!has_vid(config))
2811895ff267SJean Delvare 		sio_data->skip_vid = 1;
2812d9b327c3SJean Delvare 
281332dd7c40SGuenter Roeck 	/* Read GPIO config and VID value from LDN 7 (GPIO) */
281432dd7c40SGuenter Roeck 	if (sio_data->type == it87) {
2815d9b327c3SJean Delvare 		/* The IT8705F has a different LD number for GPIO */
28163c2e3512SGuenter Roeck 		superio_select(sioaddr, 5);
28173c2e3512SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
28183c2e3512SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
28190531d98bSGuenter Roeck 	} else if (sio_data->type == it8783) {
2820088ce2acSGuenter Roeck 		int reg25, reg27, reg2a, reg2c, regef;
28210531d98bSGuenter Roeck 
28223c2e3512SGuenter Roeck 		superio_select(sioaddr, GPIO);
28230531d98bSGuenter Roeck 
28243c2e3512SGuenter Roeck 		reg25 = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
28253c2e3512SGuenter Roeck 		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
28263c2e3512SGuenter Roeck 		reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG);
28273c2e3512SGuenter Roeck 		reg2c = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
28283c2e3512SGuenter Roeck 		regef = superio_inb(sioaddr, IT87_SIO_SPI_REG);
28290531d98bSGuenter Roeck 
28300531d98bSGuenter Roeck 		/* Check if fan3 is there or not */
283148b2ae7fSGuenter Roeck 		if ((reg27 & BIT(0)) || !(reg2c & BIT(2)))
283248b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(2);
2833c962024eSGuenter Roeck 		if ((reg25 & BIT(4)) ||
2834c962024eSGuenter Roeck 		    (!(reg2a & BIT(1)) && (regef & BIT(0))))
283548b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(2);
28360531d98bSGuenter Roeck 
28370531d98bSGuenter Roeck 		/* Check if fan2 is there or not */
283848b2ae7fSGuenter Roeck 		if (reg27 & BIT(7))
283948b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(1);
284048b2ae7fSGuenter Roeck 		if (reg27 & BIT(3))
284148b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(1);
28420531d98bSGuenter Roeck 
28430531d98bSGuenter Roeck 		/* VIN5 */
284448b2ae7fSGuenter Roeck 		if ((reg27 & BIT(0)) || (reg2c & BIT(2)))
284548b2ae7fSGuenter Roeck 			sio_data->skip_in |= BIT(5); /* No VIN5 */
28460531d98bSGuenter Roeck 
28470531d98bSGuenter Roeck 		/* VIN6 */
284848b2ae7fSGuenter Roeck 		if (reg27 & BIT(1))
284948b2ae7fSGuenter Roeck 			sio_data->skip_in |= BIT(6); /* No VIN6 */
28500531d98bSGuenter Roeck 
28510531d98bSGuenter Roeck 		/*
28520531d98bSGuenter Roeck 		 * VIN7
28530531d98bSGuenter Roeck 		 * Does not depend on bit 2 of Reg2C, contrary to datasheet.
28540531d98bSGuenter Roeck 		 */
285548b2ae7fSGuenter Roeck 		if (reg27 & BIT(2)) {
28569172b5d1SGuenter Roeck 			/*
28579172b5d1SGuenter Roeck 			 * The data sheet is a bit unclear regarding the
28589172b5d1SGuenter Roeck 			 * internal voltage divider for VCCH5V. It says
28599172b5d1SGuenter Roeck 			 * "This bit enables and switches VIN7 (pin 91) to the
28609172b5d1SGuenter Roeck 			 * internal voltage divider for VCCH5V".
28619172b5d1SGuenter Roeck 			 * This is different to other chips, where the internal
28629172b5d1SGuenter Roeck 			 * voltage divider would connect VIN7 to an internal
28639172b5d1SGuenter Roeck 			 * voltage source. Maybe that is the case here as well.
28649172b5d1SGuenter Roeck 			 *
28659172b5d1SGuenter Roeck 			 * Since we don't know for sure, re-route it if that is
28669172b5d1SGuenter Roeck 			 * not the case, and ask the user to report if the
28679172b5d1SGuenter Roeck 			 * resulting voltage is sane.
28689172b5d1SGuenter Roeck 			 */
286948b2ae7fSGuenter Roeck 			if (!(reg2c & BIT(1))) {
287048b2ae7fSGuenter Roeck 				reg2c |= BIT(1);
28713c2e3512SGuenter Roeck 				superio_outb(sioaddr, IT87_SIO_PINX2_REG,
28723c2e3512SGuenter Roeck 					     reg2c);
2873384548e5SMaciej S. Szmigiero 				sio_data->need_in7_reroute = true;
28749172b5d1SGuenter Roeck 				pr_notice("Routing internal VCCH5V to in7.\n");
28759172b5d1SGuenter Roeck 			}
28769172b5d1SGuenter Roeck 			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
28779172b5d1SGuenter Roeck 			pr_notice("Please report if it displays a reasonable voltage.\n");
28789172b5d1SGuenter Roeck 		}
28790531d98bSGuenter Roeck 
288048b2ae7fSGuenter Roeck 		if (reg2c & BIT(0))
288148b2ae7fSGuenter Roeck 			sio_data->internal |= BIT(0);
288248b2ae7fSGuenter Roeck 		if (reg2c & BIT(1))
288348b2ae7fSGuenter Roeck 			sio_data->internal |= BIT(1);
28840531d98bSGuenter Roeck 
28853c2e3512SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
28863c2e3512SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
2887c145d5c6SRudolf Marek 	} else if (sio_data->type == it8603) {
2888c145d5c6SRudolf Marek 		int reg27, reg29;
28890531d98bSGuenter Roeck 
28903c2e3512SGuenter Roeck 		superio_select(sioaddr, GPIO);
2891c145d5c6SRudolf Marek 
28923c2e3512SGuenter Roeck 		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
2893c145d5c6SRudolf Marek 
2894c145d5c6SRudolf Marek 		/* Check if fan3 is there or not */
289548b2ae7fSGuenter Roeck 		if (reg27 & BIT(6))
289648b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(2);
289748b2ae7fSGuenter Roeck 		if (reg27 & BIT(7))
289848b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(2);
2899c145d5c6SRudolf Marek 
2900c145d5c6SRudolf Marek 		/* Check if fan2 is there or not */
29013c2e3512SGuenter Roeck 		reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
290248b2ae7fSGuenter Roeck 		if (reg29 & BIT(1))
290348b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(1);
290448b2ae7fSGuenter Roeck 		if (reg29 & BIT(2))
290548b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(1);
2906c145d5c6SRudolf Marek 
290748b2ae7fSGuenter Roeck 		sio_data->skip_in |= BIT(5); /* No VIN5 */
290848b2ae7fSGuenter Roeck 		sio_data->skip_in |= BIT(6); /* No VIN6 */
2909c145d5c6SRudolf Marek 
29103c2e3512SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
29113c2e3512SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
291271a9c232SGuenter Roeck 	} else if (sio_data->type == it8620 || sio_data->type == it8628) {
29133ba9d977SGuenter Roeck 		int reg;
29143ba9d977SGuenter Roeck 
29153c2e3512SGuenter Roeck 		superio_select(sioaddr, GPIO);
29163ba9d977SGuenter Roeck 
291736c4d98aSGuenter Roeck 		/* Check for pwm5 */
29183c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
291948b2ae7fSGuenter Roeck 		if (reg & BIT(6))
292048b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(4);
292136c4d98aSGuenter Roeck 
29223ba9d977SGuenter Roeck 		/* Check for fan4, fan5 */
29233c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
292448b2ae7fSGuenter Roeck 		if (!(reg & BIT(5)))
292548b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(3);
292648b2ae7fSGuenter Roeck 		if (!(reg & BIT(4)))
292748b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(4);
29283ba9d977SGuenter Roeck 
29293ba9d977SGuenter Roeck 		/* Check for pwm3, fan3 */
29303c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
293148b2ae7fSGuenter Roeck 		if (reg & BIT(6))
293248b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(2);
293348b2ae7fSGuenter Roeck 		if (reg & BIT(7))
293448b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(2);
29353ba9d977SGuenter Roeck 
293636c4d98aSGuenter Roeck 		/* Check for pwm4 */
29373c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
2938d66777caSGuenter Roeck 		if (reg & BIT(2))
293948b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(3);
294036c4d98aSGuenter Roeck 
29413ba9d977SGuenter Roeck 		/* Check for pwm2, fan2 */
29423c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
294348b2ae7fSGuenter Roeck 		if (reg & BIT(1))
294448b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(1);
294548b2ae7fSGuenter Roeck 		if (reg & BIT(2))
294648b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(1);
294736c4d98aSGuenter Roeck 		/* Check for pwm6, fan6 */
294848b2ae7fSGuenter Roeck 		if (!(reg & BIT(7))) {
294948b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(5);
295048b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(5);
295136c4d98aSGuenter Roeck 		}
29523ba9d977SGuenter Roeck 
2953638c1c07SGuenter Roeck 		/* Check if AVCC is on VIN3 */
2954638c1c07SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
2955638c1c07SGuenter Roeck 		if (reg & BIT(0))
2956638c1c07SGuenter Roeck 			sio_data->internal |= BIT(0);
2957638c1c07SGuenter Roeck 		else
2958638c1c07SGuenter Roeck 			sio_data->skip_in |= BIT(9);
2959638c1c07SGuenter Roeck 
2960638c1c07SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
2961638c1c07SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
2962638c1c07SGuenter Roeck 	} else if (sio_data->type == it8622) {
2963638c1c07SGuenter Roeck 		int reg;
2964638c1c07SGuenter Roeck 
2965638c1c07SGuenter Roeck 		superio_select(sioaddr, GPIO);
2966638c1c07SGuenter Roeck 
2967638c1c07SGuenter Roeck 		/* Check for pwm4, fan4 */
2968638c1c07SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
2969638c1c07SGuenter Roeck 		if (reg & BIT(6))
2970638c1c07SGuenter Roeck 			sio_data->skip_fan |= BIT(3);
2971638c1c07SGuenter Roeck 		if (reg & BIT(5))
2972638c1c07SGuenter Roeck 			sio_data->skip_pwm |= BIT(3);
2973638c1c07SGuenter Roeck 
2974638c1c07SGuenter Roeck 		/* Check for pwm3, fan3, pwm5, fan5 */
2975638c1c07SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
2976638c1c07SGuenter Roeck 		if (reg & BIT(6))
2977638c1c07SGuenter Roeck 			sio_data->skip_pwm |= BIT(2);
2978638c1c07SGuenter Roeck 		if (reg & BIT(7))
2979638c1c07SGuenter Roeck 			sio_data->skip_fan |= BIT(2);
2980638c1c07SGuenter Roeck 		if (reg & BIT(3))
2981638c1c07SGuenter Roeck 			sio_data->skip_pwm |= BIT(4);
2982638c1c07SGuenter Roeck 		if (reg & BIT(1))
2983638c1c07SGuenter Roeck 			sio_data->skip_fan |= BIT(4);
2984638c1c07SGuenter Roeck 
2985638c1c07SGuenter Roeck 		/* Check for pwm2, fan2 */
2986638c1c07SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
2987638c1c07SGuenter Roeck 		if (reg & BIT(1))
2988638c1c07SGuenter Roeck 			sio_data->skip_pwm |= BIT(1);
2989638c1c07SGuenter Roeck 		if (reg & BIT(2))
2990638c1c07SGuenter Roeck 			sio_data->skip_fan |= BIT(1);
2991638c1c07SGuenter Roeck 
2992638c1c07SGuenter Roeck 		/* Check for AVCC */
2993638c1c07SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
2994638c1c07SGuenter Roeck 		if (!(reg & BIT(0)))
2995638c1c07SGuenter Roeck 			sio_data->skip_in |= BIT(9);
2996638c1c07SGuenter Roeck 
29973c2e3512SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
29983c2e3512SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
2999bd594022SFrank Crawford 	} else if (sio_data->type == it8732) {
3000bd594022SFrank Crawford 		int reg;
3001bd594022SFrank Crawford 
3002bd594022SFrank Crawford 		superio_select(sioaddr, GPIO);
3003bd594022SFrank Crawford 
3004bd594022SFrank Crawford 		/* Check for pwm2, fan2 */
3005bd594022SFrank Crawford 		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
3006bd594022SFrank Crawford 		if (reg & BIT(1))
3007bd594022SFrank Crawford 			sio_data->skip_pwm |= BIT(1);
3008bd594022SFrank Crawford 		if (reg & BIT(2))
3009bd594022SFrank Crawford 			sio_data->skip_fan |= BIT(1);
3010bd594022SFrank Crawford 
3011bd594022SFrank Crawford 		/* Check for pwm3, fan3, fan4 */
3012bd594022SFrank Crawford 		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
3013bd594022SFrank Crawford 		if (reg & BIT(6))
3014bd594022SFrank Crawford 			sio_data->skip_pwm |= BIT(2);
3015bd594022SFrank Crawford 		if (reg & BIT(7))
3016bd594022SFrank Crawford 			sio_data->skip_fan |= BIT(2);
3017bd594022SFrank Crawford 		if (reg & BIT(5))
3018bd594022SFrank Crawford 			sio_data->skip_fan |= BIT(3);
3019bd594022SFrank Crawford 
3020bd594022SFrank Crawford 		/* Check if AVCC is on VIN3 */
3021bd594022SFrank Crawford 		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
3022bd594022SFrank Crawford 		if (reg & BIT(0))
3023bd594022SFrank Crawford 			sio_data->internal |= BIT(0);
3024bd594022SFrank Crawford 
3025bd594022SFrank Crawford 		sio_data->beep_pin = superio_inb(sioaddr,
3026bd594022SFrank Crawford 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
3027895ff267SJean Delvare 	} else {
302887673dd7SJean Delvare 		int reg;
30299172b5d1SGuenter Roeck 		bool uart6;
303087673dd7SJean Delvare 
30313c2e3512SGuenter Roeck 		superio_select(sioaddr, GPIO);
303244c1bcd4SJean Delvare 
3033a0df926dSGuenter Roeck 		/* Check for fan4, fan5 */
3034a0df926dSGuenter Roeck 		if (has_five_fans(config)) {
3035a0df926dSGuenter Roeck 			reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
3036a0df926dSGuenter Roeck 			switch (sio_data->type) {
3037a0df926dSGuenter Roeck 			case it8718:
3038a0df926dSGuenter Roeck 				if (reg & BIT(5))
3039a0df926dSGuenter Roeck 					sio_data->skip_fan |= BIT(3);
3040a0df926dSGuenter Roeck 				if (reg & BIT(4))
3041a0df926dSGuenter Roeck 					sio_data->skip_fan |= BIT(4);
3042a0df926dSGuenter Roeck 				break;
3043a0df926dSGuenter Roeck 			case it8720:
3044a0df926dSGuenter Roeck 			case it8721:
3045a0df926dSGuenter Roeck 			case it8728:
3046a0df926dSGuenter Roeck 				if (!(reg & BIT(5)))
3047a0df926dSGuenter Roeck 					sio_data->skip_fan |= BIT(3);
3048a0df926dSGuenter Roeck 				if (!(reg & BIT(4)))
3049a0df926dSGuenter Roeck 					sio_data->skip_fan |= BIT(4);
3050a0df926dSGuenter Roeck 				break;
3051a0df926dSGuenter Roeck 			default:
3052a0df926dSGuenter Roeck 				break;
3053a0df926dSGuenter Roeck 			}
3054a0df926dSGuenter Roeck 		}
3055a0df926dSGuenter Roeck 
30563c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
305732dd7c40SGuenter Roeck 		if (!sio_data->skip_vid) {
305844c1bcd4SJean Delvare 			/* We need at least 4 VID pins */
3059895ff267SJean Delvare 			if (reg & 0x0f) {
3060a8ca1037SJoe Perches 				pr_info("VID is disabled (pins used for GPIO)\n");
3061895ff267SJean Delvare 				sio_data->skip_vid = 1;
3062895ff267SJean Delvare 			}
306344c1bcd4SJean Delvare 		}
3064895ff267SJean Delvare 
3065591ec650SJean Delvare 		/* Check if fan3 is there or not */
306648b2ae7fSGuenter Roeck 		if (reg & BIT(6))
306748b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(2);
306848b2ae7fSGuenter Roeck 		if (reg & BIT(7))
306948b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(2);
3070591ec650SJean Delvare 
3071591ec650SJean Delvare 		/* Check if fan2 is there or not */
30723c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
307348b2ae7fSGuenter Roeck 		if (reg & BIT(1))
307448b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(1);
307548b2ae7fSGuenter Roeck 		if (reg & BIT(2))
307648b2ae7fSGuenter Roeck 			sio_data->skip_fan |= BIT(1);
3077591ec650SJean Delvare 
3078c962024eSGuenter Roeck 		if ((sio_data->type == it8718 || sio_data->type == it8720) &&
3079c962024eSGuenter Roeck 		    !(sio_data->skip_vid))
30803c2e3512SGuenter Roeck 			sio_data->vid_value = superio_inb(sioaddr,
30813c2e3512SGuenter Roeck 							  IT87_SIO_VID_REG);
308287673dd7SJean Delvare 
30833c2e3512SGuenter Roeck 		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
30849172b5d1SGuenter Roeck 
308548b2ae7fSGuenter Roeck 		uart6 = sio_data->type == it8782 && (reg & BIT(2));
30869172b5d1SGuenter Roeck 
3087436cad2aSJean Delvare 		/*
3088557cbf49SMaciej S. Szmigiero 		 * The IT8720F has no VIN7 pin, so VCCH5V should always be
3089436cad2aSJean Delvare 		 * routed internally to VIN7 with an internal divider.
3090436cad2aSJean Delvare 		 * Curiously, there still is a configuration bit to control
3091436cad2aSJean Delvare 		 * this, which means it can be set incorrectly. And even
3092436cad2aSJean Delvare 		 * more curiously, many boards out there are improperly
3093436cad2aSJean Delvare 		 * configured, even though the IT8720F datasheet claims
3094557cbf49SMaciej S. Szmigiero 		 * that the internal routing of VCCH5V to VIN7 is the default
3095436cad2aSJean Delvare 		 * setting. So we force the internal routing in this case.
30960531d98bSGuenter Roeck 		 *
30970531d98bSGuenter Roeck 		 * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
30989172b5d1SGuenter Roeck 		 * If UART6 is enabled, re-route VIN7 to the internal divider
30999172b5d1SGuenter Roeck 		 * if that is not already the case.
3100436cad2aSJean Delvare 		 */
310148b2ae7fSGuenter Roeck 		if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) {
310248b2ae7fSGuenter Roeck 			reg |= BIT(1);
31033c2e3512SGuenter Roeck 			superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
3104384548e5SMaciej S. Szmigiero 			sio_data->need_in7_reroute = true;
3105557cbf49SMaciej S. Szmigiero 			pr_notice("Routing internal VCCH5V to in7\n");
3106436cad2aSJean Delvare 		}
310748b2ae7fSGuenter Roeck 		if (reg & BIT(0))
310848b2ae7fSGuenter Roeck 			sio_data->internal |= BIT(0);
310948b2ae7fSGuenter Roeck 		if (reg & BIT(1))
311048b2ae7fSGuenter Roeck 			sio_data->internal |= BIT(1);
3111d9b327c3SJean Delvare 
31129172b5d1SGuenter Roeck 		/*
31139172b5d1SGuenter Roeck 		 * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
31149172b5d1SGuenter Roeck 		 * While VIN7 can be routed to the internal voltage divider,
31159172b5d1SGuenter Roeck 		 * VIN5 and VIN6 are not available if UART6 is enabled.
31164573acbcSGuenter Roeck 		 *
31174573acbcSGuenter Roeck 		 * Also, temp3 is not available if UART6 is enabled and TEMPIN3
31184573acbcSGuenter Roeck 		 * is the temperature source. Since we can not read the
31194573acbcSGuenter Roeck 		 * temperature source here, skip_temp is preliminary.
31209172b5d1SGuenter Roeck 		 */
31214573acbcSGuenter Roeck 		if (uart6) {
312248b2ae7fSGuenter Roeck 			sio_data->skip_in |= BIT(5) | BIT(6);
312348b2ae7fSGuenter Roeck 			sio_data->skip_temp |= BIT(2);
31244573acbcSGuenter Roeck 		}
31259172b5d1SGuenter Roeck 
31263c2e3512SGuenter Roeck 		sio_data->beep_pin = superio_inb(sioaddr,
31273c2e3512SGuenter Roeck 						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
312887673dd7SJean Delvare 	}
3129d9b327c3SJean Delvare 	if (sio_data->beep_pin)
3130a8ca1037SJoe Perches 		pr_info("Beeping is supported\n");
313187673dd7SJean Delvare 
3132a1bedbccSFrank Crawford 	/* Set values based on DMI matches */
3133a1bedbccSFrank Crawford 	if (dmi_data)
3134a1bedbccSFrank Crawford 		sio_data->skip_pwm |= dmi_data->skip_pwm;
313598dd22c3SJean Delvare 
31369989b3c0SFrank Crawford 	if (config->smbus_bitmap) {
31379989b3c0SFrank Crawford 		u8 reg;
31389989b3c0SFrank Crawford 
31399989b3c0SFrank Crawford 		superio_select(sioaddr, PME);
31409989b3c0SFrank Crawford 		reg = superio_inb(sioaddr, IT87_SPECIAL_CFG_REG);
31419989b3c0SFrank Crawford 		sio_data->ec_special_config = reg;
31429989b3c0SFrank Crawford 		sio_data->smbus_bitmap = reg & config->smbus_bitmap;
31439989b3c0SFrank Crawford 	}
31449989b3c0SFrank Crawford 
31458d5d45fbSJean Delvare exit:
31464119693bSFrank Crawford 	superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
31478d5d45fbSJean Delvare 	return err;
31488d5d45fbSJean Delvare }
31498d5d45fbSJean Delvare 
3150557cbf49SMaciej S. Szmigiero /*
3151557cbf49SMaciej S. Szmigiero  * Some chips seem to have default value 0xff for all limit
3152557cbf49SMaciej S. Szmigiero  * registers. For low voltage limits it makes no sense and triggers
3153557cbf49SMaciej S. Szmigiero  * alarms, so change to 0 instead. For high temperature limits, it
3154557cbf49SMaciej S. Szmigiero  * means -1 degree C, which surprisingly doesn't trigger an alarm,
3155557cbf49SMaciej S. Szmigiero  * but is still confusing, so change to 127 degrees C.
3156557cbf49SMaciej S. Szmigiero  */
it87_check_limit_regs(struct it87_data * data)3157557cbf49SMaciej S. Szmigiero static void it87_check_limit_regs(struct it87_data *data)
3158557cbf49SMaciej S. Szmigiero {
3159557cbf49SMaciej S. Szmigiero 	int i, reg;
3160557cbf49SMaciej S. Szmigiero 
3161557cbf49SMaciej S. Szmigiero 	for (i = 0; i < NUM_VIN_LIMIT; i++) {
3162557cbf49SMaciej S. Szmigiero 		reg = it87_read_value(data, IT87_REG_VIN_MIN(i));
3163557cbf49SMaciej S. Szmigiero 		if (reg == 0xff)
3164557cbf49SMaciej S. Szmigiero 			it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
3165557cbf49SMaciej S. Szmigiero 	}
3166557cbf49SMaciej S. Szmigiero 	for (i = 0; i < NUM_TEMP_LIMIT; i++) {
3167557cbf49SMaciej S. Szmigiero 		reg = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
3168557cbf49SMaciej S. Szmigiero 		if (reg == 0xff)
3169557cbf49SMaciej S. Szmigiero 			it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
3170557cbf49SMaciej S. Szmigiero 	}
3171557cbf49SMaciej S. Szmigiero }
3172557cbf49SMaciej S. Szmigiero 
3173557cbf49SMaciej S. Szmigiero /* Check if voltage monitors are reset manually or by some reason */
it87_check_voltage_monitors_reset(struct it87_data * data)3174557cbf49SMaciej S. Szmigiero static void it87_check_voltage_monitors_reset(struct it87_data *data)
3175557cbf49SMaciej S. Szmigiero {
3176557cbf49SMaciej S. Szmigiero 	int reg;
3177557cbf49SMaciej S. Szmigiero 
3178557cbf49SMaciej S. Szmigiero 	reg = it87_read_value(data, IT87_REG_VIN_ENABLE);
3179557cbf49SMaciej S. Szmigiero 	if ((reg & 0xff) == 0) {
3180557cbf49SMaciej S. Szmigiero 		/* Enable all voltage monitors */
3181557cbf49SMaciej S. Szmigiero 		it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
3182557cbf49SMaciej S. Szmigiero 	}
3183557cbf49SMaciej S. Szmigiero }
3184557cbf49SMaciej S. Szmigiero 
3185557cbf49SMaciej S. Szmigiero /* Check if tachometers are reset manually or by some reason */
it87_check_tachometers_reset(struct platform_device * pdev)3186557cbf49SMaciej S. Szmigiero static void it87_check_tachometers_reset(struct platform_device *pdev)
3187557cbf49SMaciej S. Szmigiero {
3188557cbf49SMaciej S. Szmigiero 	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
3189557cbf49SMaciej S. Szmigiero 	struct it87_data *data = platform_get_drvdata(pdev);
3190557cbf49SMaciej S. Szmigiero 	u8 mask, fan_main_ctrl;
3191557cbf49SMaciej S. Szmigiero 
3192557cbf49SMaciej S. Szmigiero 	mask = 0x70 & ~(sio_data->skip_fan << 4);
3193557cbf49SMaciej S. Szmigiero 	fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
3194557cbf49SMaciej S. Szmigiero 	if ((fan_main_ctrl & mask) == 0) {
3195557cbf49SMaciej S. Szmigiero 		/* Enable all fan tachometers */
3196557cbf49SMaciej S. Szmigiero 		fan_main_ctrl |= mask;
3197557cbf49SMaciej S. Szmigiero 		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
3198557cbf49SMaciej S. Szmigiero 				 fan_main_ctrl);
3199557cbf49SMaciej S. Szmigiero 	}
3200557cbf49SMaciej S. Szmigiero }
3201557cbf49SMaciej S. Szmigiero 
3202557cbf49SMaciej S. Szmigiero /* Set tachometers to 16-bit mode if needed */
it87_check_tachometers_16bit_mode(struct platform_device * pdev)3203557cbf49SMaciej S. Szmigiero static void it87_check_tachometers_16bit_mode(struct platform_device *pdev)
3204557cbf49SMaciej S. Szmigiero {
3205557cbf49SMaciej S. Szmigiero 	struct it87_data *data = platform_get_drvdata(pdev);
3206557cbf49SMaciej S. Szmigiero 	int reg;
3207557cbf49SMaciej S. Szmigiero 
3208557cbf49SMaciej S. Szmigiero 	if (!has_fan16_config(data))
3209557cbf49SMaciej S. Szmigiero 		return;
3210557cbf49SMaciej S. Szmigiero 
3211557cbf49SMaciej S. Szmigiero 	reg = it87_read_value(data, IT87_REG_FAN_16BIT);
3212557cbf49SMaciej S. Szmigiero 	if (~reg & 0x07 & data->has_fan) {
3213557cbf49SMaciej S. Szmigiero 		dev_dbg(&pdev->dev,
3214557cbf49SMaciej S. Szmigiero 			"Setting fan1-3 to 16-bit mode\n");
3215557cbf49SMaciej S. Szmigiero 		it87_write_value(data, IT87_REG_FAN_16BIT,
3216557cbf49SMaciej S. Szmigiero 				 reg | 0x07);
3217557cbf49SMaciej S. Szmigiero 	}
3218557cbf49SMaciej S. Szmigiero }
3219557cbf49SMaciej S. Szmigiero 
it87_start_monitoring(struct it87_data * data)3220557cbf49SMaciej S. Szmigiero static void it87_start_monitoring(struct it87_data *data)
3221557cbf49SMaciej S. Szmigiero {
3222557cbf49SMaciej S. Szmigiero 	it87_write_value(data, IT87_REG_CONFIG,
3223557cbf49SMaciej S. Szmigiero 			 (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
3224557cbf49SMaciej S. Szmigiero 			 | (update_vbat ? 0x41 : 0x01));
3225557cbf49SMaciej S. Szmigiero }
3226557cbf49SMaciej S. Szmigiero 
3227c1e7a4caSGuenter Roeck /* Called when we have found a new IT87. */
it87_init_device(struct platform_device * pdev)3228c1e7a4caSGuenter Roeck static void it87_init_device(struct platform_device *pdev)
3229c1e7a4caSGuenter Roeck {
3230c1e7a4caSGuenter Roeck 	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
3231c1e7a4caSGuenter Roeck 	struct it87_data *data = platform_get_drvdata(pdev);
3232c1e7a4caSGuenter Roeck 	int tmp, i;
3233c1e7a4caSGuenter Roeck 
3234c1e7a4caSGuenter Roeck 	/*
3235c1e7a4caSGuenter Roeck 	 * For each PWM channel:
3236c1e7a4caSGuenter Roeck 	 * - If it is in automatic mode, setting to manual mode should set
3237c1e7a4caSGuenter Roeck 	 *   the fan to full speed by default.
3238c1e7a4caSGuenter Roeck 	 * - If it is in manual mode, we need a mapping to temperature
3239c1e7a4caSGuenter Roeck 	 *   channels to use when later setting to automatic mode later.
3240c1e7a4caSGuenter Roeck 	 *   Use a 1:1 mapping by default (we are clueless.)
3241c1e7a4caSGuenter Roeck 	 * In both cases, the value can (and should) be changed by the user
3242c1e7a4caSGuenter Roeck 	 * prior to switching to a different mode.
3243c1e7a4caSGuenter Roeck 	 * Note that this is no longer needed for the IT8721F and later, as
3244c1e7a4caSGuenter Roeck 	 * these have separate registers for the temperature mapping and the
3245c1e7a4caSGuenter Roeck 	 * manual duty cycle.
3246c1e7a4caSGuenter Roeck 	 */
32472310048dSGuenter Roeck 	for (i = 0; i < NUM_AUTO_PWM; i++) {
3248c1e7a4caSGuenter Roeck 		data->pwm_temp_map[i] = i;
3249c1e7a4caSGuenter Roeck 		data->pwm_duty[i] = 0x7f;	/* Full speed */
3250c1e7a4caSGuenter Roeck 		data->auto_pwm[i][3] = 0x7f;	/* Full speed, hard-coded */
3251c1e7a4caSGuenter Roeck 	}
3252c1e7a4caSGuenter Roeck 
3253557cbf49SMaciej S. Szmigiero 	it87_check_limit_regs(data);
3254c1e7a4caSGuenter Roeck 
3255c1e7a4caSGuenter Roeck 	/*
3256c1e7a4caSGuenter Roeck 	 * Temperature channels are not forcibly enabled, as they can be
3257c1e7a4caSGuenter Roeck 	 * set to two different sensor types and we can't guess which one
3258c1e7a4caSGuenter Roeck 	 * is correct for a given system. These channels can be enabled at
3259c1e7a4caSGuenter Roeck 	 * run-time through the temp{1-3}_type sysfs accessors if needed.
3260c1e7a4caSGuenter Roeck 	 */
3261c1e7a4caSGuenter Roeck 
3262557cbf49SMaciej S. Szmigiero 	it87_check_voltage_monitors_reset(data);
3263c1e7a4caSGuenter Roeck 
3264557cbf49SMaciej S. Szmigiero 	it87_check_tachometers_reset(pdev);
3265557cbf49SMaciej S. Szmigiero 
3266c1e7a4caSGuenter Roeck 	data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
3267c1e7a4caSGuenter Roeck 	data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
3268c1e7a4caSGuenter Roeck 
3269557cbf49SMaciej S. Szmigiero 	it87_check_tachometers_16bit_mode(pdev);
3270c1e7a4caSGuenter Roeck 
3271c1e7a4caSGuenter Roeck 	/* Check for additional fans */
3272557cbf49SMaciej S. Szmigiero 	tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
3273557cbf49SMaciej S. Szmigiero 
32745a4417bcSFrank Crawford 	if (has_four_fans(data) && (tmp & BIT(4)))
327548b2ae7fSGuenter Roeck 		data->has_fan |= BIT(3); /* fan4 enabled */
32765a4417bcSFrank Crawford 	if (has_five_fans(data) && (tmp & BIT(5)))
327748b2ae7fSGuenter Roeck 		data->has_fan |= BIT(4); /* fan5 enabled */
327848b2ae7fSGuenter Roeck 	if (has_six_fans(data) && (tmp & BIT(2)))
327948b2ae7fSGuenter Roeck 		data->has_fan |= BIT(5); /* fan6 enabled */
3280c1e7a4caSGuenter Roeck 
3281c1e7a4caSGuenter Roeck 	/* Fan input pins may be used for alternative functions */
3282c1e7a4caSGuenter Roeck 	data->has_fan &= ~sio_data->skip_fan;
3283c1e7a4caSGuenter Roeck 
3284c1e7a4caSGuenter Roeck 	/* Check if pwm5, pwm6 are enabled */
3285c1e7a4caSGuenter Roeck 	if (has_six_pwm(data)) {
3286c1e7a4caSGuenter Roeck 		/* The following code may be IT8620E specific */
3287c1e7a4caSGuenter Roeck 		tmp = it87_read_value(data, IT87_REG_FAN_DIV);
3288c1e7a4caSGuenter Roeck 		if ((tmp & 0xc0) == 0xc0)
328948b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(4);
329048b2ae7fSGuenter Roeck 		if (!(tmp & BIT(3)))
329148b2ae7fSGuenter Roeck 			sio_data->skip_pwm |= BIT(5);
3292c1e7a4caSGuenter Roeck 	}
3293c1e7a4caSGuenter Roeck 
3294557cbf49SMaciej S. Szmigiero 	it87_start_monitoring(data);
3295c1e7a4caSGuenter Roeck }
3296c1e7a4caSGuenter Roeck 
3297c1e7a4caSGuenter Roeck /* Return 1 if and only if the PWM interface is safe to use */
it87_check_pwm(struct device * dev)3298c1e7a4caSGuenter Roeck static int it87_check_pwm(struct device *dev)
3299c1e7a4caSGuenter Roeck {
3300c1e7a4caSGuenter Roeck 	struct it87_data *data = dev_get_drvdata(dev);
3301c1e7a4caSGuenter Roeck 	/*
3302c1e7a4caSGuenter Roeck 	 * Some BIOSes fail to correctly configure the IT87 fans. All fans off
3303c1e7a4caSGuenter Roeck 	 * and polarity set to active low is sign that this is the case so we
3304c1e7a4caSGuenter Roeck 	 * disable pwm control to protect the user.
3305c1e7a4caSGuenter Roeck 	 */
3306c1e7a4caSGuenter Roeck 	int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
3307c1e7a4caSGuenter Roeck 
3308c1e7a4caSGuenter Roeck 	if ((tmp & 0x87) == 0) {
3309c1e7a4caSGuenter Roeck 		if (fix_pwm_polarity) {
3310c1e7a4caSGuenter Roeck 			/*
3311c1e7a4caSGuenter Roeck 			 * The user asks us to attempt a chip reconfiguration.
3312c1e7a4caSGuenter Roeck 			 * This means switching to active high polarity and
3313c1e7a4caSGuenter Roeck 			 * inverting all fan speed values.
3314c1e7a4caSGuenter Roeck 			 */
3315c1e7a4caSGuenter Roeck 			int i;
3316c1e7a4caSGuenter Roeck 			u8 pwm[3];
3317c1e7a4caSGuenter Roeck 
33182310048dSGuenter Roeck 			for (i = 0; i < ARRAY_SIZE(pwm); i++)
3319c1e7a4caSGuenter Roeck 				pwm[i] = it87_read_value(data,
3320c1e7a4caSGuenter Roeck 							 IT87_REG_PWM[i]);
3321c1e7a4caSGuenter Roeck 
3322c1e7a4caSGuenter Roeck 			/*
3323c1e7a4caSGuenter Roeck 			 * If any fan is in automatic pwm mode, the polarity
3324c1e7a4caSGuenter Roeck 			 * might be correct, as suspicious as it seems, so we
3325c1e7a4caSGuenter Roeck 			 * better don't change anything (but still disable the
3326c1e7a4caSGuenter Roeck 			 * PWM interface).
3327c1e7a4caSGuenter Roeck 			 */
3328c1e7a4caSGuenter Roeck 			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
3329c1e7a4caSGuenter Roeck 				dev_info(dev,
3330c1e7a4caSGuenter Roeck 					 "Reconfiguring PWM to active high polarity\n");
3331c1e7a4caSGuenter Roeck 				it87_write_value(data, IT87_REG_FAN_CTL,
3332c1e7a4caSGuenter Roeck 						 tmp | 0x87);
3333c1e7a4caSGuenter Roeck 				for (i = 0; i < 3; i++)
3334c1e7a4caSGuenter Roeck 					it87_write_value(data,
3335c1e7a4caSGuenter Roeck 							 IT87_REG_PWM[i],
3336c1e7a4caSGuenter Roeck 							 0x7f & ~pwm[i]);
3337c1e7a4caSGuenter Roeck 				return 1;
3338c1e7a4caSGuenter Roeck 			}
3339c1e7a4caSGuenter Roeck 
3340c1e7a4caSGuenter Roeck 			dev_info(dev,
3341c1e7a4caSGuenter Roeck 				 "PWM configuration is too broken to be fixed\n");
3342c1e7a4caSGuenter Roeck 		}
3343c1e7a4caSGuenter Roeck 
3344c1e7a4caSGuenter Roeck 		return 0;
3345c1e7a4caSGuenter Roeck 	} else if (fix_pwm_polarity) {
3346c1e7a4caSGuenter Roeck 		dev_info(dev,
3347c1e7a4caSGuenter Roeck 			 "PWM configuration looks sane, won't touch\n");
3348c1e7a4caSGuenter Roeck 	}
3349c1e7a4caSGuenter Roeck 
3350c1e7a4caSGuenter Roeck 	return 1;
3351c1e7a4caSGuenter Roeck }
3352c1e7a4caSGuenter Roeck 
it87_probe(struct platform_device * pdev)33536c931ae1SBill Pemberton static int it87_probe(struct platform_device *pdev)
33548d5d45fbSJean Delvare {
33558d5d45fbSJean Delvare 	struct it87_data *data;
3356b74f3fddScorentin.labbe 	struct resource *res;
3357b74f3fddScorentin.labbe 	struct device *dev = &pdev->dev;
3358a8b3a3a5SJingoo Han 	struct it87_sio_data *sio_data = dev_get_platdata(dev);
33598d5d45fbSJean Delvare 	int enable_pwm_interface;
33608638d0afSGuenter Roeck 	struct device *hwmon_dev;
3361376e1a93SFrank Crawford 	int err;
33628d5d45fbSJean Delvare 
3363b74f3fddScorentin.labbe 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
336462a1d05fSGuenter Roeck 	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
336562a1d05fSGuenter Roeck 				 DRVNAME)) {
3366b74f3fddScorentin.labbe 		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
3367b74f3fddScorentin.labbe 			(unsigned long)res->start,
336887b4b663SBjorn Helgaas 			(unsigned long)(res->start + IT87_EC_EXTENT - 1));
336962a1d05fSGuenter Roeck 		return -EBUSY;
33708e9afcbbSJean Delvare 	}
33718d5d45fbSJean Delvare 
337262a1d05fSGuenter Roeck 	data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
337362a1d05fSGuenter Roeck 	if (!data)
337462a1d05fSGuenter Roeck 		return -ENOMEM;
33758d5d45fbSJean Delvare 
3376b74f3fddScorentin.labbe 	data->addr = res->start;
3377384548e5SMaciej S. Szmigiero 	data->sioaddr = sio_data->sioaddr;
3378b74f3fddScorentin.labbe 	data->type = sio_data->type;
33799989b3c0SFrank Crawford 	data->smbus_bitmap = sio_data->smbus_bitmap;
33809989b3c0SFrank Crawford 	data->ec_special_config = sio_data->ec_special_config;
3381483db43eSGuenter Roeck 	data->features = it87_devices[sio_data->type].features;
33825d8d2f2bSGuenter Roeck 	data->peci_mask = it87_devices[sio_data->type].peci_mask;
338319529784SGuenter Roeck 	data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
3384483db43eSGuenter Roeck 	/*
3385483db43eSGuenter Roeck 	 * IT8705F Datasheet 0.4.1, 3h == Version G.
3386483db43eSGuenter Roeck 	 * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
3387483db43eSGuenter Roeck 	 * These are the first revisions with 16-bit tachometer support.
3388483db43eSGuenter Roeck 	 */
3389483db43eSGuenter Roeck 	switch (data->type) {
3390483db43eSGuenter Roeck 	case it87:
3391483db43eSGuenter Roeck 		if (sio_data->revision >= 0x03) {
3392483db43eSGuenter Roeck 			data->features &= ~FEAT_OLD_AUTOPWM;
33939faf28caSGuenter Roeck 			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
3394483db43eSGuenter Roeck 		}
3395483db43eSGuenter Roeck 		break;
3396483db43eSGuenter Roeck 	case it8712:
3397483db43eSGuenter Roeck 		if (sio_data->revision >= 0x08) {
3398483db43eSGuenter Roeck 			data->features &= ~FEAT_OLD_AUTOPWM;
33999faf28caSGuenter Roeck 			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
34009faf28caSGuenter Roeck 					  FEAT_FIVE_FANS;
3401483db43eSGuenter Roeck 		}
3402483db43eSGuenter Roeck 		break;
3403483db43eSGuenter Roeck 	default:
3404483db43eSGuenter Roeck 		break;
3405483db43eSGuenter Roeck 	}
34068d5d45fbSJean Delvare 
3407b74f3fddScorentin.labbe 	platform_set_drvdata(pdev, data);
34088d5d45fbSJean Delvare 
34099a61bf63SIngo Molnar 	mutex_init(&data->update_lock);
34108d5d45fbSJean Delvare 
3411376e1a93SFrank Crawford 	err = smbus_disable(data);
3412376e1a93SFrank Crawford 	if (err)
3413376e1a93SFrank Crawford 		return err;
3414376e1a93SFrank Crawford 
3415376e1a93SFrank Crawford 	/* Now, we do the remaining detection. */
3416376e1a93SFrank Crawford 	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
3417376e1a93SFrank Crawford 	    it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
3418376e1a93SFrank Crawford 		smbus_enable(data);
3419376e1a93SFrank Crawford 		return -ENODEV;
3420376e1a93SFrank Crawford 	}
3421376e1a93SFrank Crawford 
34228d5d45fbSJean Delvare 	/* Check PWM configuration */
3423b74f3fddScorentin.labbe 	enable_pwm_interface = it87_check_pwm(dev);
3424384548e5SMaciej S. Szmigiero 	if (!enable_pwm_interface)
3425384548e5SMaciej S. Szmigiero 		dev_info(dev,
3426384548e5SMaciej S. Szmigiero 			 "Detected broken BIOS defaults, disabling PWM interface\n");
34278d5d45fbSJean Delvare 
342844c1bcd4SJean Delvare 	/* Starting with IT8721F, we handle scaling of internal voltages */
3429968b66ffSFrank Crawford 	if (has_scaling(data)) {
343048b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(0))
343148b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(3);	/* in3 is AVCC */
343248b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(1))
343348b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(7);	/* in7 is VSB */
343448b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(2))
343548b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(8);	/* in8 is Vbat */
343648b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(3))
343748b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(9);	/* in9 is AVCC */
34387bc32d29SGuenter Roeck 	} else if (sio_data->type == it8781 || sio_data->type == it8782 ||
34397bc32d29SGuenter Roeck 		   sio_data->type == it8783) {
344048b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(0))
344148b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(3);	/* in3 is VCC5V */
344248b2ae7fSGuenter Roeck 		if (sio_data->internal & BIT(1))
344348b2ae7fSGuenter Roeck 			data->in_scaled |= BIT(7);	/* in7 is VCCH5V */
344444c1bcd4SJean Delvare 	}
344544c1bcd4SJean Delvare 
34464573acbcSGuenter Roeck 	data->has_temp = 0x07;
344748b2ae7fSGuenter Roeck 	if (sio_data->skip_temp & BIT(2)) {
3448c962024eSGuenter Roeck 		if (sio_data->type == it8782 &&
3449c962024eSGuenter Roeck 		    !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
345048b2ae7fSGuenter Roeck 			data->has_temp &= ~BIT(2);
34514573acbcSGuenter Roeck 	}
34524573acbcSGuenter Roeck 
3453d3766848SGuenter Roeck 	data->in_internal = sio_data->internal;
3454384548e5SMaciej S. Szmigiero 	data->need_in7_reroute = sio_data->need_in7_reroute;
345552929715SGuenter Roeck 	data->has_in = 0x3ff & ~sio_data->skip_in;
345652929715SGuenter Roeck 
3457339c8f24SFrank Crawford 	if (has_four_temp(data)) {
3458339c8f24SFrank Crawford 		data->has_temp |= BIT(3);
3459339c8f24SFrank Crawford 	} else if (has_six_temp(data)) {
3460cc18da79SGuenter Roeck 		u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
3461cc18da79SGuenter Roeck 
3462f838aa26SGuenter Roeck 		/* Check for additional temperature sensors */
3463cc18da79SGuenter Roeck 		if ((reg & 0x03) >= 0x02)
346448b2ae7fSGuenter Roeck 			data->has_temp |= BIT(3);
3465cc18da79SGuenter Roeck 		if (((reg >> 2) & 0x03) >= 0x02)
346648b2ae7fSGuenter Roeck 			data->has_temp |= BIT(4);
3467cc18da79SGuenter Roeck 		if (((reg >> 4) & 0x03) >= 0x02)
346848b2ae7fSGuenter Roeck 			data->has_temp |= BIT(5);
3469f838aa26SGuenter Roeck 
3470f838aa26SGuenter Roeck 		/* Check for additional voltage sensors */
3471f838aa26SGuenter Roeck 		if ((reg & 0x03) == 0x01)
347248b2ae7fSGuenter Roeck 			data->has_in |= BIT(10);
3473f838aa26SGuenter Roeck 		if (((reg >> 2) & 0x03) == 0x01)
347448b2ae7fSGuenter Roeck 			data->has_in |= BIT(11);
3475f838aa26SGuenter Roeck 		if (((reg >> 4) & 0x03) == 0x01)
347648b2ae7fSGuenter Roeck 			data->has_in |= BIT(12);
3477cc18da79SGuenter Roeck 	}
3478cc18da79SGuenter Roeck 
347952929715SGuenter Roeck 	data->has_beep = !!sio_data->beep_pin;
348052929715SGuenter Roeck 
34818d5d45fbSJean Delvare 	/* Initialize the IT87 chip */
3482b74f3fddScorentin.labbe 	it87_init_device(pdev);
34838d5d45fbSJean Delvare 
3484376e1a93SFrank Crawford 	smbus_enable(data);
3485376e1a93SFrank Crawford 
3486d3766848SGuenter Roeck 	if (!sio_data->skip_vid) {
3487d3766848SGuenter Roeck 		data->has_vid = true;
3488d3766848SGuenter Roeck 		data->vrm = vid_which_vrm();
3489d3766848SGuenter Roeck 		/* VID reading from Super-I/O config space if available */
3490d3766848SGuenter Roeck 		data->vid = sio_data->vid_value;
3491d3766848SGuenter Roeck 	}
3492d3766848SGuenter Roeck 
34938638d0afSGuenter Roeck 	/* Prepare for sysfs hooks */
34948638d0afSGuenter Roeck 	data->groups[0] = &it87_group;
34958638d0afSGuenter Roeck 	data->groups[1] = &it87_group_in;
34968638d0afSGuenter Roeck 	data->groups[2] = &it87_group_temp;
34978638d0afSGuenter Roeck 	data->groups[3] = &it87_group_fan;
3498d9b327c3SJean Delvare 
34998d5d45fbSJean Delvare 	if (enable_pwm_interface) {
350048b2ae7fSGuenter Roeck 		data->has_pwm = BIT(ARRAY_SIZE(IT87_REG_PWM)) - 1;
35015c391261SGuenter Roeck 		data->has_pwm &= ~sio_data->skip_pwm;
35025c391261SGuenter Roeck 
35038638d0afSGuenter Roeck 		data->groups[4] = &it87_group_pwm;
35042cbb9c37SGuenter Roeck 		if (has_old_autopwm(data) || has_newer_autopwm(data))
35058638d0afSGuenter Roeck 			data->groups[5] = &it87_group_auto_pwm;
350698dd22c3SJean Delvare 	}
35078d5d45fbSJean Delvare 
35088638d0afSGuenter Roeck 	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
35098638d0afSGuenter Roeck 					it87_devices[sio_data->type].name,
35108638d0afSGuenter Roeck 					data, data->groups);
35118638d0afSGuenter Roeck 	return PTR_ERR_OR_ZERO(hwmon_dev);
35128d5d45fbSJean Delvare }
35138d5d45fbSJean Delvare 
it87_resume_sio(struct platform_device * pdev)351431b34d62SJonathan Cameron static void it87_resume_sio(struct platform_device *pdev)
3515384548e5SMaciej S. Szmigiero {
3516384548e5SMaciej S. Szmigiero 	struct it87_data *data = dev_get_drvdata(&pdev->dev);
3517384548e5SMaciej S. Szmigiero 	int err;
3518384548e5SMaciej S. Szmigiero 	int reg2c;
3519384548e5SMaciej S. Szmigiero 
3520384548e5SMaciej S. Szmigiero 	if (!data->need_in7_reroute)
3521384548e5SMaciej S. Szmigiero 		return;
3522384548e5SMaciej S. Szmigiero 
3523384548e5SMaciej S. Szmigiero 	err = superio_enter(data->sioaddr);
3524384548e5SMaciej S. Szmigiero 	if (err) {
3525384548e5SMaciej S. Szmigiero 		dev_warn(&pdev->dev,
3526384548e5SMaciej S. Szmigiero 			 "Unable to enter Super I/O to reroute in7 (%d)",
3527384548e5SMaciej S. Szmigiero 			 err);
3528384548e5SMaciej S. Szmigiero 		return;
3529384548e5SMaciej S. Szmigiero 	}
3530384548e5SMaciej S. Szmigiero 
3531384548e5SMaciej S. Szmigiero 	superio_select(data->sioaddr, GPIO);
3532384548e5SMaciej S. Szmigiero 
3533384548e5SMaciej S. Szmigiero 	reg2c = superio_inb(data->sioaddr, IT87_SIO_PINX2_REG);
3534384548e5SMaciej S. Szmigiero 	if (!(reg2c & BIT(1))) {
3535384548e5SMaciej S. Szmigiero 		dev_dbg(&pdev->dev,
3536384548e5SMaciej S. Szmigiero 			"Routing internal VCCH5V to in7 again");
3537384548e5SMaciej S. Szmigiero 
3538384548e5SMaciej S. Szmigiero 		reg2c |= BIT(1);
3539384548e5SMaciej S. Szmigiero 		superio_outb(data->sioaddr, IT87_SIO_PINX2_REG,
3540384548e5SMaciej S. Szmigiero 			     reg2c);
3541384548e5SMaciej S. Szmigiero 	}
3542384548e5SMaciej S. Szmigiero 
35434119693bSFrank Crawford 	superio_exit(data->sioaddr, has_conf_noexit(data));
3544384548e5SMaciej S. Szmigiero }
3545384548e5SMaciej S. Szmigiero 
it87_resume(struct device * dev)354631b34d62SJonathan Cameron static int it87_resume(struct device *dev)
3547384548e5SMaciej S. Szmigiero {
3548384548e5SMaciej S. Szmigiero 	struct platform_device *pdev = to_platform_device(dev);
3549384548e5SMaciej S. Szmigiero 	struct it87_data *data = dev_get_drvdata(dev);
3550384548e5SMaciej S. Szmigiero 
3551384548e5SMaciej S. Szmigiero 	it87_resume_sio(pdev);
3552384548e5SMaciej S. Szmigiero 
3553376e1a93SFrank Crawford 	it87_lock(data);
3554384548e5SMaciej S. Szmigiero 
3555384548e5SMaciej S. Szmigiero 	it87_check_pwm(dev);
3556384548e5SMaciej S. Szmigiero 	it87_check_limit_regs(data);
3557384548e5SMaciej S. Szmigiero 	it87_check_voltage_monitors_reset(data);
3558384548e5SMaciej S. Szmigiero 	it87_check_tachometers_reset(pdev);
3559384548e5SMaciej S. Szmigiero 	it87_check_tachometers_16bit_mode(pdev);
3560384548e5SMaciej S. Szmigiero 
3561384548e5SMaciej S. Szmigiero 	it87_start_monitoring(data);
3562384548e5SMaciej S. Szmigiero 
3563384548e5SMaciej S. Szmigiero 	/* force update */
3564952a11caSPaul Fertser 	data->valid = false;
3565384548e5SMaciej S. Szmigiero 
3566376e1a93SFrank Crawford 	it87_unlock(data);
3567384548e5SMaciej S. Szmigiero 
3568384548e5SMaciej S. Szmigiero 	it87_update_device(dev);
3569384548e5SMaciej S. Szmigiero 
3570384548e5SMaciej S. Szmigiero 	return 0;
3571384548e5SMaciej S. Szmigiero }
3572384548e5SMaciej S. Szmigiero 
357331b34d62SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume);
3574384548e5SMaciej S. Szmigiero 
3575c1e7a4caSGuenter Roeck static struct platform_driver it87_driver = {
3576c1e7a4caSGuenter Roeck 	.driver = {
3577c1e7a4caSGuenter Roeck 		.name	= DRVNAME,
357831b34d62SJonathan Cameron 		.pm     = pm_sleep_ptr(&it87_dev_pm_ops),
3579c1e7a4caSGuenter Roeck 	},
3580c1e7a4caSGuenter Roeck 	.probe	= it87_probe,
3581c1e7a4caSGuenter Roeck };
35828d5d45fbSJean Delvare 
it87_device_add(int index,unsigned short address,const struct it87_sio_data * sio_data)3583e84bd953SGuenter Roeck static int __init it87_device_add(int index, unsigned short address,
3584b74f3fddScorentin.labbe 				  const struct it87_sio_data *sio_data)
3585b74f3fddScorentin.labbe {
35868e50e3c3SGuenter Roeck 	struct platform_device *pdev;
3587b74f3fddScorentin.labbe 	struct resource res = {
358887b4b663SBjorn Helgaas 		.start	= address + IT87_EC_OFFSET,
358987b4b663SBjorn Helgaas 		.end	= address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,
3590b74f3fddScorentin.labbe 		.name	= DRVNAME,
3591b74f3fddScorentin.labbe 		.flags	= IORESOURCE_IO,
3592b74f3fddScorentin.labbe 	};
3593b74f3fddScorentin.labbe 	int err;
3594b74f3fddScorentin.labbe 
3595b9acb64aSJean Delvare 	err = acpi_check_resource_conflict(&res);
359612c44ab8SAhmad Khalifa 	if (err) {
359712c44ab8SAhmad Khalifa 		if (!ignore_resource_conflict)
35985cae84a5SGuenter Roeck 			return err;
359912c44ab8SAhmad Khalifa 	}
3600b9acb64aSJean Delvare 
3601b74f3fddScorentin.labbe 	pdev = platform_device_alloc(DRVNAME, address);
36025cae84a5SGuenter Roeck 	if (!pdev)
36035cae84a5SGuenter Roeck 		return -ENOMEM;
3604b74f3fddScorentin.labbe 
3605b74f3fddScorentin.labbe 	err = platform_device_add_resources(pdev, &res, 1);
3606b74f3fddScorentin.labbe 	if (err) {
3607a8ca1037SJoe Perches 		pr_err("Device resource addition failed (%d)\n", err);
3608b74f3fddScorentin.labbe 		goto exit_device_put;
3609b74f3fddScorentin.labbe 	}
3610b74f3fddScorentin.labbe 
3611b74f3fddScorentin.labbe 	err = platform_device_add_data(pdev, sio_data,
3612b74f3fddScorentin.labbe 				       sizeof(struct it87_sio_data));
3613b74f3fddScorentin.labbe 	if (err) {
3614a8ca1037SJoe Perches 		pr_err("Platform data allocation failed\n");
3615b74f3fddScorentin.labbe 		goto exit_device_put;
3616b74f3fddScorentin.labbe 	}
3617b74f3fddScorentin.labbe 
3618b74f3fddScorentin.labbe 	err = platform_device_add(pdev);
3619b74f3fddScorentin.labbe 	if (err) {
3620a8ca1037SJoe Perches 		pr_err("Device addition failed (%d)\n", err);
3621b74f3fddScorentin.labbe 		goto exit_device_put;
3622b74f3fddScorentin.labbe 	}
3623b74f3fddScorentin.labbe 
3624e84bd953SGuenter Roeck 	it87_pdev[index] = pdev;
3625b74f3fddScorentin.labbe 	return 0;
3626b74f3fddScorentin.labbe 
3627b74f3fddScorentin.labbe exit_device_put:
3628b74f3fddScorentin.labbe 	platform_device_put(pdev);
3629b74f3fddScorentin.labbe 	return err;
3630b74f3fddScorentin.labbe }
3631b74f3fddScorentin.labbe 
3632a1bedbccSFrank Crawford /* callback function for DMI */
it87_dmi_cb(const struct dmi_system_id * dmi_entry)3633a1bedbccSFrank Crawford static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
3634a1bedbccSFrank Crawford {
3635a1bedbccSFrank Crawford 	dmi_data = dmi_entry->driver_data;
3636a1bedbccSFrank Crawford 
3637a1bedbccSFrank Crawford 	if (dmi_data && dmi_data->skip_pwm)
3638a1bedbccSFrank Crawford 		pr_info("Disabling pwm2 due to hardware constraints\n");
3639a1bedbccSFrank Crawford 
3640a1bedbccSFrank Crawford 	return 1;
3641a1bedbccSFrank Crawford }
3642a1bedbccSFrank Crawford 
3643a1bedbccSFrank Crawford /*
3644ff9dedd2SFrank Crawford  * On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
3645ff9dedd2SFrank Crawford  * (IT8792E) needs to be in configuration mode before accessing the first
3646ff9dedd2SFrank Crawford  * due to a bug in IT8792E which otherwise results in LPC bus access errors.
3647ff9dedd2SFrank Crawford  * This needs to be done before accessing the first Super-IO chip since
3648ff9dedd2SFrank Crawford  * the second chip may have been accessed prior to loading this driver.
3649ff9dedd2SFrank Crawford  *
3650ff9dedd2SFrank Crawford  * The problem is also reported to affect IT8795E, which is used on X299 boards
3651ff9dedd2SFrank Crawford  * and has the same chip ID as IT8792E (0x8733). It also appears to affect
3652ff9dedd2SFrank Crawford  * systems with IT8790E, which is used on some Z97X-Gaming boards as well as
3653ff9dedd2SFrank Crawford  * Z87X-OC.
3654ff9dedd2SFrank Crawford  * DMI entries for those systems will be added as they become available and
3655ff9dedd2SFrank Crawford  * as the problem is confirmed to affect those boards.
3656ff9dedd2SFrank Crawford  */
it87_sio_force(const struct dmi_system_id * dmi_entry)3657ff9dedd2SFrank Crawford static int it87_sio_force(const struct dmi_system_id *dmi_entry)
3658ff9dedd2SFrank Crawford {
3659ff9dedd2SFrank Crawford 	__superio_enter(REG_4E);
3660ff9dedd2SFrank Crawford 
3661ff9dedd2SFrank Crawford 	return it87_dmi_cb(dmi_entry);
3662ff9dedd2SFrank Crawford };
3663ff9dedd2SFrank Crawford 
3664ff9dedd2SFrank Crawford /*
3665a1bedbccSFrank Crawford  * On the Shuttle SN68PT, FAN_CTL2 is apparently not
3666a1bedbccSFrank Crawford  * connected to a fan, but to something else. One user
3667a1bedbccSFrank Crawford  * has reported instant system power-off when changing
3668a1bedbccSFrank Crawford  * the PWM2 duty cycle, so we disable it.
3669a1bedbccSFrank Crawford  * I use the board name string as the trigger in case
3670a1bedbccSFrank Crawford  * the same board is ever used in other systems.
3671a1bedbccSFrank Crawford  */
3672a1bedbccSFrank Crawford static struct it87_dmi_data nvidia_fn68pt = {
3673a1bedbccSFrank Crawford 	.skip_pwm = BIT(1),
3674a1bedbccSFrank Crawford };
3675a1bedbccSFrank Crawford 
3676a1bedbccSFrank Crawford #define IT87_DMI_MATCH_VND(vendor, name, cb, data) \
3677a1bedbccSFrank Crawford 	{ \
3678a1bedbccSFrank Crawford 		.callback = cb, \
3679a1bedbccSFrank Crawford 		.matches = { \
3680a1bedbccSFrank Crawford 			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \
3681a1bedbccSFrank Crawford 			DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
3682a1bedbccSFrank Crawford 		}, \
3683a1bedbccSFrank Crawford 		.driver_data = data, \
3684a1bedbccSFrank Crawford 	}
3685a1bedbccSFrank Crawford 
3686ff9dedd2SFrank Crawford #define IT87_DMI_MATCH_GBT(name, cb, data) \
3687ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
3688ff9dedd2SFrank Crawford 
3689a1bedbccSFrank Crawford static const struct dmi_system_id it87_dmi_table[] __initconst = {
3690ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
3691ff9dedd2SFrank Crawford 		/* ? + IT8792E/IT8795E */
3692ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
3693ff9dedd2SFrank Crawford 		/* ? + IT8792E/IT8795E */
3694ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
3695ff9dedd2SFrank Crawford 		/* ? + IT8790E */
3696ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
3697ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3698ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
3699ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3700ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
3701ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3702ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
3703ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3704ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
3705ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3706ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
3707ff9dedd2SFrank Crawford 		/* IT8688E + IT8792E/IT8795E */
3708ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
3709ff9dedd2SFrank Crawford 		/* IT8689E + IT87952E */
3710ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
3711ff9dedd2SFrank Crawford 		/* IT8689E + IT87952E */
3712ff9dedd2SFrank Crawford 	IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
3713ff9dedd2SFrank Crawford 		/* IT8689E + IT87952E */
3714a1bedbccSFrank Crawford 	IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
3715a1bedbccSFrank Crawford 	{ }
3716a1bedbccSFrank Crawford 
3717a1bedbccSFrank Crawford };
3718a1bedbccSFrank Crawford MODULE_DEVICE_TABLE(dmi, it87_dmi_table);
3719a1bedbccSFrank Crawford 
sm_it87_init(void)37208d5d45fbSJean Delvare static int __init sm_it87_init(void)
37218d5d45fbSJean Delvare {
3722e84bd953SGuenter Roeck 	int sioaddr[2] = { REG_2E, REG_4E };
3723b74f3fddScorentin.labbe 	struct it87_sio_data sio_data;
37248358378bSGuenter Roeck 	unsigned short isa_address[2];
3725e84bd953SGuenter Roeck 	bool found = false;
3726e84bd953SGuenter Roeck 	int i, err;
3727fde09509SJean Delvare 
3728b74f3fddScorentin.labbe 	err = platform_driver_register(&it87_driver);
3729b74f3fddScorentin.labbe 	if (err)
3730b74f3fddScorentin.labbe 		return err;
3731b74f3fddScorentin.labbe 
3732a1bedbccSFrank Crawford 	dmi_check_system(it87_dmi_table);
3733a1bedbccSFrank Crawford 
3734e84bd953SGuenter Roeck 	for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
3735e84bd953SGuenter Roeck 		memset(&sio_data, 0, sizeof(struct it87_sio_data));
37368358378bSGuenter Roeck 		isa_address[i] = 0;
37372a64e9d4SFrank Crawford 		err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i);
37388358378bSGuenter Roeck 		if (err || isa_address[i] == 0)
3739e84bd953SGuenter Roeck 			continue;
37408358378bSGuenter Roeck 		/*
37418358378bSGuenter Roeck 		 * Don't register second chip if its ISA address matches
37428358378bSGuenter Roeck 		 * the first chip's ISA address.
37438358378bSGuenter Roeck 		 */
37448358378bSGuenter Roeck 		if (i && isa_address[i] == isa_address[0])
37458358378bSGuenter Roeck 			break;
3746e84bd953SGuenter Roeck 
37478358378bSGuenter Roeck 		err = it87_device_add(i, isa_address[i], &sio_data);
3748e84bd953SGuenter Roeck 		if (err)
3749e84bd953SGuenter Roeck 			goto exit_dev_unregister;
37508358378bSGuenter Roeck 
3751e84bd953SGuenter Roeck 		found = true;
37528358378bSGuenter Roeck 
37538358378bSGuenter Roeck 		/*
37548358378bSGuenter Roeck 		 * IT8705F may respond on both SIO addresses.
37558358378bSGuenter Roeck 		 * Stop probing after finding one.
37568358378bSGuenter Roeck 		 */
37578358378bSGuenter Roeck 		if (sio_data.type == it87)
37588358378bSGuenter Roeck 			break;
3759e84bd953SGuenter Roeck 	}
3760e84bd953SGuenter Roeck 
3761e84bd953SGuenter Roeck 	if (!found) {
3762e84bd953SGuenter Roeck 		err = -ENODEV;
3763e84bd953SGuenter Roeck 		goto exit_unregister;
3764e84bd953SGuenter Roeck 	}
3765e84bd953SGuenter Roeck 	return 0;
3766e84bd953SGuenter Roeck 
3767e84bd953SGuenter Roeck exit_dev_unregister:
3768e84bd953SGuenter Roeck 	/* NULL check handled by platform_device_unregister */
3769e84bd953SGuenter Roeck 	platform_device_unregister(it87_pdev[0]);
3770e84bd953SGuenter Roeck exit_unregister:
3771b74f3fddScorentin.labbe 	platform_driver_unregister(&it87_driver);
3772b74f3fddScorentin.labbe 	return err;
3773b74f3fddScorentin.labbe }
3774b74f3fddScorentin.labbe 
sm_it87_exit(void)37758d5d45fbSJean Delvare static void __exit sm_it87_exit(void)
37768d5d45fbSJean Delvare {
3777e84bd953SGuenter Roeck 	/* NULL check handled by platform_device_unregister */
3778e84bd953SGuenter Roeck 	platform_device_unregister(it87_pdev[1]);
3779e84bd953SGuenter Roeck 	platform_device_unregister(it87_pdev[0]);
3780b74f3fddScorentin.labbe 	platform_driver_unregister(&it87_driver);
37818d5d45fbSJean Delvare }
37828d5d45fbSJean Delvare 
37837c81c60fSJean Delvare MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
378444c1bcd4SJean Delvare MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
3785b361a1cfSFrank Crawford 
37862a64e9d4SFrank Crawford module_param_array(force_id, ushort, &force_id_cnt, 0);
37872a64e9d4SFrank Crawford MODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)");
3788b361a1cfSFrank Crawford 
3789b361a1cfSFrank Crawford module_param(ignore_resource_conflict, bool, 0);
3790b361a1cfSFrank Crawford MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
3791b361a1cfSFrank Crawford 
37928d5d45fbSJean Delvare module_param(update_vbat, bool, 0);
37938d5d45fbSJean Delvare MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
3794b361a1cfSFrank Crawford 
37958d5d45fbSJean Delvare module_param(fix_pwm_polarity, bool, 0);
37965f2dc798SJean Delvare MODULE_PARM_DESC(fix_pwm_polarity,
37975f2dc798SJean Delvare 		 "Force PWM polarity to active high (DANGEROUS)");
3798b361a1cfSFrank Crawford 
37998d5d45fbSJean Delvare MODULE_LICENSE("GPL");
38008d5d45fbSJean Delvare 
38018d5d45fbSJean Delvare module_init(sm_it87_init);
38028d5d45fbSJean Delvare module_exit(sm_it87_exit);
3803