162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  it87.c - Part of lm_sensors, Linux kernel modules for hardware
462306a36Sopenharmony_ci *           monitoring.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci *  The IT8705F is an LPC-based Super I/O part that contains UARTs, a
762306a36Sopenharmony_ci *  parallel port, an IR port, a MIDI port, a floppy controller, etc., in
862306a36Sopenharmony_ci *  addition to an Environment Controller (Enhanced Hardware Monitor and
962306a36Sopenharmony_ci *  Fan Controller)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  This driver supports only the Environment Controller in the IT8705F and
1262306a36Sopenharmony_ci *  similar parts.  The other devices are supported by different drivers.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci *  Supports: IT8603E  Super I/O chip w/LPC interface
1562306a36Sopenharmony_ci *            IT8620E  Super I/O chip w/LPC interface
1662306a36Sopenharmony_ci *            IT8622E  Super I/O chip w/LPC interface
1762306a36Sopenharmony_ci *            IT8623E  Super I/O chip w/LPC interface
1862306a36Sopenharmony_ci *            IT8628E  Super I/O chip w/LPC interface
1962306a36Sopenharmony_ci *            IT8705F  Super I/O chip w/LPC interface
2062306a36Sopenharmony_ci *            IT8712F  Super I/O chip w/LPC interface
2162306a36Sopenharmony_ci *            IT8716F  Super I/O chip w/LPC interface
2262306a36Sopenharmony_ci *            IT8718F  Super I/O chip w/LPC interface
2362306a36Sopenharmony_ci *            IT8720F  Super I/O chip w/LPC interface
2462306a36Sopenharmony_ci *            IT8721F  Super I/O chip w/LPC interface
2562306a36Sopenharmony_ci *            IT8726F  Super I/O chip w/LPC interface
2662306a36Sopenharmony_ci *            IT8728F  Super I/O chip w/LPC interface
2762306a36Sopenharmony_ci *            IT8732F  Super I/O chip w/LPC interface
2862306a36Sopenharmony_ci *            IT8758E  Super I/O chip w/LPC interface
2962306a36Sopenharmony_ci *            IT8771E  Super I/O chip w/LPC interface
3062306a36Sopenharmony_ci *            IT8772E  Super I/O chip w/LPC interface
3162306a36Sopenharmony_ci *            IT8781F  Super I/O chip w/LPC interface
3262306a36Sopenharmony_ci *            IT8782F  Super I/O chip w/LPC interface
3362306a36Sopenharmony_ci *            IT8783E/F Super I/O chip w/LPC interface
3462306a36Sopenharmony_ci *            IT8786E  Super I/O chip w/LPC interface
3562306a36Sopenharmony_ci *            IT8790E  Super I/O chip w/LPC interface
3662306a36Sopenharmony_ci *            IT8792E  Super I/O chip w/LPC interface
3762306a36Sopenharmony_ci *            IT87952E  Super I/O chip w/LPC interface
3862306a36Sopenharmony_ci *            Sis950   A clone of the IT8705F
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci *  Copyright (C) 2001 Chris Gauthron
4162306a36Sopenharmony_ci *  Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.de>
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#include <linux/bitops.h>
4762306a36Sopenharmony_ci#include <linux/module.h>
4862306a36Sopenharmony_ci#include <linux/init.h>
4962306a36Sopenharmony_ci#include <linux/slab.h>
5062306a36Sopenharmony_ci#include <linux/jiffies.h>
5162306a36Sopenharmony_ci#include <linux/platform_device.h>
5262306a36Sopenharmony_ci#include <linux/hwmon.h>
5362306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
5462306a36Sopenharmony_ci#include <linux/hwmon-vid.h>
5562306a36Sopenharmony_ci#include <linux/err.h>
5662306a36Sopenharmony_ci#include <linux/mutex.h>
5762306a36Sopenharmony_ci#include <linux/sysfs.h>
5862306a36Sopenharmony_ci#include <linux/string.h>
5962306a36Sopenharmony_ci#include <linux/dmi.h>
6062306a36Sopenharmony_ci#include <linux/acpi.h>
6162306a36Sopenharmony_ci#include <linux/io.h>
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define DRVNAME "it87"
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cienum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
6662306a36Sopenharmony_ci	     it8771, it8772, it8781, it8782, it8783, it8786, it8790,
6762306a36Sopenharmony_ci	     it8792, it8603, it8620, it8622, it8628, it87952 };
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic struct platform_device *it87_pdev[2];
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#define	REG_2E	0x2e	/* The register to read/write */
7262306a36Sopenharmony_ci#define	REG_4E	0x4e	/* Secondary register to read/write */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define	DEV	0x07	/* Register: Logical device select */
7562306a36Sopenharmony_ci#define PME	0x04	/* The device with the fan registers in it */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* The device with the IT8718F/IT8720F VID value in it */
7862306a36Sopenharmony_ci#define GPIO	0x07
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#define	DEVID	0x20	/* Register: Device ID */
8162306a36Sopenharmony_ci#define	DEVREV	0x22	/* Register: Device Revision */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic inline void __superio_enter(int ioreg)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	outb(0x87, ioreg);
8662306a36Sopenharmony_ci	outb(0x01, ioreg);
8762306a36Sopenharmony_ci	outb(0x55, ioreg);
8862306a36Sopenharmony_ci	outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic inline int superio_inb(int ioreg, int reg)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	outb(reg, ioreg);
9462306a36Sopenharmony_ci	return inb(ioreg + 1);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic inline void superio_outb(int ioreg, int reg, int val)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	outb(reg, ioreg);
10062306a36Sopenharmony_ci	outb(val, ioreg + 1);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int superio_inw(int ioreg, int reg)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	int val;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	outb(reg++, ioreg);
10862306a36Sopenharmony_ci	val = inb(ioreg + 1) << 8;
10962306a36Sopenharmony_ci	outb(reg, ioreg);
11062306a36Sopenharmony_ci	val |= inb(ioreg + 1);
11162306a36Sopenharmony_ci	return val;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic inline void superio_select(int ioreg, int ldn)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	outb(DEV, ioreg);
11762306a36Sopenharmony_ci	outb(ldn, ioreg + 1);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline int superio_enter(int ioreg)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	/*
12362306a36Sopenharmony_ci	 * Try to reserve ioreg and ioreg + 1 for exclusive access.
12462306a36Sopenharmony_ci	 */
12562306a36Sopenharmony_ci	if (!request_muxed_region(ioreg, 2, DRVNAME))
12662306a36Sopenharmony_ci		return -EBUSY;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	__superio_enter(ioreg);
12962306a36Sopenharmony_ci	return 0;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic inline void superio_exit(int ioreg, bool noexit)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	if (!noexit) {
13562306a36Sopenharmony_ci		outb(0x02, ioreg);
13662306a36Sopenharmony_ci		outb(0x02, ioreg + 1);
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	release_region(ioreg, 2);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* Logical device 4 registers */
14262306a36Sopenharmony_ci#define IT8712F_DEVID 0x8712
14362306a36Sopenharmony_ci#define IT8705F_DEVID 0x8705
14462306a36Sopenharmony_ci#define IT8716F_DEVID 0x8716
14562306a36Sopenharmony_ci#define IT8718F_DEVID 0x8718
14662306a36Sopenharmony_ci#define IT8720F_DEVID 0x8720
14762306a36Sopenharmony_ci#define IT8721F_DEVID 0x8721
14862306a36Sopenharmony_ci#define IT8726F_DEVID 0x8726
14962306a36Sopenharmony_ci#define IT8728F_DEVID 0x8728
15062306a36Sopenharmony_ci#define IT8732F_DEVID 0x8732
15162306a36Sopenharmony_ci#define IT8792E_DEVID 0x8733
15262306a36Sopenharmony_ci#define IT8771E_DEVID 0x8771
15362306a36Sopenharmony_ci#define IT8772E_DEVID 0x8772
15462306a36Sopenharmony_ci#define IT8781F_DEVID 0x8781
15562306a36Sopenharmony_ci#define IT8782F_DEVID 0x8782
15662306a36Sopenharmony_ci#define IT8783E_DEVID 0x8783
15762306a36Sopenharmony_ci#define IT8786E_DEVID 0x8786
15862306a36Sopenharmony_ci#define IT8790E_DEVID 0x8790
15962306a36Sopenharmony_ci#define IT8603E_DEVID 0x8603
16062306a36Sopenharmony_ci#define IT8620E_DEVID 0x8620
16162306a36Sopenharmony_ci#define IT8622E_DEVID 0x8622
16262306a36Sopenharmony_ci#define IT8623E_DEVID 0x8623
16362306a36Sopenharmony_ci#define IT8628E_DEVID 0x8628
16462306a36Sopenharmony_ci#define IT87952E_DEVID 0x8695
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/* Logical device 4 (Environmental Monitor) registers */
16762306a36Sopenharmony_ci#define IT87_ACT_REG	0x30
16862306a36Sopenharmony_ci#define IT87_BASE_REG	0x60
16962306a36Sopenharmony_ci#define IT87_SPECIAL_CFG_REG	0xf3	/* special configuration register */
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/* Logical device 7 registers (IT8712F and later) */
17262306a36Sopenharmony_ci#define IT87_SIO_GPIO1_REG	0x25
17362306a36Sopenharmony_ci#define IT87_SIO_GPIO2_REG	0x26
17462306a36Sopenharmony_ci#define IT87_SIO_GPIO3_REG	0x27
17562306a36Sopenharmony_ci#define IT87_SIO_GPIO4_REG	0x28
17662306a36Sopenharmony_ci#define IT87_SIO_GPIO5_REG	0x29
17762306a36Sopenharmony_ci#define IT87_SIO_PINX1_REG	0x2a	/* Pin selection */
17862306a36Sopenharmony_ci#define IT87_SIO_PINX2_REG	0x2c	/* Pin selection */
17962306a36Sopenharmony_ci#define IT87_SIO_SPI_REG	0xef	/* SPI function pin select */
18062306a36Sopenharmony_ci#define IT87_SIO_VID_REG	0xfc	/* VID value */
18162306a36Sopenharmony_ci#define IT87_SIO_BEEP_PIN_REG	0xf6	/* Beep pin mapping */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* Force chip IDs to specified values. Should only be used for testing */
18462306a36Sopenharmony_cistatic unsigned short force_id[2];
18562306a36Sopenharmony_cistatic unsigned int force_id_cnt;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/* ACPI resource conflicts are ignored if this parameter is set to 1 */
18862306a36Sopenharmony_cistatic bool ignore_resource_conflict;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* Update battery voltage after every reading if true */
19162306a36Sopenharmony_cistatic bool update_vbat;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* Not all BIOSes properly configure the PWM registers */
19462306a36Sopenharmony_cistatic bool fix_pwm_polarity;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci/* Many IT87 constants specified below */
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* Length of ISA address segment */
19962306a36Sopenharmony_ci#define IT87_EXTENT 8
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Length of ISA address segment for Environmental Controller */
20262306a36Sopenharmony_ci#define IT87_EC_EXTENT 2
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* Offset of EC registers from ISA base address */
20562306a36Sopenharmony_ci#define IT87_EC_OFFSET 5
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* Where are the ISA address/data registers relative to the EC base address */
20862306a36Sopenharmony_ci#define IT87_ADDR_REG_OFFSET 0
20962306a36Sopenharmony_ci#define IT87_DATA_REG_OFFSET 1
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/*----- The IT87 registers -----*/
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci#define IT87_REG_CONFIG        0x00
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci#define IT87_REG_ALARM1        0x01
21662306a36Sopenharmony_ci#define IT87_REG_ALARM2        0x02
21762306a36Sopenharmony_ci#define IT87_REG_ALARM3        0x03
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/*
22062306a36Sopenharmony_ci * The IT8718F and IT8720F have the VID value in a different register, in
22162306a36Sopenharmony_ci * Super-I/O configuration space.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_ci#define IT87_REG_VID           0x0a
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Interface Selection register on other chips */
22662306a36Sopenharmony_ci#define IT87_REG_IFSEL         0x0a
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci/*
22962306a36Sopenharmony_ci * The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
23062306a36Sopenharmony_ci * for fan divisors. Later IT8712F revisions must use 16-bit tachometer
23162306a36Sopenharmony_ci * mode.
23262306a36Sopenharmony_ci */
23362306a36Sopenharmony_ci#define IT87_REG_FAN_DIV       0x0b
23462306a36Sopenharmony_ci#define IT87_REG_FAN_16BIT     0x0c
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*
23762306a36Sopenharmony_ci * Monitors:
23862306a36Sopenharmony_ci * - up to 13 voltage (0 to 7, battery, avcc, 10 to 12)
23962306a36Sopenharmony_ci * - up to 6 temp (1 to 6)
24062306a36Sopenharmony_ci * - up to 6 fan (1 to 6)
24162306a36Sopenharmony_ci */
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic const u8 IT87_REG_FAN[]         = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
24462306a36Sopenharmony_cistatic const u8 IT87_REG_FAN_MIN[]     = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
24562306a36Sopenharmony_cistatic const u8 IT87_REG_FANX[]        = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d };
24662306a36Sopenharmony_cistatic const u8 IT87_REG_FANX_MIN[]    = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f };
24762306a36Sopenharmony_cistatic const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci#define IT87_REG_FAN_MAIN_CTRL 0x13
25062306a36Sopenharmony_ci#define IT87_REG_FAN_CTL       0x14
25162306a36Sopenharmony_cistatic const u8 IT87_REG_PWM[]         = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
25262306a36Sopenharmony_cistatic const u8 IT87_REG_PWM_DUTY[]    = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic const u8 IT87_REG_VIN[]	= { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
25562306a36Sopenharmony_ci				    0x27, 0x28, 0x2f, 0x2c, 0x2d, 0x2e };
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci#define IT87_REG_TEMP(nr)      (0x29 + (nr))
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci#define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)
26062306a36Sopenharmony_ci#define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)
26162306a36Sopenharmony_ci#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2)
26262306a36Sopenharmony_ci#define IT87_REG_TEMP_LOW(nr)  (0x41 + (nr) * 2)
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci#define IT87_REG_VIN_ENABLE    0x50
26562306a36Sopenharmony_ci#define IT87_REG_TEMP_ENABLE   0x51
26662306a36Sopenharmony_ci#define IT87_REG_TEMP_EXTRA    0x55
26762306a36Sopenharmony_ci#define IT87_REG_BEEP_ENABLE   0x5c
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci#define IT87_REG_CHIPID        0x58
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci#define IT87_REG_AUTO_TEMP(nr, i) (IT87_REG_AUTO_BASE[nr] + (i))
27462306a36Sopenharmony_ci#define IT87_REG_AUTO_PWM(nr, i)  (IT87_REG_AUTO_BASE[nr] + 5 + (i))
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci#define IT87_REG_TEMP456_ENABLE	0x77
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci#define NUM_VIN			ARRAY_SIZE(IT87_REG_VIN)
27962306a36Sopenharmony_ci#define NUM_VIN_LIMIT		8
28062306a36Sopenharmony_ci#define NUM_TEMP		6
28162306a36Sopenharmony_ci#define NUM_TEMP_OFFSET		ARRAY_SIZE(IT87_REG_TEMP_OFFSET)
28262306a36Sopenharmony_ci#define NUM_TEMP_LIMIT		3
28362306a36Sopenharmony_ci#define NUM_FAN			ARRAY_SIZE(IT87_REG_FAN)
28462306a36Sopenharmony_ci#define NUM_FAN_DIV		3
28562306a36Sopenharmony_ci#define NUM_PWM			ARRAY_SIZE(IT87_REG_PWM)
28662306a36Sopenharmony_ci#define NUM_AUTO_PWM		ARRAY_SIZE(IT87_REG_PWM)
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistruct it87_devices {
28962306a36Sopenharmony_ci	const char *name;
29062306a36Sopenharmony_ci	const char * const model;
29162306a36Sopenharmony_ci	u32 features;
29262306a36Sopenharmony_ci	u8 peci_mask;
29362306a36Sopenharmony_ci	u8 old_peci_mask;
29462306a36Sopenharmony_ci	u8 smbus_bitmap;	/* SMBus enable bits in extra config register */
29562306a36Sopenharmony_ci	u8 ec_special_config;
29662306a36Sopenharmony_ci};
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#define FEAT_12MV_ADC		BIT(0)
29962306a36Sopenharmony_ci#define FEAT_NEWER_AUTOPWM	BIT(1)
30062306a36Sopenharmony_ci#define FEAT_OLD_AUTOPWM	BIT(2)
30162306a36Sopenharmony_ci#define FEAT_16BIT_FANS		BIT(3)
30262306a36Sopenharmony_ci#define FEAT_TEMP_OFFSET	BIT(4)
30362306a36Sopenharmony_ci#define FEAT_TEMP_PECI		BIT(5)
30462306a36Sopenharmony_ci#define FEAT_TEMP_OLD_PECI	BIT(6)
30562306a36Sopenharmony_ci#define FEAT_FAN16_CONFIG	BIT(7)	/* Need to enable 16-bit fans */
30662306a36Sopenharmony_ci#define FEAT_FIVE_FANS		BIT(8)	/* Supports five fans */
30762306a36Sopenharmony_ci#define FEAT_VID		BIT(9)	/* Set if chip supports VID */
30862306a36Sopenharmony_ci#define FEAT_IN7_INTERNAL	BIT(10)	/* Set if in7 is internal */
30962306a36Sopenharmony_ci#define FEAT_SIX_FANS		BIT(11)	/* Supports six fans */
31062306a36Sopenharmony_ci#define FEAT_10_9MV_ADC		BIT(12)
31162306a36Sopenharmony_ci#define FEAT_AVCC3		BIT(13)	/* Chip supports in9/AVCC3 */
31262306a36Sopenharmony_ci#define FEAT_FIVE_PWM		BIT(14)	/* Chip supports 5 pwm chn */
31362306a36Sopenharmony_ci#define FEAT_SIX_PWM		BIT(15)	/* Chip supports 6 pwm chn */
31462306a36Sopenharmony_ci#define FEAT_PWM_FREQ2		BIT(16)	/* Separate pwm freq 2 */
31562306a36Sopenharmony_ci#define FEAT_SIX_TEMP		BIT(17)	/* Up to 6 temp sensors */
31662306a36Sopenharmony_ci#define FEAT_VIN3_5V		BIT(18)	/* VIN3 connected to +5V */
31762306a36Sopenharmony_ci/*
31862306a36Sopenharmony_ci * Disabling configuration mode on some chips can result in system
31962306a36Sopenharmony_ci * hang-ups and access failures to the Super-IO chip at the
32062306a36Sopenharmony_ci * second SIO address. Never exit configuration mode on these
32162306a36Sopenharmony_ci * chips to avoid the problem.
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_ci#define FEAT_CONF_NOEXIT	BIT(19)	/* Chip should not exit conf mode */
32462306a36Sopenharmony_ci#define FEAT_FOUR_FANS		BIT(20)	/* Supports four fans */
32562306a36Sopenharmony_ci#define FEAT_FOUR_PWM		BIT(21)	/* Supports four fan controls */
32662306a36Sopenharmony_ci#define FEAT_FOUR_TEMP		BIT(22)
32762306a36Sopenharmony_ci#define FEAT_FANCTL_ONOFF	BIT(23)	/* chip has FAN_CTL ON/OFF */
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic const struct it87_devices it87_devices[] = {
33062306a36Sopenharmony_ci	[it87] = {
33162306a36Sopenharmony_ci		.name = "it87",
33262306a36Sopenharmony_ci		.model = "IT87F",
33362306a36Sopenharmony_ci		.features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
33462306a36Sopenharmony_ci		/* may need to overwrite */
33562306a36Sopenharmony_ci	},
33662306a36Sopenharmony_ci	[it8712] = {
33762306a36Sopenharmony_ci		.name = "it8712",
33862306a36Sopenharmony_ci		.model = "IT8712F",
33962306a36Sopenharmony_ci		.features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
34062306a36Sopenharmony_ci		/* may need to overwrite */
34162306a36Sopenharmony_ci	},
34262306a36Sopenharmony_ci	[it8716] = {
34362306a36Sopenharmony_ci		.name = "it8716",
34462306a36Sopenharmony_ci		.model = "IT8716F",
34562306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
34662306a36Sopenharmony_ci		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
34762306a36Sopenharmony_ci		  | FEAT_FANCTL_ONOFF,
34862306a36Sopenharmony_ci	},
34962306a36Sopenharmony_ci	[it8718] = {
35062306a36Sopenharmony_ci		.name = "it8718",
35162306a36Sopenharmony_ci		.model = "IT8718F",
35262306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
35362306a36Sopenharmony_ci		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
35462306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
35562306a36Sopenharmony_ci		.old_peci_mask = 0x4,
35662306a36Sopenharmony_ci	},
35762306a36Sopenharmony_ci	[it8720] = {
35862306a36Sopenharmony_ci		.name = "it8720",
35962306a36Sopenharmony_ci		.model = "IT8720F",
36062306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
36162306a36Sopenharmony_ci		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
36262306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
36362306a36Sopenharmony_ci		.old_peci_mask = 0x4,
36462306a36Sopenharmony_ci	},
36562306a36Sopenharmony_ci	[it8721] = {
36662306a36Sopenharmony_ci		.name = "it8721",
36762306a36Sopenharmony_ci		.model = "IT8721F",
36862306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
36962306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
37062306a36Sopenharmony_ci		  | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
37162306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
37262306a36Sopenharmony_ci		.peci_mask = 0x05,
37362306a36Sopenharmony_ci		.old_peci_mask = 0x02,	/* Actually reports PCH */
37462306a36Sopenharmony_ci	},
37562306a36Sopenharmony_ci	[it8728] = {
37662306a36Sopenharmony_ci		.name = "it8728",
37762306a36Sopenharmony_ci		.model = "IT8728F",
37862306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
37962306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
38062306a36Sopenharmony_ci		  | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
38162306a36Sopenharmony_ci		  | FEAT_FANCTL_ONOFF,
38262306a36Sopenharmony_ci		.peci_mask = 0x07,
38362306a36Sopenharmony_ci	},
38462306a36Sopenharmony_ci	[it8732] = {
38562306a36Sopenharmony_ci		.name = "it8732",
38662306a36Sopenharmony_ci		.model = "IT8732F",
38762306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
38862306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
38962306a36Sopenharmony_ci		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
39062306a36Sopenharmony_ci		  | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
39162306a36Sopenharmony_ci		.peci_mask = 0x07,
39262306a36Sopenharmony_ci		.old_peci_mask = 0x02,	/* Actually reports PCH */
39362306a36Sopenharmony_ci	},
39462306a36Sopenharmony_ci	[it8771] = {
39562306a36Sopenharmony_ci		.name = "it8771",
39662306a36Sopenharmony_ci		.model = "IT8771E",
39762306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
39862306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
39962306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
40062306a36Sopenharmony_ci				/* PECI: guesswork */
40162306a36Sopenharmony_ci				/* 12mV ADC (OHM) */
40262306a36Sopenharmony_ci				/* 16 bit fans (OHM) */
40362306a36Sopenharmony_ci				/* three fans, always 16 bit (guesswork) */
40462306a36Sopenharmony_ci		.peci_mask = 0x07,
40562306a36Sopenharmony_ci	},
40662306a36Sopenharmony_ci	[it8772] = {
40762306a36Sopenharmony_ci		.name = "it8772",
40862306a36Sopenharmony_ci		.model = "IT8772E",
40962306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
41062306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
41162306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
41262306a36Sopenharmony_ci				/* PECI (coreboot) */
41362306a36Sopenharmony_ci				/* 12mV ADC (HWSensors4, OHM) */
41462306a36Sopenharmony_ci				/* 16 bit fans (HWSensors4, OHM) */
41562306a36Sopenharmony_ci				/* three fans, always 16 bit (datasheet) */
41662306a36Sopenharmony_ci		.peci_mask = 0x07,
41762306a36Sopenharmony_ci	},
41862306a36Sopenharmony_ci	[it8781] = {
41962306a36Sopenharmony_ci		.name = "it8781",
42062306a36Sopenharmony_ci		.model = "IT8781F",
42162306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
42262306a36Sopenharmony_ci		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
42362306a36Sopenharmony_ci		  | FEAT_FANCTL_ONOFF,
42462306a36Sopenharmony_ci		.old_peci_mask = 0x4,
42562306a36Sopenharmony_ci	},
42662306a36Sopenharmony_ci	[it8782] = {
42762306a36Sopenharmony_ci		.name = "it8782",
42862306a36Sopenharmony_ci		.model = "IT8782F",
42962306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
43062306a36Sopenharmony_ci		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
43162306a36Sopenharmony_ci		  | FEAT_FANCTL_ONOFF,
43262306a36Sopenharmony_ci		.old_peci_mask = 0x4,
43362306a36Sopenharmony_ci	},
43462306a36Sopenharmony_ci	[it8783] = {
43562306a36Sopenharmony_ci		.name = "it8783",
43662306a36Sopenharmony_ci		.model = "IT8783E/F",
43762306a36Sopenharmony_ci		.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
43862306a36Sopenharmony_ci		  | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
43962306a36Sopenharmony_ci		  | FEAT_FANCTL_ONOFF,
44062306a36Sopenharmony_ci		.old_peci_mask = 0x4,
44162306a36Sopenharmony_ci	},
44262306a36Sopenharmony_ci	[it8786] = {
44362306a36Sopenharmony_ci		.name = "it8786",
44462306a36Sopenharmony_ci		.model = "IT8786E",
44562306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
44662306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
44762306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
44862306a36Sopenharmony_ci		.peci_mask = 0x07,
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci	[it8790] = {
45162306a36Sopenharmony_ci		.name = "it8790",
45262306a36Sopenharmony_ci		.model = "IT8790E",
45362306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
45462306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
45562306a36Sopenharmony_ci		  | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_CONF_NOEXIT,
45662306a36Sopenharmony_ci		.peci_mask = 0x07,
45762306a36Sopenharmony_ci	},
45862306a36Sopenharmony_ci	[it8792] = {
45962306a36Sopenharmony_ci		.name = "it8792",
46062306a36Sopenharmony_ci		.model = "IT8792E/IT8795E",
46162306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
46262306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
46362306a36Sopenharmony_ci		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
46462306a36Sopenharmony_ci		  | FEAT_CONF_NOEXIT,
46562306a36Sopenharmony_ci		.peci_mask = 0x07,
46662306a36Sopenharmony_ci		.old_peci_mask = 0x02,	/* Actually reports PCH */
46762306a36Sopenharmony_ci	},
46862306a36Sopenharmony_ci	[it8603] = {
46962306a36Sopenharmony_ci		.name = "it8603",
47062306a36Sopenharmony_ci		.model = "IT8603E",
47162306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
47262306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
47362306a36Sopenharmony_ci		  | FEAT_AVCC3 | FEAT_PWM_FREQ2,
47462306a36Sopenharmony_ci		.peci_mask = 0x07,
47562306a36Sopenharmony_ci	},
47662306a36Sopenharmony_ci	[it8620] = {
47762306a36Sopenharmony_ci		.name = "it8620",
47862306a36Sopenharmony_ci		.model = "IT8620E",
47962306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
48062306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
48162306a36Sopenharmony_ci		  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
48262306a36Sopenharmony_ci		  | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
48362306a36Sopenharmony_ci		.peci_mask = 0x07,
48462306a36Sopenharmony_ci	},
48562306a36Sopenharmony_ci	[it8622] = {
48662306a36Sopenharmony_ci		.name = "it8622",
48762306a36Sopenharmony_ci		.model = "IT8622E",
48862306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
48962306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
49062306a36Sopenharmony_ci		  | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
49162306a36Sopenharmony_ci		  | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
49262306a36Sopenharmony_ci		.peci_mask = 0x07,
49362306a36Sopenharmony_ci		.smbus_bitmap = BIT(1) | BIT(2),
49462306a36Sopenharmony_ci	},
49562306a36Sopenharmony_ci	[it8628] = {
49662306a36Sopenharmony_ci		.name = "it8628",
49762306a36Sopenharmony_ci		.model = "IT8628E",
49862306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
49962306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
50062306a36Sopenharmony_ci		  | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
50162306a36Sopenharmony_ci		  | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
50262306a36Sopenharmony_ci		.peci_mask = 0x07,
50362306a36Sopenharmony_ci	},
50462306a36Sopenharmony_ci	[it87952] = {
50562306a36Sopenharmony_ci		.name = "it87952",
50662306a36Sopenharmony_ci		.model = "IT87952E",
50762306a36Sopenharmony_ci		.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
50862306a36Sopenharmony_ci		  | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
50962306a36Sopenharmony_ci		  | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
51062306a36Sopenharmony_ci		  | FEAT_CONF_NOEXIT,
51162306a36Sopenharmony_ci		.peci_mask = 0x07,
51262306a36Sopenharmony_ci		.old_peci_mask = 0x02,	/* Actually reports PCH */
51362306a36Sopenharmony_ci	},
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci#define has_16bit_fans(data)	((data)->features & FEAT_16BIT_FANS)
51762306a36Sopenharmony_ci#define has_12mv_adc(data)	((data)->features & FEAT_12MV_ADC)
51862306a36Sopenharmony_ci#define has_10_9mv_adc(data)	((data)->features & FEAT_10_9MV_ADC)
51962306a36Sopenharmony_ci#define has_newer_autopwm(data)	((data)->features & FEAT_NEWER_AUTOPWM)
52062306a36Sopenharmony_ci#define has_old_autopwm(data)	((data)->features & FEAT_OLD_AUTOPWM)
52162306a36Sopenharmony_ci#define has_temp_offset(data)	((data)->features & FEAT_TEMP_OFFSET)
52262306a36Sopenharmony_ci#define has_temp_peci(data, nr)	(((data)->features & FEAT_TEMP_PECI) && \
52362306a36Sopenharmony_ci				 ((data)->peci_mask & BIT(nr)))
52462306a36Sopenharmony_ci#define has_temp_old_peci(data, nr) \
52562306a36Sopenharmony_ci				(((data)->features & FEAT_TEMP_OLD_PECI) && \
52662306a36Sopenharmony_ci				 ((data)->old_peci_mask & BIT(nr)))
52762306a36Sopenharmony_ci#define has_fan16_config(data)	((data)->features & FEAT_FAN16_CONFIG)
52862306a36Sopenharmony_ci#define has_four_fans(data)	((data)->features & (FEAT_FOUR_FANS | \
52962306a36Sopenharmony_ci						     FEAT_FIVE_FANS | \
53062306a36Sopenharmony_ci						     FEAT_SIX_FANS))
53162306a36Sopenharmony_ci#define has_five_fans(data)	((data)->features & (FEAT_FIVE_FANS | \
53262306a36Sopenharmony_ci						     FEAT_SIX_FANS))
53362306a36Sopenharmony_ci#define has_six_fans(data)	((data)->features & FEAT_SIX_FANS)
53462306a36Sopenharmony_ci#define has_vid(data)		((data)->features & FEAT_VID)
53562306a36Sopenharmony_ci#define has_in7_internal(data)	((data)->features & FEAT_IN7_INTERNAL)
53662306a36Sopenharmony_ci#define has_avcc3(data)		((data)->features & FEAT_AVCC3)
53762306a36Sopenharmony_ci#define has_four_pwm(data)	((data)->features & (FEAT_FOUR_PWM | \
53862306a36Sopenharmony_ci						     FEAT_FIVE_PWM | \
53962306a36Sopenharmony_ci						     FEAT_SIX_PWM))
54062306a36Sopenharmony_ci#define has_five_pwm(data)	((data)->features & (FEAT_FIVE_PWM | \
54162306a36Sopenharmony_ci						     FEAT_SIX_PWM))
54262306a36Sopenharmony_ci#define has_six_pwm(data)	((data)->features & FEAT_SIX_PWM)
54362306a36Sopenharmony_ci#define has_pwm_freq2(data)	((data)->features & FEAT_PWM_FREQ2)
54462306a36Sopenharmony_ci#define has_four_temp(data)	((data)->features & FEAT_FOUR_TEMP)
54562306a36Sopenharmony_ci#define has_six_temp(data)	((data)->features & FEAT_SIX_TEMP)
54662306a36Sopenharmony_ci#define has_vin3_5v(data)	((data)->features & FEAT_VIN3_5V)
54762306a36Sopenharmony_ci#define has_conf_noexit(data)	((data)->features & FEAT_CONF_NOEXIT)
54862306a36Sopenharmony_ci#define has_scaling(data)	((data)->features & (FEAT_12MV_ADC | \
54962306a36Sopenharmony_ci						     FEAT_10_9MV_ADC))
55062306a36Sopenharmony_ci#define has_fanctl_onoff(data)	((data)->features & FEAT_FANCTL_ONOFF)
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_cistruct it87_sio_data {
55362306a36Sopenharmony_ci	int sioaddr;
55462306a36Sopenharmony_ci	enum chips type;
55562306a36Sopenharmony_ci	/* Values read from Super-I/O config space */
55662306a36Sopenharmony_ci	u8 revision;
55762306a36Sopenharmony_ci	u8 vid_value;
55862306a36Sopenharmony_ci	u8 beep_pin;
55962306a36Sopenharmony_ci	u8 internal;	/* Internal sensors can be labeled */
56062306a36Sopenharmony_ci	bool need_in7_reroute;
56162306a36Sopenharmony_ci	/* Features skipped based on config or DMI */
56262306a36Sopenharmony_ci	u16 skip_in;
56362306a36Sopenharmony_ci	u8 skip_vid;
56462306a36Sopenharmony_ci	u8 skip_fan;
56562306a36Sopenharmony_ci	u8 skip_pwm;
56662306a36Sopenharmony_ci	u8 skip_temp;
56762306a36Sopenharmony_ci	u8 smbus_bitmap;
56862306a36Sopenharmony_ci	u8 ec_special_config;
56962306a36Sopenharmony_ci};
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci/*
57262306a36Sopenharmony_ci * For each registered chip, we need to keep some data in memory.
57362306a36Sopenharmony_ci * The structure is dynamically allocated.
57462306a36Sopenharmony_ci */
57562306a36Sopenharmony_cistruct it87_data {
57662306a36Sopenharmony_ci	const struct attribute_group *groups[7];
57762306a36Sopenharmony_ci	int sioaddr;
57862306a36Sopenharmony_ci	enum chips type;
57962306a36Sopenharmony_ci	u32 features;
58062306a36Sopenharmony_ci	u8 peci_mask;
58162306a36Sopenharmony_ci	u8 old_peci_mask;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	u8 smbus_bitmap;	/* !=0 if SMBus needs to be disabled */
58462306a36Sopenharmony_ci	u8 ec_special_config;	/* EC special config register restore value */
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	unsigned short addr;
58762306a36Sopenharmony_ci	const char *name;
58862306a36Sopenharmony_ci	struct mutex update_lock;
58962306a36Sopenharmony_ci	bool valid;		/* true if following fields are valid */
59062306a36Sopenharmony_ci	unsigned long last_updated;	/* In jiffies */
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	u16 in_scaled;		/* Internal voltage sensors are scaled */
59362306a36Sopenharmony_ci	u16 in_internal;	/* Bitfield, internal sensors (for labels) */
59462306a36Sopenharmony_ci	u16 has_in;		/* Bitfield, voltage sensors enabled */
59562306a36Sopenharmony_ci	u8 in[NUM_VIN][3];		/* [nr][0]=in, [1]=min, [2]=max */
59662306a36Sopenharmony_ci	bool need_in7_reroute;
59762306a36Sopenharmony_ci	u8 has_fan;		/* Bitfield, fans enabled */
59862306a36Sopenharmony_ci	u16 fan[NUM_FAN][2];	/* Register values, [nr][0]=fan, [1]=min */
59962306a36Sopenharmony_ci	u8 has_temp;		/* Bitfield, temp sensors enabled */
60062306a36Sopenharmony_ci	s8 temp[NUM_TEMP][4];	/* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
60162306a36Sopenharmony_ci	u8 sensor;		/* Register value (IT87_REG_TEMP_ENABLE) */
60262306a36Sopenharmony_ci	u8 extra;		/* Register value (IT87_REG_TEMP_EXTRA) */
60362306a36Sopenharmony_ci	u8 fan_div[NUM_FAN_DIV];/* Register encoding, shifted right */
60462306a36Sopenharmony_ci	bool has_vid;		/* True if VID supported */
60562306a36Sopenharmony_ci	u8 vid;			/* Register encoding, combined */
60662306a36Sopenharmony_ci	u8 vrm;
60762306a36Sopenharmony_ci	u32 alarms;		/* Register encoding, combined */
60862306a36Sopenharmony_ci	bool has_beep;		/* true if beep supported */
60962306a36Sopenharmony_ci	u8 beeps;		/* Register encoding */
61062306a36Sopenharmony_ci	u8 fan_main_ctrl;	/* Register value */
61162306a36Sopenharmony_ci	u8 fan_ctl;		/* Register value */
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/*
61462306a36Sopenharmony_ci	 * The following 3 arrays correspond to the same registers up to
61562306a36Sopenharmony_ci	 * the IT8720F. The meaning of bits 6-0 depends on the value of bit
61662306a36Sopenharmony_ci	 * 7, and we want to preserve settings on mode changes, so we have
61762306a36Sopenharmony_ci	 * to track all values separately.
61862306a36Sopenharmony_ci	 * Starting with the IT8721F, the manual PWM duty cycles are stored
61962306a36Sopenharmony_ci	 * in separate registers (8-bit values), so the separate tracking
62062306a36Sopenharmony_ci	 * is no longer needed, but it is still done to keep the driver
62162306a36Sopenharmony_ci	 * simple.
62262306a36Sopenharmony_ci	 */
62362306a36Sopenharmony_ci	u8 has_pwm;		/* Bitfield, pwm control enabled */
62462306a36Sopenharmony_ci	u8 pwm_ctrl[NUM_PWM];	/* Register value */
62562306a36Sopenharmony_ci	u8 pwm_duty[NUM_PWM];	/* Manual PWM value set by user */
62662306a36Sopenharmony_ci	u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Automatic fan speed control registers */
62962306a36Sopenharmony_ci	u8 auto_pwm[NUM_AUTO_PWM][4];	/* [nr][3] is hard-coded */
63062306a36Sopenharmony_ci	s8 auto_temp[NUM_AUTO_PWM][5];	/* [nr][0] is point1_temp_hyst */
63162306a36Sopenharmony_ci};
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci/* Board specific settings from DMI matching */
63462306a36Sopenharmony_cistruct it87_dmi_data {
63562306a36Sopenharmony_ci	u8 skip_pwm;		/* pwm channels to skip for this board  */
63662306a36Sopenharmony_ci};
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci/* Global for results from DMI matching, if needed */
63962306a36Sopenharmony_cistatic struct it87_dmi_data *dmi_data;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic int adc_lsb(const struct it87_data *data, int nr)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	int lsb;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (has_12mv_adc(data))
64662306a36Sopenharmony_ci		lsb = 120;
64762306a36Sopenharmony_ci	else if (has_10_9mv_adc(data))
64862306a36Sopenharmony_ci		lsb = 109;
64962306a36Sopenharmony_ci	else
65062306a36Sopenharmony_ci		lsb = 160;
65162306a36Sopenharmony_ci	if (data->in_scaled & BIT(nr))
65262306a36Sopenharmony_ci		lsb <<= 1;
65362306a36Sopenharmony_ci	return lsb;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic u8 in_to_reg(const struct it87_data *data, int nr, long val)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr));
65962306a36Sopenharmony_ci	return clamp_val(val, 0, 255);
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic int in_from_reg(const struct it87_data *data, int nr, int val)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10);
66562306a36Sopenharmony_ci}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_cistatic inline u8 FAN_TO_REG(long rpm, int div)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	if (rpm == 0)
67062306a36Sopenharmony_ci		return 255;
67162306a36Sopenharmony_ci	rpm = clamp_val(rpm, 1, 1000000);
67262306a36Sopenharmony_ci	return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic inline u16 FAN16_TO_REG(long rpm)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	if (rpm == 0)
67862306a36Sopenharmony_ci		return 0xffff;
67962306a36Sopenharmony_ci	return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \
68362306a36Sopenharmony_ci				1350000 / ((val) * (div)))
68462306a36Sopenharmony_ci/* The divider is fixed to 2 in 16-bit mode */
68562306a36Sopenharmony_ci#define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \
68662306a36Sopenharmony_ci			     1350000 / ((val) * 2))
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \
68962306a36Sopenharmony_ci				    ((val) + 500) / 1000), -128, 127))
69062306a36Sopenharmony_ci#define TEMP_FROM_REG(val) ((val) * 1000)
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic u8 pwm_to_reg(const struct it87_data *data, long val)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	if (has_newer_autopwm(data))
69562306a36Sopenharmony_ci		return val;
69662306a36Sopenharmony_ci	else
69762306a36Sopenharmony_ci		return val >> 1;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int pwm_from_reg(const struct it87_data *data, u8 reg)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	if (has_newer_autopwm(data))
70362306a36Sopenharmony_ci		return reg;
70462306a36Sopenharmony_ci	else
70562306a36Sopenharmony_ci		return (reg & 0x7f) << 1;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int DIV_TO_REG(int val)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	int answer = 0;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	while (answer < 7 && (val >>= 1))
71362306a36Sopenharmony_ci		answer++;
71462306a36Sopenharmony_ci	return answer;
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci#define DIV_FROM_REG(val) BIT(val)
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/*
72062306a36Sopenharmony_ci * PWM base frequencies. The frequency has to be divided by either 128 or 256,
72162306a36Sopenharmony_ci * depending on the chip type, to calculate the actual PWM frequency.
72262306a36Sopenharmony_ci *
72362306a36Sopenharmony_ci * Some of the chip datasheets suggest a base frequency of 51 kHz instead
72462306a36Sopenharmony_ci * of 750 kHz for the slowest base frequency, resulting in a PWM frequency
72562306a36Sopenharmony_ci * of 200 Hz. Sometimes both PWM frequency select registers are affected,
72662306a36Sopenharmony_ci * sometimes just one. It is unknown if this is a datasheet error or real,
72762306a36Sopenharmony_ci * so this is ignored for now.
72862306a36Sopenharmony_ci */
72962306a36Sopenharmony_cistatic const unsigned int pwm_freq[8] = {
73062306a36Sopenharmony_ci	48000000,
73162306a36Sopenharmony_ci	24000000,
73262306a36Sopenharmony_ci	12000000,
73362306a36Sopenharmony_ci	8000000,
73462306a36Sopenharmony_ci	6000000,
73562306a36Sopenharmony_ci	3000000,
73662306a36Sopenharmony_ci	1500000,
73762306a36Sopenharmony_ci	750000,
73862306a36Sopenharmony_ci};
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic int smbus_disable(struct it87_data *data)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	int err;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	if (data->smbus_bitmap) {
74562306a36Sopenharmony_ci		err = superio_enter(data->sioaddr);
74662306a36Sopenharmony_ci		if (err)
74762306a36Sopenharmony_ci			return err;
74862306a36Sopenharmony_ci		superio_select(data->sioaddr, PME);
74962306a36Sopenharmony_ci		superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
75062306a36Sopenharmony_ci			     data->ec_special_config & ~data->smbus_bitmap);
75162306a36Sopenharmony_ci		superio_exit(data->sioaddr, has_conf_noexit(data));
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci	return 0;
75462306a36Sopenharmony_ci}
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_cistatic int smbus_enable(struct it87_data *data)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	int err;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (data->smbus_bitmap) {
76162306a36Sopenharmony_ci		err = superio_enter(data->sioaddr);
76262306a36Sopenharmony_ci		if (err)
76362306a36Sopenharmony_ci			return err;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		superio_select(data->sioaddr, PME);
76662306a36Sopenharmony_ci		superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
76762306a36Sopenharmony_ci			     data->ec_special_config);
76862306a36Sopenharmony_ci		superio_exit(data->sioaddr, has_conf_noexit(data));
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci	return 0;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/*
77462306a36Sopenharmony_ci * Must be called with data->update_lock held, except during initialization.
77562306a36Sopenharmony_ci * Must be called with SMBus accesses disabled.
77662306a36Sopenharmony_ci * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
77762306a36Sopenharmony_ci * would slow down the IT87 access and should not be necessary.
77862306a36Sopenharmony_ci */
77962306a36Sopenharmony_cistatic int it87_read_value(struct it87_data *data, u8 reg)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
78262306a36Sopenharmony_ci	return inb_p(data->addr + IT87_DATA_REG_OFFSET);
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci/*
78662306a36Sopenharmony_ci * Must be called with data->update_lock held, except during initialization.
78762306a36Sopenharmony_ci * Must be called with SMBus accesses disabled.
78862306a36Sopenharmony_ci * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
78962306a36Sopenharmony_ci * would slow down the IT87 access and should not be necessary.
79062306a36Sopenharmony_ci */
79162306a36Sopenharmony_cistatic void it87_write_value(struct it87_data *data, u8 reg, u8 value)
79262306a36Sopenharmony_ci{
79362306a36Sopenharmony_ci	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
79462306a36Sopenharmony_ci	outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
79562306a36Sopenharmony_ci}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_cistatic void it87_update_pwm_ctrl(struct it87_data *data, int nr)
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
80062306a36Sopenharmony_ci	if (has_newer_autopwm(data)) {
80162306a36Sopenharmony_ci		data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
80262306a36Sopenharmony_ci		data->pwm_duty[nr] = it87_read_value(data,
80362306a36Sopenharmony_ci						     IT87_REG_PWM_DUTY[nr]);
80462306a36Sopenharmony_ci	} else {
80562306a36Sopenharmony_ci		if (data->pwm_ctrl[nr] & 0x80)	/* Automatic mode */
80662306a36Sopenharmony_ci			data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
80762306a36Sopenharmony_ci		else				/* Manual mode */
80862306a36Sopenharmony_ci			data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	if (has_old_autopwm(data)) {
81262306a36Sopenharmony_ci		int i;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		for (i = 0; i < 5 ; i++)
81562306a36Sopenharmony_ci			data->auto_temp[nr][i] = it87_read_value(data,
81662306a36Sopenharmony_ci						IT87_REG_AUTO_TEMP(nr, i));
81762306a36Sopenharmony_ci		for (i = 0; i < 3 ; i++)
81862306a36Sopenharmony_ci			data->auto_pwm[nr][i] = it87_read_value(data,
81962306a36Sopenharmony_ci						IT87_REG_AUTO_PWM(nr, i));
82062306a36Sopenharmony_ci	} else if (has_newer_autopwm(data)) {
82162306a36Sopenharmony_ci		int i;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		/*
82462306a36Sopenharmony_ci		 * 0: temperature hysteresis (base + 5)
82562306a36Sopenharmony_ci		 * 1: fan off temperature (base + 0)
82662306a36Sopenharmony_ci		 * 2: fan start temperature (base + 1)
82762306a36Sopenharmony_ci		 * 3: fan max temperature (base + 2)
82862306a36Sopenharmony_ci		 */
82962306a36Sopenharmony_ci		data->auto_temp[nr][0] =
83062306a36Sopenharmony_ci			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 5));
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		for (i = 0; i < 3 ; i++)
83362306a36Sopenharmony_ci			data->auto_temp[nr][i + 1] =
83462306a36Sopenharmony_ci				it87_read_value(data,
83562306a36Sopenharmony_ci						IT87_REG_AUTO_TEMP(nr, i));
83662306a36Sopenharmony_ci		/*
83762306a36Sopenharmony_ci		 * 0: start pwm value (base + 3)
83862306a36Sopenharmony_ci		 * 1: pwm slope (base + 4, 1/8th pwm)
83962306a36Sopenharmony_ci		 */
84062306a36Sopenharmony_ci		data->auto_pwm[nr][0] =
84162306a36Sopenharmony_ci			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 3));
84262306a36Sopenharmony_ci		data->auto_pwm[nr][1] =
84362306a36Sopenharmony_ci			it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 4));
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cistatic int it87_lock(struct it87_data *data)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	int err;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
85262306a36Sopenharmony_ci	err = smbus_disable(data);
85362306a36Sopenharmony_ci	if (err)
85462306a36Sopenharmony_ci		mutex_unlock(&data->update_lock);
85562306a36Sopenharmony_ci	return err;
85662306a36Sopenharmony_ci}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_cistatic void it87_unlock(struct it87_data *data)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	smbus_enable(data);
86162306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic struct it87_data *it87_update_device(struct device *dev)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
86762306a36Sopenharmony_ci	struct it87_data *ret = data;
86862306a36Sopenharmony_ci	int err;
86962306a36Sopenharmony_ci	int i;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
87462306a36Sopenharmony_ci		       !data->valid) {
87562306a36Sopenharmony_ci		err = smbus_disable(data);
87662306a36Sopenharmony_ci		if (err) {
87762306a36Sopenharmony_ci			ret = ERR_PTR(err);
87862306a36Sopenharmony_ci			goto unlock;
87962306a36Sopenharmony_ci		}
88062306a36Sopenharmony_ci		if (update_vbat) {
88162306a36Sopenharmony_ci			/*
88262306a36Sopenharmony_ci			 * Cleared after each update, so reenable.  Value
88362306a36Sopenharmony_ci			 * returned by this read will be previous value
88462306a36Sopenharmony_ci			 */
88562306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_CONFIG,
88662306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_CONFIG) | 0x40);
88762306a36Sopenharmony_ci		}
88862306a36Sopenharmony_ci		for (i = 0; i < NUM_VIN; i++) {
88962306a36Sopenharmony_ci			if (!(data->has_in & BIT(i)))
89062306a36Sopenharmony_ci				continue;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci			data->in[i][0] =
89362306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_VIN[i]);
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci			/* VBAT and AVCC don't have limit registers */
89662306a36Sopenharmony_ci			if (i >= NUM_VIN_LIMIT)
89762306a36Sopenharmony_ci				continue;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci			data->in[i][1] =
90062306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_VIN_MIN(i));
90162306a36Sopenharmony_ci			data->in[i][2] =
90262306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_VIN_MAX(i));
90362306a36Sopenharmony_ci		}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		for (i = 0; i < NUM_FAN; i++) {
90662306a36Sopenharmony_ci			/* Skip disabled fans */
90762306a36Sopenharmony_ci			if (!(data->has_fan & BIT(i)))
90862306a36Sopenharmony_ci				continue;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci			data->fan[i][1] =
91162306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_FAN_MIN[i]);
91262306a36Sopenharmony_ci			data->fan[i][0] = it87_read_value(data,
91362306a36Sopenharmony_ci				       IT87_REG_FAN[i]);
91462306a36Sopenharmony_ci			/* Add high byte if in 16-bit mode */
91562306a36Sopenharmony_ci			if (has_16bit_fans(data)) {
91662306a36Sopenharmony_ci				data->fan[i][0] |= it87_read_value(data,
91762306a36Sopenharmony_ci						IT87_REG_FANX[i]) << 8;
91862306a36Sopenharmony_ci				data->fan[i][1] |= it87_read_value(data,
91962306a36Sopenharmony_ci						IT87_REG_FANX_MIN[i]) << 8;
92062306a36Sopenharmony_ci			}
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci		for (i = 0; i < NUM_TEMP; i++) {
92362306a36Sopenharmony_ci			if (!(data->has_temp & BIT(i)))
92462306a36Sopenharmony_ci				continue;
92562306a36Sopenharmony_ci			data->temp[i][0] =
92662306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_TEMP(i));
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci			if (has_temp_offset(data) && i < NUM_TEMP_OFFSET)
92962306a36Sopenharmony_ci				data->temp[i][3] =
93062306a36Sopenharmony_ci				  it87_read_value(data,
93162306a36Sopenharmony_ci						  IT87_REG_TEMP_OFFSET[i]);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci			if (i >= NUM_TEMP_LIMIT)
93462306a36Sopenharmony_ci				continue;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci			data->temp[i][1] =
93762306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_TEMP_LOW(i));
93862306a36Sopenharmony_ci			data->temp[i][2] =
93962306a36Sopenharmony_ci				it87_read_value(data, IT87_REG_TEMP_HIGH(i));
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		/* Newer chips don't have clock dividers */
94362306a36Sopenharmony_ci		if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
94462306a36Sopenharmony_ci			i = it87_read_value(data, IT87_REG_FAN_DIV);
94562306a36Sopenharmony_ci			data->fan_div[0] = i & 0x07;
94662306a36Sopenharmony_ci			data->fan_div[1] = (i >> 3) & 0x07;
94762306a36Sopenharmony_ci			data->fan_div[2] = (i & 0x40) ? 3 : 1;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		data->alarms =
95162306a36Sopenharmony_ci			it87_read_value(data, IT87_REG_ALARM1) |
95262306a36Sopenharmony_ci			(it87_read_value(data, IT87_REG_ALARM2) << 8) |
95362306a36Sopenharmony_ci			(it87_read_value(data, IT87_REG_ALARM3) << 16);
95462306a36Sopenharmony_ci		data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		data->fan_main_ctrl = it87_read_value(data,
95762306a36Sopenharmony_ci				IT87_REG_FAN_MAIN_CTRL);
95862306a36Sopenharmony_ci		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
95962306a36Sopenharmony_ci		for (i = 0; i < NUM_PWM; i++) {
96062306a36Sopenharmony_ci			if (!(data->has_pwm & BIT(i)))
96162306a36Sopenharmony_ci				continue;
96262306a36Sopenharmony_ci			it87_update_pwm_ctrl(data, i);
96362306a36Sopenharmony_ci		}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
96662306a36Sopenharmony_ci		data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
96762306a36Sopenharmony_ci		/*
96862306a36Sopenharmony_ci		 * The IT8705F does not have VID capability.
96962306a36Sopenharmony_ci		 * The IT8718F and later don't use IT87_REG_VID for the
97062306a36Sopenharmony_ci		 * same purpose.
97162306a36Sopenharmony_ci		 */
97262306a36Sopenharmony_ci		if (data->type == it8712 || data->type == it8716) {
97362306a36Sopenharmony_ci			data->vid = it87_read_value(data, IT87_REG_VID);
97462306a36Sopenharmony_ci			/*
97562306a36Sopenharmony_ci			 * The older IT8712F revisions had only 5 VID pins,
97662306a36Sopenharmony_ci			 * but we assume it is always safe to read 6 bits.
97762306a36Sopenharmony_ci			 */
97862306a36Sopenharmony_ci			data->vid &= 0x3f;
97962306a36Sopenharmony_ci		}
98062306a36Sopenharmony_ci		data->last_updated = jiffies;
98162306a36Sopenharmony_ci		data->valid = true;
98262306a36Sopenharmony_ci		smbus_enable(data);
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ciunlock:
98562306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
98662306a36Sopenharmony_ci	return ret;
98762306a36Sopenharmony_ci}
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_cistatic ssize_t show_in(struct device *dev, struct device_attribute *attr,
99062306a36Sopenharmony_ci		       char *buf)
99162306a36Sopenharmony_ci{
99262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
99362306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
99462306a36Sopenharmony_ci	int index = sattr->index;
99562306a36Sopenharmony_ci	int nr = sattr->nr;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (IS_ERR(data))
99862306a36Sopenharmony_ci		return PTR_ERR(data);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic ssize_t set_in(struct device *dev, struct device_attribute *attr,
100462306a36Sopenharmony_ci		      const char *buf, size_t count)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
100762306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
100862306a36Sopenharmony_ci	int index = sattr->index;
100962306a36Sopenharmony_ci	int nr = sattr->nr;
101062306a36Sopenharmony_ci	unsigned long val;
101162306a36Sopenharmony_ci	int err;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
101462306a36Sopenharmony_ci		return -EINVAL;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	err = it87_lock(data);
101762306a36Sopenharmony_ci	if (err)
101862306a36Sopenharmony_ci		return err;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	data->in[nr][index] = in_to_reg(data, nr, val);
102162306a36Sopenharmony_ci	it87_write_value(data,
102262306a36Sopenharmony_ci			 index == 1 ? IT87_REG_VIN_MIN(nr)
102362306a36Sopenharmony_ci				    : IT87_REG_VIN_MAX(nr),
102462306a36Sopenharmony_ci			 data->in[nr][index]);
102562306a36Sopenharmony_ci	it87_unlock(data);
102662306a36Sopenharmony_ci	return count;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
103062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
103162306a36Sopenharmony_ci			    0, 1);
103262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
103362306a36Sopenharmony_ci			    0, 2);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
103662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
103762306a36Sopenharmony_ci			    1, 1);
103862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
103962306a36Sopenharmony_ci			    1, 2);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
104262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
104362306a36Sopenharmony_ci			    2, 1);
104462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
104562306a36Sopenharmony_ci			    2, 2);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
104862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
104962306a36Sopenharmony_ci			    3, 1);
105062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
105162306a36Sopenharmony_ci			    3, 2);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
105462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
105562306a36Sopenharmony_ci			    4, 1);
105662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
105762306a36Sopenharmony_ci			    4, 2);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0);
106062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
106162306a36Sopenharmony_ci			    5, 1);
106262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
106362306a36Sopenharmony_ci			    5, 2);
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0);
106662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in,
106762306a36Sopenharmony_ci			    6, 1);
106862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in,
106962306a36Sopenharmony_ci			    6, 2);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0);
107262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in,
107362306a36Sopenharmony_ci			    7, 1);
107462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
107562306a36Sopenharmony_ci			    7, 2);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
107862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);
107962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 10, 0);
108062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in, NULL, 11, 0);
108162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in, NULL, 12, 0);
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci/* Up to 6 temperatures */
108462306a36Sopenharmony_cistatic ssize_t show_temp(struct device *dev, struct device_attribute *attr,
108562306a36Sopenharmony_ci			 char *buf)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
108862306a36Sopenharmony_ci	int nr = sattr->nr;
108962306a36Sopenharmony_ci	int index = sattr->index;
109062306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	if (IS_ERR(data))
109362306a36Sopenharmony_ci		return PTR_ERR(data);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_cistatic ssize_t set_temp(struct device *dev, struct device_attribute *attr,
109962306a36Sopenharmony_ci			const char *buf, size_t count)
110062306a36Sopenharmony_ci{
110162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
110262306a36Sopenharmony_ci	int nr = sattr->nr;
110362306a36Sopenharmony_ci	int index = sattr->index;
110462306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
110562306a36Sopenharmony_ci	long val;
110662306a36Sopenharmony_ci	u8 reg, regval;
110762306a36Sopenharmony_ci	int err;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0)
111062306a36Sopenharmony_ci		return -EINVAL;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	err = it87_lock(data);
111362306a36Sopenharmony_ci	if (err)
111462306a36Sopenharmony_ci		return err;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	switch (index) {
111762306a36Sopenharmony_ci	default:
111862306a36Sopenharmony_ci	case 1:
111962306a36Sopenharmony_ci		reg = IT87_REG_TEMP_LOW(nr);
112062306a36Sopenharmony_ci		break;
112162306a36Sopenharmony_ci	case 2:
112262306a36Sopenharmony_ci		reg = IT87_REG_TEMP_HIGH(nr);
112362306a36Sopenharmony_ci		break;
112462306a36Sopenharmony_ci	case 3:
112562306a36Sopenharmony_ci		regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
112662306a36Sopenharmony_ci		if (!(regval & 0x80)) {
112762306a36Sopenharmony_ci			regval |= 0x80;
112862306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
112962306a36Sopenharmony_ci		}
113062306a36Sopenharmony_ci		data->valid = false;
113162306a36Sopenharmony_ci		reg = IT87_REG_TEMP_OFFSET[nr];
113262306a36Sopenharmony_ci		break;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	data->temp[nr][index] = TEMP_TO_REG(val);
113662306a36Sopenharmony_ci	it87_write_value(data, reg, data->temp[nr][index]);
113762306a36Sopenharmony_ci	it87_unlock(data);
113862306a36Sopenharmony_ci	return count;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
114262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
114362306a36Sopenharmony_ci			    0, 1);
114462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
114562306a36Sopenharmony_ci			    0, 2);
114662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
114762306a36Sopenharmony_ci			    set_temp, 0, 3);
114862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
114962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
115062306a36Sopenharmony_ci			    1, 1);
115162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
115262306a36Sopenharmony_ci			    1, 2);
115362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
115462306a36Sopenharmony_ci			    set_temp, 1, 3);
115562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
115662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
115762306a36Sopenharmony_ci			    2, 1);
115862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
115962306a36Sopenharmony_ci			    2, 2);
116062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
116162306a36Sopenharmony_ci			    set_temp, 2, 3);
116262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
116362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
116462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic int get_temp_type(struct it87_data *data, int index)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	/*
116962306a36Sopenharmony_ci	 * 2 is deprecated;
117062306a36Sopenharmony_ci	 * 3 = thermal diode;
117162306a36Sopenharmony_ci	 * 4 = thermistor;
117262306a36Sopenharmony_ci	 * 5 = AMDTSI;
117362306a36Sopenharmony_ci	 * 6 = Intel PECI;
117462306a36Sopenharmony_ci	 * 0 = disabled
117562306a36Sopenharmony_ci	 */
117662306a36Sopenharmony_ci	u8 reg, extra;
117762306a36Sopenharmony_ci	int ttype, type = 0;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* Detect PECI vs. AMDTSI */
118062306a36Sopenharmony_ci	ttype = 6;
118162306a36Sopenharmony_ci	if ((has_temp_peci(data, index)) || data->type == it8721 ||
118262306a36Sopenharmony_ci	    data->type == it8720) {
118362306a36Sopenharmony_ci		extra = it87_read_value(data, IT87_REG_IFSEL);
118462306a36Sopenharmony_ci		if ((extra & 0x70) == 0x40)
118562306a36Sopenharmony_ci			ttype = 5;
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	/* Per chip special detection */
119162306a36Sopenharmony_ci	switch (data->type) {
119262306a36Sopenharmony_ci	case it8622:
119362306a36Sopenharmony_ci		if (!(reg & 0xc0) && index == 3)
119462306a36Sopenharmony_ci			type = ttype;
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci	default:
119762306a36Sopenharmony_ci		break;
119862306a36Sopenharmony_ci	}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	if (type || index >= 3)
120162306a36Sopenharmony_ci		return type;
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	if ((has_temp_peci(data, index) && (reg >> 6 == index + 1)) ||
120662306a36Sopenharmony_ci	    (has_temp_old_peci(data, index) && (extra & 0x80)))
120762306a36Sopenharmony_ci		type = ttype;	/* Intel PECI or AMDTSI */
120862306a36Sopenharmony_ci	else if (reg & BIT(index))
120962306a36Sopenharmony_ci		type = 3;	/* thermal diode */
121062306a36Sopenharmony_ci	else if (reg & BIT(index + 3))
121162306a36Sopenharmony_ci		type = 4;	/* thermistor */
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	return type;
121462306a36Sopenharmony_ci}
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_cistatic ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
121762306a36Sopenharmony_ci			      char *buf)
121862306a36Sopenharmony_ci{
121962306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
122062306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	if (IS_ERR(data))
122362306a36Sopenharmony_ci		return PTR_ERR(data);
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", get_temp_type(data, sensor_attr->index));
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
122962306a36Sopenharmony_ci			     const char *buf, size_t count)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
123262306a36Sopenharmony_ci	int nr = sensor_attr->index;
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
123562306a36Sopenharmony_ci	long val;
123662306a36Sopenharmony_ci	u8 reg, extra;
123762306a36Sopenharmony_ci	int err;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0)
124062306a36Sopenharmony_ci		return -EINVAL;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	err = it87_lock(data);
124362306a36Sopenharmony_ci	if (err)
124462306a36Sopenharmony_ci		return err;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
124762306a36Sopenharmony_ci	reg &= ~(1 << nr);
124862306a36Sopenharmony_ci	reg &= ~(8 << nr);
124962306a36Sopenharmony_ci	if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6))
125062306a36Sopenharmony_ci		reg &= 0x3f;
125162306a36Sopenharmony_ci	extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
125262306a36Sopenharmony_ci	if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6))
125362306a36Sopenharmony_ci		extra &= 0x7f;
125462306a36Sopenharmony_ci	if (val == 2) {	/* backwards compatibility */
125562306a36Sopenharmony_ci		dev_warn(dev,
125662306a36Sopenharmony_ci			 "Sensor type 2 is deprecated, please use 4 instead\n");
125762306a36Sopenharmony_ci		val = 4;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci	/* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */
126062306a36Sopenharmony_ci	if (val == 3)
126162306a36Sopenharmony_ci		reg |= 1 << nr;
126262306a36Sopenharmony_ci	else if (val == 4)
126362306a36Sopenharmony_ci		reg |= 8 << nr;
126462306a36Sopenharmony_ci	else if (has_temp_peci(data, nr) && val == 6)
126562306a36Sopenharmony_ci		reg |= (nr + 1) << 6;
126662306a36Sopenharmony_ci	else if (has_temp_old_peci(data, nr) && val == 6)
126762306a36Sopenharmony_ci		extra |= 0x80;
126862306a36Sopenharmony_ci	else if (val != 0) {
126962306a36Sopenharmony_ci		count = -EINVAL;
127062306a36Sopenharmony_ci		goto unlock;
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	data->sensor = reg;
127462306a36Sopenharmony_ci	data->extra = extra;
127562306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
127662306a36Sopenharmony_ci	if (has_temp_old_peci(data, nr))
127762306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
127862306a36Sopenharmony_ci	data->valid = false;	/* Force cache refresh */
127962306a36Sopenharmony_ciunlock:
128062306a36Sopenharmony_ci	it87_unlock(data);
128162306a36Sopenharmony_ci	return count;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
128562306a36Sopenharmony_ci			  set_temp_type, 0);
128662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
128762306a36Sopenharmony_ci			  set_temp_type, 1);
128862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
128962306a36Sopenharmony_ci			  set_temp_type, 2);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci/* 6 Fans */
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_cistatic int pwm_mode(const struct it87_data *data, int nr)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	if (has_fanctl_onoff(data) && nr < 3 &&
129662306a36Sopenharmony_ci	    !(data->fan_main_ctrl & BIT(nr)))
129762306a36Sopenharmony_ci		return 0;			/* Full speed */
129862306a36Sopenharmony_ci	if (data->pwm_ctrl[nr] & 0x80)
129962306a36Sopenharmony_ci		return 2;			/* Automatic mode */
130062306a36Sopenharmony_ci	if ((!has_fanctl_onoff(data) || nr >= 3) &&
130162306a36Sopenharmony_ci	    data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
130262306a36Sopenharmony_ci		return 0;			/* Full speed */
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	return 1;				/* Manual mode */
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic ssize_t show_fan(struct device *dev, struct device_attribute *attr,
130862306a36Sopenharmony_ci			char *buf)
130962306a36Sopenharmony_ci{
131062306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
131162306a36Sopenharmony_ci	int nr = sattr->nr;
131262306a36Sopenharmony_ci	int index = sattr->index;
131362306a36Sopenharmony_ci	int speed;
131462306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	if (IS_ERR(data))
131762306a36Sopenharmony_ci		return PTR_ERR(data);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	speed = has_16bit_fans(data) ?
132062306a36Sopenharmony_ci		FAN16_FROM_REG(data->fan[nr][index]) :
132162306a36Sopenharmony_ci		FAN_FROM_REG(data->fan[nr][index],
132262306a36Sopenharmony_ci			     DIV_FROM_REG(data->fan_div[nr]));
132362306a36Sopenharmony_ci	return sprintf(buf, "%d\n", speed);
132462306a36Sopenharmony_ci}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cistatic ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
132762306a36Sopenharmony_ci			    char *buf)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
133062306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
133162306a36Sopenharmony_ci	int nr = sensor_attr->index;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (IS_ERR(data))
133462306a36Sopenharmony_ci		return PTR_ERR(data);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_cistatic ssize_t show_pwm_enable(struct device *dev,
134062306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
134362306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
134462306a36Sopenharmony_ci	int nr = sensor_attr->index;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (IS_ERR(data))
134762306a36Sopenharmony_ci		return PTR_ERR(data);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	return sprintf(buf, "%d\n", pwm_mode(data, nr));
135062306a36Sopenharmony_ci}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_cistatic ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
135362306a36Sopenharmony_ci			char *buf)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
135662306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
135762306a36Sopenharmony_ci	int nr = sensor_attr->index;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	if (IS_ERR(data))
136062306a36Sopenharmony_ci		return PTR_ERR(data);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	return sprintf(buf, "%d\n",
136362306a36Sopenharmony_ci		       pwm_from_reg(data, data->pwm_duty[nr]));
136462306a36Sopenharmony_ci}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_cistatic ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
136762306a36Sopenharmony_ci			     char *buf)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
137062306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
137162306a36Sopenharmony_ci	int nr = sensor_attr->index;
137262306a36Sopenharmony_ci	unsigned int freq;
137362306a36Sopenharmony_ci	int index;
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	if (IS_ERR(data))
137662306a36Sopenharmony_ci		return PTR_ERR(data);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (has_pwm_freq2(data) && nr == 1)
137962306a36Sopenharmony_ci		index = (data->extra >> 4) & 0x07;
138062306a36Sopenharmony_ci	else
138162306a36Sopenharmony_ci		index = (data->fan_ctl >> 4) & 0x07;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	freq = pwm_freq[index] / (has_newer_autopwm(data) ? 256 : 128);
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	return sprintf(buf, "%u\n", freq);
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic ssize_t set_fan(struct device *dev, struct device_attribute *attr,
138962306a36Sopenharmony_ci		       const char *buf, size_t count)
139062306a36Sopenharmony_ci{
139162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
139262306a36Sopenharmony_ci	int nr = sattr->nr;
139362306a36Sopenharmony_ci	int index = sattr->index;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
139662306a36Sopenharmony_ci	long val;
139762306a36Sopenharmony_ci	int err;
139862306a36Sopenharmony_ci	u8 reg;
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0)
140162306a36Sopenharmony_ci		return -EINVAL;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	err = it87_lock(data);
140462306a36Sopenharmony_ci	if (err)
140562306a36Sopenharmony_ci		return err;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	if (has_16bit_fans(data)) {
140862306a36Sopenharmony_ci		data->fan[nr][index] = FAN16_TO_REG(val);
140962306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FAN_MIN[nr],
141062306a36Sopenharmony_ci				 data->fan[nr][index] & 0xff);
141162306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FANX_MIN[nr],
141262306a36Sopenharmony_ci				 data->fan[nr][index] >> 8);
141362306a36Sopenharmony_ci	} else {
141462306a36Sopenharmony_ci		reg = it87_read_value(data, IT87_REG_FAN_DIV);
141562306a36Sopenharmony_ci		switch (nr) {
141662306a36Sopenharmony_ci		case 0:
141762306a36Sopenharmony_ci			data->fan_div[nr] = reg & 0x07;
141862306a36Sopenharmony_ci			break;
141962306a36Sopenharmony_ci		case 1:
142062306a36Sopenharmony_ci			data->fan_div[nr] = (reg >> 3) & 0x07;
142162306a36Sopenharmony_ci			break;
142262306a36Sopenharmony_ci		case 2:
142362306a36Sopenharmony_ci			data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
142462306a36Sopenharmony_ci			break;
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci		data->fan[nr][index] =
142762306a36Sopenharmony_ci		  FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
142862306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FAN_MIN[nr],
142962306a36Sopenharmony_ci				 data->fan[nr][index]);
143062306a36Sopenharmony_ci	}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci	it87_unlock(data);
143362306a36Sopenharmony_ci	return count;
143462306a36Sopenharmony_ci}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
143762306a36Sopenharmony_ci			   const char *buf, size_t count)
143862306a36Sopenharmony_ci{
143962306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
144062306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
144162306a36Sopenharmony_ci	int nr = sensor_attr->index;
144262306a36Sopenharmony_ci	unsigned long val;
144362306a36Sopenharmony_ci	int min, err;
144462306a36Sopenharmony_ci	u8 old;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
144762306a36Sopenharmony_ci		return -EINVAL;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	err = it87_lock(data);
145062306a36Sopenharmony_ci	if (err)
145162306a36Sopenharmony_ci		return err;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	old = it87_read_value(data, IT87_REG_FAN_DIV);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	/* Save fan min limit */
145662306a36Sopenharmony_ci	min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr]));
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	switch (nr) {
145962306a36Sopenharmony_ci	case 0:
146062306a36Sopenharmony_ci	case 1:
146162306a36Sopenharmony_ci		data->fan_div[nr] = DIV_TO_REG(val);
146262306a36Sopenharmony_ci		break;
146362306a36Sopenharmony_ci	case 2:
146462306a36Sopenharmony_ci		if (val < 8)
146562306a36Sopenharmony_ci			data->fan_div[nr] = 1;
146662306a36Sopenharmony_ci		else
146762306a36Sopenharmony_ci			data->fan_div[nr] = 3;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci	val = old & 0x80;
147062306a36Sopenharmony_ci	val |= (data->fan_div[0] & 0x07);
147162306a36Sopenharmony_ci	val |= (data->fan_div[1] & 0x07) << 3;
147262306a36Sopenharmony_ci	if (data->fan_div[2] == 3)
147362306a36Sopenharmony_ci		val |= 0x1 << 6;
147462306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_FAN_DIV, val);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* Restore fan min limit */
147762306a36Sopenharmony_ci	data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
147862306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	it87_unlock(data);
148162306a36Sopenharmony_ci	return count;
148262306a36Sopenharmony_ci}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci/* Returns 0 if OK, -EINVAL otherwise */
148562306a36Sopenharmony_cistatic int check_trip_points(struct device *dev, int nr)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	const struct it87_data *data = dev_get_drvdata(dev);
148862306a36Sopenharmony_ci	int i, err = 0;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	if (has_old_autopwm(data)) {
149162306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
149262306a36Sopenharmony_ci			if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
149362306a36Sopenharmony_ci				err = -EINVAL;
149462306a36Sopenharmony_ci		}
149562306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
149662306a36Sopenharmony_ci			if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1])
149762306a36Sopenharmony_ci				err = -EINVAL;
149862306a36Sopenharmony_ci		}
149962306a36Sopenharmony_ci	} else if (has_newer_autopwm(data)) {
150062306a36Sopenharmony_ci		for (i = 1; i < 3; i++) {
150162306a36Sopenharmony_ci			if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1])
150262306a36Sopenharmony_ci				err = -EINVAL;
150362306a36Sopenharmony_ci		}
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	if (err) {
150762306a36Sopenharmony_ci		dev_err(dev,
150862306a36Sopenharmony_ci			"Inconsistent trip points, not switching to automatic mode\n");
150962306a36Sopenharmony_ci		dev_err(dev, "Adjust the trip points and try again\n");
151062306a36Sopenharmony_ci	}
151162306a36Sopenharmony_ci	return err;
151262306a36Sopenharmony_ci}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_cistatic ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
151562306a36Sopenharmony_ci			      const char *buf, size_t count)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
151862306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
151962306a36Sopenharmony_ci	int nr = sensor_attr->index;
152062306a36Sopenharmony_ci	long val;
152162306a36Sopenharmony_ci	int err;
152262306a36Sopenharmony_ci
152362306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
152462306a36Sopenharmony_ci		return -EINVAL;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* Check trip points before switching to automatic mode */
152762306a36Sopenharmony_ci	if (val == 2) {
152862306a36Sopenharmony_ci		if (check_trip_points(dev, nr) < 0)
152962306a36Sopenharmony_ci			return -EINVAL;
153062306a36Sopenharmony_ci	}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	err = it87_lock(data);
153362306a36Sopenharmony_ci	if (err)
153462306a36Sopenharmony_ci		return err;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	if (val == 0) {
153762306a36Sopenharmony_ci		if (nr < 3 && has_fanctl_onoff(data)) {
153862306a36Sopenharmony_ci			int tmp;
153962306a36Sopenharmony_ci			/* make sure the fan is on when in on/off mode */
154062306a36Sopenharmony_ci			tmp = it87_read_value(data, IT87_REG_FAN_CTL);
154162306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr));
154262306a36Sopenharmony_ci			/* set on/off mode */
154362306a36Sopenharmony_ci			data->fan_main_ctrl &= ~BIT(nr);
154462306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
154562306a36Sopenharmony_ci					 data->fan_main_ctrl);
154662306a36Sopenharmony_ci		} else {
154762306a36Sopenharmony_ci			u8 ctrl;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci			/* No on/off mode, set maximum pwm value */
155062306a36Sopenharmony_ci			data->pwm_duty[nr] = pwm_to_reg(data, 0xff);
155162306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_PWM_DUTY[nr],
155262306a36Sopenharmony_ci					 data->pwm_duty[nr]);
155362306a36Sopenharmony_ci			/* and set manual mode */
155462306a36Sopenharmony_ci			if (has_newer_autopwm(data)) {
155562306a36Sopenharmony_ci				ctrl = (data->pwm_ctrl[nr] & 0x7c) |
155662306a36Sopenharmony_ci					data->pwm_temp_map[nr];
155762306a36Sopenharmony_ci			} else {
155862306a36Sopenharmony_ci				ctrl = data->pwm_duty[nr];
155962306a36Sopenharmony_ci			}
156062306a36Sopenharmony_ci			data->pwm_ctrl[nr] = ctrl;
156162306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_PWM[nr], ctrl);
156262306a36Sopenharmony_ci		}
156362306a36Sopenharmony_ci	} else {
156462306a36Sopenharmony_ci		u8 ctrl;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci		if (has_newer_autopwm(data)) {
156762306a36Sopenharmony_ci			ctrl = (data->pwm_ctrl[nr] & 0x7c) |
156862306a36Sopenharmony_ci				data->pwm_temp_map[nr];
156962306a36Sopenharmony_ci			if (val != 1)
157062306a36Sopenharmony_ci				ctrl |= 0x80;
157162306a36Sopenharmony_ci		} else {
157262306a36Sopenharmony_ci			ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80);
157362306a36Sopenharmony_ci		}
157462306a36Sopenharmony_ci		data->pwm_ctrl[nr] = ctrl;
157562306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_PWM[nr], ctrl);
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci		if (has_fanctl_onoff(data) && nr < 3) {
157862306a36Sopenharmony_ci			/* set SmartGuardian mode */
157962306a36Sopenharmony_ci			data->fan_main_ctrl |= BIT(nr);
158062306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
158162306a36Sopenharmony_ci					 data->fan_main_ctrl);
158262306a36Sopenharmony_ci		}
158362306a36Sopenharmony_ci	}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	it87_unlock(data);
158662306a36Sopenharmony_ci	return count;
158762306a36Sopenharmony_ci}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_cistatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
159062306a36Sopenharmony_ci		       const char *buf, size_t count)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
159362306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
159462306a36Sopenharmony_ci	int nr = sensor_attr->index;
159562306a36Sopenharmony_ci	long val;
159662306a36Sopenharmony_ci	int err;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
159962306a36Sopenharmony_ci		return -EINVAL;
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	err = it87_lock(data);
160262306a36Sopenharmony_ci	if (err)
160362306a36Sopenharmony_ci		return err;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	it87_update_pwm_ctrl(data, nr);
160662306a36Sopenharmony_ci	if (has_newer_autopwm(data)) {
160762306a36Sopenharmony_ci		/*
160862306a36Sopenharmony_ci		 * If we are in automatic mode, the PWM duty cycle register
160962306a36Sopenharmony_ci		 * is read-only so we can't write the value.
161062306a36Sopenharmony_ci		 */
161162306a36Sopenharmony_ci		if (data->pwm_ctrl[nr] & 0x80) {
161262306a36Sopenharmony_ci			count = -EBUSY;
161362306a36Sopenharmony_ci			goto unlock;
161462306a36Sopenharmony_ci		}
161562306a36Sopenharmony_ci		data->pwm_duty[nr] = pwm_to_reg(data, val);
161662306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_PWM_DUTY[nr],
161762306a36Sopenharmony_ci				 data->pwm_duty[nr]);
161862306a36Sopenharmony_ci	} else {
161962306a36Sopenharmony_ci		data->pwm_duty[nr] = pwm_to_reg(data, val);
162062306a36Sopenharmony_ci		/*
162162306a36Sopenharmony_ci		 * If we are in manual mode, write the duty cycle immediately;
162262306a36Sopenharmony_ci		 * otherwise, just store it for later use.
162362306a36Sopenharmony_ci		 */
162462306a36Sopenharmony_ci		if (!(data->pwm_ctrl[nr] & 0x80)) {
162562306a36Sopenharmony_ci			data->pwm_ctrl[nr] = data->pwm_duty[nr];
162662306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_PWM[nr],
162762306a36Sopenharmony_ci					 data->pwm_ctrl[nr]);
162862306a36Sopenharmony_ci		}
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ciunlock:
163162306a36Sopenharmony_ci	it87_unlock(data);
163262306a36Sopenharmony_ci	return count;
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_cistatic ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
163662306a36Sopenharmony_ci			    const char *buf, size_t count)
163762306a36Sopenharmony_ci{
163862306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
163962306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
164062306a36Sopenharmony_ci	int nr = sensor_attr->index;
164162306a36Sopenharmony_ci	unsigned long val;
164262306a36Sopenharmony_ci	int err;
164362306a36Sopenharmony_ci	int i;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
164662306a36Sopenharmony_ci		return -EINVAL;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	val = clamp_val(val, 0, 1000000);
164962306a36Sopenharmony_ci	val *= has_newer_autopwm(data) ? 256 : 128;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	/* Search for the nearest available frequency */
165262306a36Sopenharmony_ci	for (i = 0; i < 7; i++) {
165362306a36Sopenharmony_ci		if (val > (pwm_freq[i] + pwm_freq[i + 1]) / 2)
165462306a36Sopenharmony_ci			break;
165562306a36Sopenharmony_ci	}
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	err = it87_lock(data);
165862306a36Sopenharmony_ci	if (err)
165962306a36Sopenharmony_ci		return err;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	if (nr == 0) {
166262306a36Sopenharmony_ci		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
166362306a36Sopenharmony_ci		data->fan_ctl |= i << 4;
166462306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
166562306a36Sopenharmony_ci	} else {
166662306a36Sopenharmony_ci		data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x8f;
166762306a36Sopenharmony_ci		data->extra |= i << 4;
166862306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
166962306a36Sopenharmony_ci	}
167062306a36Sopenharmony_ci	it87_unlock(data);
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	return count;
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic ssize_t show_pwm_temp_map(struct device *dev,
167662306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
167962306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
168062306a36Sopenharmony_ci	int nr = sensor_attr->index;
168162306a36Sopenharmony_ci	int map;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	if (IS_ERR(data))
168462306a36Sopenharmony_ci		return PTR_ERR(data);
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	map = data->pwm_temp_map[nr];
168762306a36Sopenharmony_ci	if (map >= 3)
168862306a36Sopenharmony_ci		map = 0;	/* Should never happen */
168962306a36Sopenharmony_ci	if (nr >= 3)		/* pwm channels 3..6 map to temp4..6 */
169062306a36Sopenharmony_ci		map += 3;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	return sprintf(buf, "%d\n", (int)BIT(map));
169362306a36Sopenharmony_ci}
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_cistatic ssize_t set_pwm_temp_map(struct device *dev,
169662306a36Sopenharmony_ci				struct device_attribute *attr, const char *buf,
169762306a36Sopenharmony_ci				size_t count)
169862306a36Sopenharmony_ci{
169962306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
170062306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
170162306a36Sopenharmony_ci	int nr = sensor_attr->index;
170262306a36Sopenharmony_ci	long val;
170362306a36Sopenharmony_ci	int err;
170462306a36Sopenharmony_ci	u8 reg;
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0)
170762306a36Sopenharmony_ci		return -EINVAL;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	if (nr >= 3)
171062306a36Sopenharmony_ci		val -= 3;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	switch (val) {
171362306a36Sopenharmony_ci	case BIT(0):
171462306a36Sopenharmony_ci		reg = 0x00;
171562306a36Sopenharmony_ci		break;
171662306a36Sopenharmony_ci	case BIT(1):
171762306a36Sopenharmony_ci		reg = 0x01;
171862306a36Sopenharmony_ci		break;
171962306a36Sopenharmony_ci	case BIT(2):
172062306a36Sopenharmony_ci		reg = 0x02;
172162306a36Sopenharmony_ci		break;
172262306a36Sopenharmony_ci	default:
172362306a36Sopenharmony_ci		return -EINVAL;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	err = it87_lock(data);
172762306a36Sopenharmony_ci	if (err)
172862306a36Sopenharmony_ci		return err;
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	it87_update_pwm_ctrl(data, nr);
173162306a36Sopenharmony_ci	data->pwm_temp_map[nr] = reg;
173262306a36Sopenharmony_ci	/*
173362306a36Sopenharmony_ci	 * If we are in automatic mode, write the temp mapping immediately;
173462306a36Sopenharmony_ci	 * otherwise, just store it for later use.
173562306a36Sopenharmony_ci	 */
173662306a36Sopenharmony_ci	if (data->pwm_ctrl[nr] & 0x80) {
173762306a36Sopenharmony_ci		data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) |
173862306a36Sopenharmony_ci						data->pwm_temp_map[nr];
173962306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
174062306a36Sopenharmony_ci	}
174162306a36Sopenharmony_ci	it87_unlock(data);
174262306a36Sopenharmony_ci	return count;
174362306a36Sopenharmony_ci}
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_cistatic ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
174662306a36Sopenharmony_ci			     char *buf)
174762306a36Sopenharmony_ci{
174862306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
174962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
175062306a36Sopenharmony_ci			to_sensor_dev_attr_2(attr);
175162306a36Sopenharmony_ci	int nr = sensor_attr->nr;
175262306a36Sopenharmony_ci	int point = sensor_attr->index;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	if (IS_ERR(data))
175562306a36Sopenharmony_ci		return PTR_ERR(data);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	return sprintf(buf, "%d\n",
175862306a36Sopenharmony_ci		       pwm_from_reg(data, data->auto_pwm[nr][point]));
175962306a36Sopenharmony_ci}
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_cistatic ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
176262306a36Sopenharmony_ci			    const char *buf, size_t count)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
176562306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
176662306a36Sopenharmony_ci			to_sensor_dev_attr_2(attr);
176762306a36Sopenharmony_ci	int nr = sensor_attr->nr;
176862306a36Sopenharmony_ci	int point = sensor_attr->index;
176962306a36Sopenharmony_ci	int regaddr;
177062306a36Sopenharmony_ci	long val;
177162306a36Sopenharmony_ci	int err;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
177462306a36Sopenharmony_ci		return -EINVAL;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	err = it87_lock(data);
177762306a36Sopenharmony_ci	if (err)
177862306a36Sopenharmony_ci		return err;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
178162306a36Sopenharmony_ci	if (has_newer_autopwm(data))
178262306a36Sopenharmony_ci		regaddr = IT87_REG_AUTO_TEMP(nr, 3);
178362306a36Sopenharmony_ci	else
178462306a36Sopenharmony_ci		regaddr = IT87_REG_AUTO_PWM(nr, point);
178562306a36Sopenharmony_ci	it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
178662306a36Sopenharmony_ci	it87_unlock(data);
178762306a36Sopenharmony_ci	return count;
178862306a36Sopenharmony_ci}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_cistatic ssize_t show_auto_pwm_slope(struct device *dev,
179162306a36Sopenharmony_ci				   struct device_attribute *attr, char *buf)
179262306a36Sopenharmony_ci{
179362306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
179462306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
179562306a36Sopenharmony_ci	int nr = sensor_attr->index;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	if (IS_ERR(data))
179862306a36Sopenharmony_ci		return PTR_ERR(data);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f);
180162306a36Sopenharmony_ci}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_cistatic ssize_t set_auto_pwm_slope(struct device *dev,
180462306a36Sopenharmony_ci				  struct device_attribute *attr,
180562306a36Sopenharmony_ci				  const char *buf, size_t count)
180662306a36Sopenharmony_ci{
180762306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
180862306a36Sopenharmony_ci	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
180962306a36Sopenharmony_ci	int nr = sensor_attr->index;
181062306a36Sopenharmony_ci	unsigned long val;
181162306a36Sopenharmony_ci	int err;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0 || val > 127)
181462306a36Sopenharmony_ci		return -EINVAL;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	err = it87_lock(data);
181762306a36Sopenharmony_ci	if (err)
181862306a36Sopenharmony_ci		return err;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
182162306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
182262306a36Sopenharmony_ci			 data->auto_pwm[nr][1]);
182362306a36Sopenharmony_ci	it87_unlock(data);
182462306a36Sopenharmony_ci	return count;
182562306a36Sopenharmony_ci}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_cistatic ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
182862306a36Sopenharmony_ci			      char *buf)
182962306a36Sopenharmony_ci{
183062306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
183162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
183262306a36Sopenharmony_ci			to_sensor_dev_attr_2(attr);
183362306a36Sopenharmony_ci	int nr = sensor_attr->nr;
183462306a36Sopenharmony_ci	int point = sensor_attr->index;
183562306a36Sopenharmony_ci	int reg;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci	if (IS_ERR(data))
183862306a36Sopenharmony_ci		return PTR_ERR(data);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (has_old_autopwm(data) || point)
184162306a36Sopenharmony_ci		reg = data->auto_temp[nr][point];
184262306a36Sopenharmony_ci	else
184362306a36Sopenharmony_ci		reg = data->auto_temp[nr][1] - (data->auto_temp[nr][0] & 0x1f);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(reg));
184662306a36Sopenharmony_ci}
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_cistatic ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
184962306a36Sopenharmony_ci			     const char *buf, size_t count)
185062306a36Sopenharmony_ci{
185162306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
185262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
185362306a36Sopenharmony_ci			to_sensor_dev_attr_2(attr);
185462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
185562306a36Sopenharmony_ci	int point = sensor_attr->index;
185662306a36Sopenharmony_ci	long val;
185762306a36Sopenharmony_ci	int reg;
185862306a36Sopenharmony_ci	int err;
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
186162306a36Sopenharmony_ci		return -EINVAL;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	err = it87_lock(data);
186462306a36Sopenharmony_ci	if (err)
186562306a36Sopenharmony_ci		return err;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (has_newer_autopwm(data) && !point) {
186862306a36Sopenharmony_ci		reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
186962306a36Sopenharmony_ci		reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
187062306a36Sopenharmony_ci		data->auto_temp[nr][0] = reg;
187162306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 5), reg);
187262306a36Sopenharmony_ci	} else {
187362306a36Sopenharmony_ci		reg = TEMP_TO_REG(val);
187462306a36Sopenharmony_ci		data->auto_temp[nr][point] = reg;
187562306a36Sopenharmony_ci		if (has_newer_autopwm(data))
187662306a36Sopenharmony_ci			point--;
187762306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci	it87_unlock(data);
188062306a36Sopenharmony_ci	return count;
188162306a36Sopenharmony_ci}
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0);
188462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
188562306a36Sopenharmony_ci			    0, 1);
188662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div,
188762306a36Sopenharmony_ci			  set_fan_div, 0);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0);
189062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
189162306a36Sopenharmony_ci			    1, 1);
189262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div,
189362306a36Sopenharmony_ci			  set_fan_div, 1);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0);
189662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
189762306a36Sopenharmony_ci			    2, 1);
189862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div,
189962306a36Sopenharmony_ci			  set_fan_div, 2);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0);
190262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
190362306a36Sopenharmony_ci			    3, 1);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0);
190662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
190762306a36Sopenharmony_ci			    4, 1);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan6_input, S_IRUGO, show_fan, NULL, 5, 0);
191062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
191162306a36Sopenharmony_ci			    5, 1);
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
191462306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 0);
191562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
191662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq,
191762306a36Sopenharmony_ci			  set_pwm_freq, 0);
191862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO,
191962306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 0);
192062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
192162306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 0, 0);
192262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
192362306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 0, 1);
192462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
192562306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 0, 2);
192662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO,
192762306a36Sopenharmony_ci			    show_auto_pwm, NULL, 0, 3);
192862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
192962306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 0, 1);
193062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
193162306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 0, 0);
193262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
193362306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 0, 2);
193462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
193562306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 0, 3);
193662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
193762306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 0, 4);
193862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_start, S_IRUGO | S_IWUSR,
193962306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 0, 0);
194062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_auto_slope, S_IRUGO | S_IWUSR,
194162306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 0);
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
194462306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 1);
194562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
194662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1);
194762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO,
194862306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 1);
194962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
195062306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 1, 0);
195162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
195262306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 1, 1);
195362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
195462306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 1, 2);
195562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO,
195662306a36Sopenharmony_ci			    show_auto_pwm, NULL, 1, 3);
195762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
195862306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 1, 1);
195962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
196062306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 1, 0);
196162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
196262306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 1, 2);
196362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
196462306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 1, 3);
196562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
196662306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 1, 4);
196762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_start, S_IRUGO | S_IWUSR,
196862306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 1, 0);
196962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_auto_slope, S_IRUGO | S_IWUSR,
197062306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 1);
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
197362306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 2);
197462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
197562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2);
197662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO,
197762306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 2);
197862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
197962306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 2, 0);
198062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
198162306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 2, 1);
198262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
198362306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 2, 2);
198462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO,
198562306a36Sopenharmony_ci			    show_auto_pwm, NULL, 2, 3);
198662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
198762306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 1);
198862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
198962306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 0);
199062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
199162306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 2);
199262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
199362306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 3);
199462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
199562306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 4);
199662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_start, S_IRUGO | S_IWUSR,
199762306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 2, 0);
199862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_auto_slope, S_IRUGO | S_IWUSR,
199962306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 2);
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR,
200262306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 3);
200362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3);
200462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3);
200562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO,
200662306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 3);
200762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp, S_IRUGO | S_IWUSR,
200862306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 1);
200962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
201062306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 0);
201162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point2_temp, S_IRUGO | S_IWUSR,
201262306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 2);
201362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point3_temp, S_IRUGO | S_IWUSR,
201462306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 3);
201562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_start, S_IRUGO | S_IWUSR,
201662306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 3, 0);
201762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_auto_slope, S_IRUGO | S_IWUSR,
201862306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 3);
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR,
202162306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 4);
202262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4);
202362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4);
202462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO,
202562306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 4);
202662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp, S_IRUGO | S_IWUSR,
202762306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 1);
202862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
202962306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 0);
203062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point2_temp, S_IRUGO | S_IWUSR,
203162306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 2);
203262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point3_temp, S_IRUGO | S_IWUSR,
203362306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 3);
203462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_start, S_IRUGO | S_IWUSR,
203562306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 4, 0);
203662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_auto_slope, S_IRUGO | S_IWUSR,
203762306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 4);
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR,
204062306a36Sopenharmony_ci			  show_pwm_enable, set_pwm_enable, 5);
204162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5);
204262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5);
204362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO,
204462306a36Sopenharmony_ci			  show_pwm_temp_map, set_pwm_temp_map, 5);
204562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp, S_IRUGO | S_IWUSR,
204662306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 1);
204762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
204862306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 0);
204962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point2_temp, S_IRUGO | S_IWUSR,
205062306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 2);
205162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point3_temp, S_IRUGO | S_IWUSR,
205262306a36Sopenharmony_ci			    show_auto_temp, set_auto_temp, 2, 3);
205362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_start, S_IRUGO | S_IWUSR,
205462306a36Sopenharmony_ci			    show_auto_pwm, set_auto_pwm, 5, 0);
205562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_auto_slope, S_IRUGO | S_IWUSR,
205662306a36Sopenharmony_ci			  show_auto_pwm_slope, set_auto_pwm_slope, 5);
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci/* Alarms */
205962306a36Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
206062306a36Sopenharmony_ci			   char *buf)
206162306a36Sopenharmony_ci{
206262306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	if (IS_ERR(data))
206562306a36Sopenharmony_ci		return PTR_ERR(data);
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	return sprintf(buf, "%u\n", data->alarms);
206862306a36Sopenharmony_ci}
206962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(alarms);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_cistatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
207262306a36Sopenharmony_ci			  char *buf)
207362306a36Sopenharmony_ci{
207462306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
207562306a36Sopenharmony_ci	int bitnr = to_sensor_dev_attr(attr)->index;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	if (IS_ERR(data))
207862306a36Sopenharmony_ci		return PTR_ERR(data);
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic ssize_t clear_intrusion(struct device *dev,
208462306a36Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
208562306a36Sopenharmony_ci			       size_t count)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
208862306a36Sopenharmony_ci	int err, config;
208962306a36Sopenharmony_ci	long val;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || val != 0)
209262306a36Sopenharmony_ci		return -EINVAL;
209362306a36Sopenharmony_ci
209462306a36Sopenharmony_ci	err = it87_lock(data);
209562306a36Sopenharmony_ci	if (err)
209662306a36Sopenharmony_ci		return err;
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	config = it87_read_value(data, IT87_REG_CONFIG);
209962306a36Sopenharmony_ci	if (config < 0) {
210062306a36Sopenharmony_ci		count = config;
210162306a36Sopenharmony_ci	} else {
210262306a36Sopenharmony_ci		config |= BIT(5);
210362306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_CONFIG, config);
210462306a36Sopenharmony_ci		/* Invalidate cache to force re-read */
210562306a36Sopenharmony_ci		data->valid = false;
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci	it87_unlock(data);
210862306a36Sopenharmony_ci	return count;
210962306a36Sopenharmony_ci}
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8);
211262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9);
211362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10);
211462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11);
211562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12);
211662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13);
211762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14);
211862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15);
211962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0);
212062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1);
212162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2);
212262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3);
212362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6);
212462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 7);
212562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
212662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
212762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
212862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
212962306a36Sopenharmony_ci			  show_alarm, clear_intrusion, 4);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic ssize_t show_beep(struct device *dev, struct device_attribute *attr,
213262306a36Sopenharmony_ci			 char *buf)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
213562306a36Sopenharmony_ci	int bitnr = to_sensor_dev_attr(attr)->index;
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	if (IS_ERR(data))
213862306a36Sopenharmony_ci		return PTR_ERR(data);
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
214162306a36Sopenharmony_ci}
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_cistatic ssize_t set_beep(struct device *dev, struct device_attribute *attr,
214462306a36Sopenharmony_ci			const char *buf, size_t count)
214562306a36Sopenharmony_ci{
214662306a36Sopenharmony_ci	int bitnr = to_sensor_dev_attr(attr)->index;
214762306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
214862306a36Sopenharmony_ci	long val;
214962306a36Sopenharmony_ci	int err;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
215262306a36Sopenharmony_ci		return -EINVAL;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	err = it87_lock(data);
215562306a36Sopenharmony_ci	if (err)
215662306a36Sopenharmony_ci		return err;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
215962306a36Sopenharmony_ci	if (val)
216062306a36Sopenharmony_ci		data->beeps |= BIT(bitnr);
216162306a36Sopenharmony_ci	else
216262306a36Sopenharmony_ci		data->beeps &= ~BIT(bitnr);
216362306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
216462306a36Sopenharmony_ci	it87_unlock(data);
216562306a36Sopenharmony_ci	return count;
216662306a36Sopenharmony_ci}
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR,
216962306a36Sopenharmony_ci			  show_beep, set_beep, 1);
217062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO, show_beep, NULL, 1);
217162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO, show_beep, NULL, 1);
217262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO, show_beep, NULL, 1);
217362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO, show_beep, NULL, 1);
217462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO, show_beep, NULL, 1);
217562306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO, show_beep, NULL, 1);
217662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO, show_beep, NULL, 1);
217762306a36Sopenharmony_ci/* fanX_beep writability is set later */
217862306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO, show_beep, set_beep, 0);
217962306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO, show_beep, set_beep, 0);
218062306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO, show_beep, set_beep, 0);
218162306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan4_beep, S_IRUGO, show_beep, set_beep, 0);
218262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan5_beep, S_IRUGO, show_beep, set_beep, 0);
218362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan6_beep, S_IRUGO, show_beep, set_beep, 0);
218462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
218562306a36Sopenharmony_ci			  show_beep, set_beep, 2);
218662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
218762306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_cistatic ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
219062306a36Sopenharmony_ci			char *buf)
219162306a36Sopenharmony_ci{
219262306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	return sprintf(buf, "%u\n", data->vrm);
219562306a36Sopenharmony_ci}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_cistatic ssize_t vrm_store(struct device *dev, struct device_attribute *attr,
219862306a36Sopenharmony_ci			 const char *buf, size_t count)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
220162306a36Sopenharmony_ci	unsigned long val;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
220462306a36Sopenharmony_ci		return -EINVAL;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	data->vrm = val;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	return count;
220962306a36Sopenharmony_ci}
221062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(vrm);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_cistatic ssize_t cpu0_vid_show(struct device *dev,
221362306a36Sopenharmony_ci			     struct device_attribute *attr, char *buf)
221462306a36Sopenharmony_ci{
221562306a36Sopenharmony_ci	struct it87_data *data = it87_update_device(dev);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci	if (IS_ERR(data))
221862306a36Sopenharmony_ci		return PTR_ERR(data);
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm));
222162306a36Sopenharmony_ci}
222262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(cpu0_vid);
222362306a36Sopenharmony_ci
222462306a36Sopenharmony_cistatic ssize_t show_label(struct device *dev, struct device_attribute *attr,
222562306a36Sopenharmony_ci			  char *buf)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	static const char * const labels[] = {
222862306a36Sopenharmony_ci		"+5V",
222962306a36Sopenharmony_ci		"5VSB",
223062306a36Sopenharmony_ci		"Vbat",
223162306a36Sopenharmony_ci		"AVCC",
223262306a36Sopenharmony_ci	};
223362306a36Sopenharmony_ci	static const char * const labels_it8721[] = {
223462306a36Sopenharmony_ci		"+3.3V",
223562306a36Sopenharmony_ci		"3VSB",
223662306a36Sopenharmony_ci		"Vbat",
223762306a36Sopenharmony_ci		"+3.3V",
223862306a36Sopenharmony_ci	};
223962306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
224062306a36Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
224162306a36Sopenharmony_ci	const char *label;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	if (has_vin3_5v(data) && nr == 0)
224462306a36Sopenharmony_ci		label = labels[0];
224562306a36Sopenharmony_ci	else if (has_scaling(data))
224662306a36Sopenharmony_ci		label = labels_it8721[nr];
224762306a36Sopenharmony_ci	else
224862306a36Sopenharmony_ci		label = labels[nr];
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	return sprintf(buf, "%s\n", label);
225162306a36Sopenharmony_ci}
225262306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
225362306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
225462306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
225562306a36Sopenharmony_ci/* AVCC3 */
225662306a36Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3);
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_cistatic umode_t it87_in_is_visible(struct kobject *kobj,
225962306a36Sopenharmony_ci				  struct attribute *attr, int index)
226062306a36Sopenharmony_ci{
226162306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
226262306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
226362306a36Sopenharmony_ci	int i = index / 5;	/* voltage index */
226462306a36Sopenharmony_ci	int a = index % 5;	/* attribute index */
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci	if (index >= 40) {	/* in8 and higher only have input attributes */
226762306a36Sopenharmony_ci		i = index - 40 + 8;
226862306a36Sopenharmony_ci		a = 0;
226962306a36Sopenharmony_ci	}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	if (!(data->has_in & BIT(i)))
227262306a36Sopenharmony_ci		return 0;
227362306a36Sopenharmony_ci
227462306a36Sopenharmony_ci	if (a == 4 && !data->has_beep)
227562306a36Sopenharmony_ci		return 0;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	return attr->mode;
227862306a36Sopenharmony_ci}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic struct attribute *it87_attributes_in[] = {
228162306a36Sopenharmony_ci	&sensor_dev_attr_in0_input.dev_attr.attr,
228262306a36Sopenharmony_ci	&sensor_dev_attr_in0_min.dev_attr.attr,
228362306a36Sopenharmony_ci	&sensor_dev_attr_in0_max.dev_attr.attr,
228462306a36Sopenharmony_ci	&sensor_dev_attr_in0_alarm.dev_attr.attr,
228562306a36Sopenharmony_ci	&sensor_dev_attr_in0_beep.dev_attr.attr,	/* 4 */
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	&sensor_dev_attr_in1_input.dev_attr.attr,
228862306a36Sopenharmony_ci	&sensor_dev_attr_in1_min.dev_attr.attr,
228962306a36Sopenharmony_ci	&sensor_dev_attr_in1_max.dev_attr.attr,
229062306a36Sopenharmony_ci	&sensor_dev_attr_in1_alarm.dev_attr.attr,
229162306a36Sopenharmony_ci	&sensor_dev_attr_in1_beep.dev_attr.attr,	/* 9 */
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	&sensor_dev_attr_in2_input.dev_attr.attr,
229462306a36Sopenharmony_ci	&sensor_dev_attr_in2_min.dev_attr.attr,
229562306a36Sopenharmony_ci	&sensor_dev_attr_in2_max.dev_attr.attr,
229662306a36Sopenharmony_ci	&sensor_dev_attr_in2_alarm.dev_attr.attr,
229762306a36Sopenharmony_ci	&sensor_dev_attr_in2_beep.dev_attr.attr,	/* 14 */
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	&sensor_dev_attr_in3_input.dev_attr.attr,
230062306a36Sopenharmony_ci	&sensor_dev_attr_in3_min.dev_attr.attr,
230162306a36Sopenharmony_ci	&sensor_dev_attr_in3_max.dev_attr.attr,
230262306a36Sopenharmony_ci	&sensor_dev_attr_in3_alarm.dev_attr.attr,
230362306a36Sopenharmony_ci	&sensor_dev_attr_in3_beep.dev_attr.attr,	/* 19 */
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci	&sensor_dev_attr_in4_input.dev_attr.attr,
230662306a36Sopenharmony_ci	&sensor_dev_attr_in4_min.dev_attr.attr,
230762306a36Sopenharmony_ci	&sensor_dev_attr_in4_max.dev_attr.attr,
230862306a36Sopenharmony_ci	&sensor_dev_attr_in4_alarm.dev_attr.attr,
230962306a36Sopenharmony_ci	&sensor_dev_attr_in4_beep.dev_attr.attr,	/* 24 */
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	&sensor_dev_attr_in5_input.dev_attr.attr,
231262306a36Sopenharmony_ci	&sensor_dev_attr_in5_min.dev_attr.attr,
231362306a36Sopenharmony_ci	&sensor_dev_attr_in5_max.dev_attr.attr,
231462306a36Sopenharmony_ci	&sensor_dev_attr_in5_alarm.dev_attr.attr,
231562306a36Sopenharmony_ci	&sensor_dev_attr_in5_beep.dev_attr.attr,	/* 29 */
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	&sensor_dev_attr_in6_input.dev_attr.attr,
231862306a36Sopenharmony_ci	&sensor_dev_attr_in6_min.dev_attr.attr,
231962306a36Sopenharmony_ci	&sensor_dev_attr_in6_max.dev_attr.attr,
232062306a36Sopenharmony_ci	&sensor_dev_attr_in6_alarm.dev_attr.attr,
232162306a36Sopenharmony_ci	&sensor_dev_attr_in6_beep.dev_attr.attr,	/* 34 */
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	&sensor_dev_attr_in7_input.dev_attr.attr,
232462306a36Sopenharmony_ci	&sensor_dev_attr_in7_min.dev_attr.attr,
232562306a36Sopenharmony_ci	&sensor_dev_attr_in7_max.dev_attr.attr,
232662306a36Sopenharmony_ci	&sensor_dev_attr_in7_alarm.dev_attr.attr,
232762306a36Sopenharmony_ci	&sensor_dev_attr_in7_beep.dev_attr.attr,	/* 39 */
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	&sensor_dev_attr_in8_input.dev_attr.attr,	/* 40 */
233062306a36Sopenharmony_ci	&sensor_dev_attr_in9_input.dev_attr.attr,
233162306a36Sopenharmony_ci	&sensor_dev_attr_in10_input.dev_attr.attr,
233262306a36Sopenharmony_ci	&sensor_dev_attr_in11_input.dev_attr.attr,
233362306a36Sopenharmony_ci	&sensor_dev_attr_in12_input.dev_attr.attr,
233462306a36Sopenharmony_ci	NULL
233562306a36Sopenharmony_ci};
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_cistatic const struct attribute_group it87_group_in = {
233862306a36Sopenharmony_ci	.attrs = it87_attributes_in,
233962306a36Sopenharmony_ci	.is_visible = it87_in_is_visible,
234062306a36Sopenharmony_ci};
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_cistatic umode_t it87_temp_is_visible(struct kobject *kobj,
234362306a36Sopenharmony_ci				    struct attribute *attr, int index)
234462306a36Sopenharmony_ci{
234562306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
234662306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
234762306a36Sopenharmony_ci	int i = index / 7;	/* temperature index */
234862306a36Sopenharmony_ci	int a = index % 7;	/* attribute index */
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci	if (index >= 21) {
235162306a36Sopenharmony_ci		i = index - 21 + 3;
235262306a36Sopenharmony_ci		a = 0;
235362306a36Sopenharmony_ci	}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	if (!(data->has_temp & BIT(i)))
235662306a36Sopenharmony_ci		return 0;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	if (a == 3) {
235962306a36Sopenharmony_ci		if (get_temp_type(data, i) == 0)
236062306a36Sopenharmony_ci			return 0;
236162306a36Sopenharmony_ci		return attr->mode;
236262306a36Sopenharmony_ci	}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_ci	if (a == 5 && !has_temp_offset(data))
236562306a36Sopenharmony_ci		return 0;
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	if (a == 6 && !data->has_beep)
236862306a36Sopenharmony_ci		return 0;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	return attr->mode;
237162306a36Sopenharmony_ci}
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_cistatic struct attribute *it87_attributes_temp[] = {
237462306a36Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
237562306a36Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
237662306a36Sopenharmony_ci	&sensor_dev_attr_temp1_min.dev_attr.attr,
237762306a36Sopenharmony_ci	&sensor_dev_attr_temp1_type.dev_attr.attr,
237862306a36Sopenharmony_ci	&sensor_dev_attr_temp1_alarm.dev_attr.attr,
237962306a36Sopenharmony_ci	&sensor_dev_attr_temp1_offset.dev_attr.attr,	/* 5 */
238062306a36Sopenharmony_ci	&sensor_dev_attr_temp1_beep.dev_attr.attr,	/* 6 */
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,	/* 7 */
238362306a36Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
238462306a36Sopenharmony_ci	&sensor_dev_attr_temp2_min.dev_attr.attr,
238562306a36Sopenharmony_ci	&sensor_dev_attr_temp2_type.dev_attr.attr,
238662306a36Sopenharmony_ci	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
238762306a36Sopenharmony_ci	&sensor_dev_attr_temp2_offset.dev_attr.attr,
238862306a36Sopenharmony_ci	&sensor_dev_attr_temp2_beep.dev_attr.attr,
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci	&sensor_dev_attr_temp3_input.dev_attr.attr,	/* 14 */
239162306a36Sopenharmony_ci	&sensor_dev_attr_temp3_max.dev_attr.attr,
239262306a36Sopenharmony_ci	&sensor_dev_attr_temp3_min.dev_attr.attr,
239362306a36Sopenharmony_ci	&sensor_dev_attr_temp3_type.dev_attr.attr,
239462306a36Sopenharmony_ci	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
239562306a36Sopenharmony_ci	&sensor_dev_attr_temp3_offset.dev_attr.attr,
239662306a36Sopenharmony_ci	&sensor_dev_attr_temp3_beep.dev_attr.attr,
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	&sensor_dev_attr_temp4_input.dev_attr.attr,	/* 21 */
239962306a36Sopenharmony_ci	&sensor_dev_attr_temp5_input.dev_attr.attr,
240062306a36Sopenharmony_ci	&sensor_dev_attr_temp6_input.dev_attr.attr,
240162306a36Sopenharmony_ci	NULL
240262306a36Sopenharmony_ci};
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_cistatic const struct attribute_group it87_group_temp = {
240562306a36Sopenharmony_ci	.attrs = it87_attributes_temp,
240662306a36Sopenharmony_ci	.is_visible = it87_temp_is_visible,
240762306a36Sopenharmony_ci};
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_cistatic umode_t it87_is_visible(struct kobject *kobj,
241062306a36Sopenharmony_ci			       struct attribute *attr, int index)
241162306a36Sopenharmony_ci{
241262306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
241362306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	if ((index == 2 || index == 3) && !data->has_vid)
241662306a36Sopenharmony_ci		return 0;
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	if (index > 3 && !(data->in_internal & BIT(index - 4)))
241962306a36Sopenharmony_ci		return 0;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	return attr->mode;
242262306a36Sopenharmony_ci}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_cistatic struct attribute *it87_attributes[] = {
242562306a36Sopenharmony_ci	&dev_attr_alarms.attr,
242662306a36Sopenharmony_ci	&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
242762306a36Sopenharmony_ci	&dev_attr_vrm.attr,				/* 2 */
242862306a36Sopenharmony_ci	&dev_attr_cpu0_vid.attr,			/* 3 */
242962306a36Sopenharmony_ci	&sensor_dev_attr_in3_label.dev_attr.attr,	/* 4 .. 7 */
243062306a36Sopenharmony_ci	&sensor_dev_attr_in7_label.dev_attr.attr,
243162306a36Sopenharmony_ci	&sensor_dev_attr_in8_label.dev_attr.attr,
243262306a36Sopenharmony_ci	&sensor_dev_attr_in9_label.dev_attr.attr,
243362306a36Sopenharmony_ci	NULL
243462306a36Sopenharmony_ci};
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_cistatic const struct attribute_group it87_group = {
243762306a36Sopenharmony_ci	.attrs = it87_attributes,
243862306a36Sopenharmony_ci	.is_visible = it87_is_visible,
243962306a36Sopenharmony_ci};
244062306a36Sopenharmony_ci
244162306a36Sopenharmony_cistatic umode_t it87_fan_is_visible(struct kobject *kobj,
244262306a36Sopenharmony_ci				   struct attribute *attr, int index)
244362306a36Sopenharmony_ci{
244462306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
244562306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
244662306a36Sopenharmony_ci	int i = index / 5;	/* fan index */
244762306a36Sopenharmony_ci	int a = index % 5;	/* attribute index */
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	if (index >= 15) {	/* fan 4..6 don't have divisor attributes */
245062306a36Sopenharmony_ci		i = (index - 15) / 4 + 3;
245162306a36Sopenharmony_ci		a = (index - 15) % 4;
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	if (!(data->has_fan & BIT(i)))
245562306a36Sopenharmony_ci		return 0;
245662306a36Sopenharmony_ci
245762306a36Sopenharmony_ci	if (a == 3) {				/* beep */
245862306a36Sopenharmony_ci		if (!data->has_beep)
245962306a36Sopenharmony_ci			return 0;
246062306a36Sopenharmony_ci		/* first fan beep attribute is writable */
246162306a36Sopenharmony_ci		if (i == __ffs(data->has_fan))
246262306a36Sopenharmony_ci			return attr->mode | S_IWUSR;
246362306a36Sopenharmony_ci	}
246462306a36Sopenharmony_ci
246562306a36Sopenharmony_ci	if (a == 4 && has_16bit_fans(data))	/* divisor */
246662306a36Sopenharmony_ci		return 0;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	return attr->mode;
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_cistatic struct attribute *it87_attributes_fan[] = {
247262306a36Sopenharmony_ci	&sensor_dev_attr_fan1_input.dev_attr.attr,
247362306a36Sopenharmony_ci	&sensor_dev_attr_fan1_min.dev_attr.attr,
247462306a36Sopenharmony_ci	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
247562306a36Sopenharmony_ci	&sensor_dev_attr_fan1_beep.dev_attr.attr,	/* 3 */
247662306a36Sopenharmony_ci	&sensor_dev_attr_fan1_div.dev_attr.attr,	/* 4 */
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	&sensor_dev_attr_fan2_input.dev_attr.attr,
247962306a36Sopenharmony_ci	&sensor_dev_attr_fan2_min.dev_attr.attr,
248062306a36Sopenharmony_ci	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
248162306a36Sopenharmony_ci	&sensor_dev_attr_fan2_beep.dev_attr.attr,
248262306a36Sopenharmony_ci	&sensor_dev_attr_fan2_div.dev_attr.attr,	/* 9 */
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	&sensor_dev_attr_fan3_input.dev_attr.attr,
248562306a36Sopenharmony_ci	&sensor_dev_attr_fan3_min.dev_attr.attr,
248662306a36Sopenharmony_ci	&sensor_dev_attr_fan3_alarm.dev_attr.attr,
248762306a36Sopenharmony_ci	&sensor_dev_attr_fan3_beep.dev_attr.attr,
248862306a36Sopenharmony_ci	&sensor_dev_attr_fan3_div.dev_attr.attr,	/* 14 */
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	&sensor_dev_attr_fan4_input.dev_attr.attr,	/* 15 */
249162306a36Sopenharmony_ci	&sensor_dev_attr_fan4_min.dev_attr.attr,
249262306a36Sopenharmony_ci	&sensor_dev_attr_fan4_alarm.dev_attr.attr,
249362306a36Sopenharmony_ci	&sensor_dev_attr_fan4_beep.dev_attr.attr,
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	&sensor_dev_attr_fan5_input.dev_attr.attr,	/* 19 */
249662306a36Sopenharmony_ci	&sensor_dev_attr_fan5_min.dev_attr.attr,
249762306a36Sopenharmony_ci	&sensor_dev_attr_fan5_alarm.dev_attr.attr,
249862306a36Sopenharmony_ci	&sensor_dev_attr_fan5_beep.dev_attr.attr,
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	&sensor_dev_attr_fan6_input.dev_attr.attr,	/* 23 */
250162306a36Sopenharmony_ci	&sensor_dev_attr_fan6_min.dev_attr.attr,
250262306a36Sopenharmony_ci	&sensor_dev_attr_fan6_alarm.dev_attr.attr,
250362306a36Sopenharmony_ci	&sensor_dev_attr_fan6_beep.dev_attr.attr,
250462306a36Sopenharmony_ci	NULL
250562306a36Sopenharmony_ci};
250662306a36Sopenharmony_ci
250762306a36Sopenharmony_cistatic const struct attribute_group it87_group_fan = {
250862306a36Sopenharmony_ci	.attrs = it87_attributes_fan,
250962306a36Sopenharmony_ci	.is_visible = it87_fan_is_visible,
251062306a36Sopenharmony_ci};
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_cistatic umode_t it87_pwm_is_visible(struct kobject *kobj,
251362306a36Sopenharmony_ci				   struct attribute *attr, int index)
251462306a36Sopenharmony_ci{
251562306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
251662306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
251762306a36Sopenharmony_ci	int i = index / 4;	/* pwm index */
251862306a36Sopenharmony_ci	int a = index % 4;	/* attribute index */
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	if (!(data->has_pwm & BIT(i)))
252162306a36Sopenharmony_ci		return 0;
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	/* pwmX_auto_channels_temp is only writable if auto pwm is supported */
252462306a36Sopenharmony_ci	if (a == 3 && (has_old_autopwm(data) || has_newer_autopwm(data)))
252562306a36Sopenharmony_ci		return attr->mode | S_IWUSR;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	/* pwm2_freq is writable if there are two pwm frequency selects */
252862306a36Sopenharmony_ci	if (has_pwm_freq2(data) && i == 1 && a == 2)
252962306a36Sopenharmony_ci		return attr->mode | S_IWUSR;
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	return attr->mode;
253262306a36Sopenharmony_ci}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_cistatic struct attribute *it87_attributes_pwm[] = {
253562306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
253662306a36Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
253762306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
253862306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
254162306a36Sopenharmony_ci	&sensor_dev_attr_pwm2.dev_attr.attr,
254262306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
254362306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_enable.dev_attr.attr,
254662306a36Sopenharmony_ci	&sensor_dev_attr_pwm3.dev_attr.attr,
254762306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_freq.dev_attr.attr,
254862306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_enable.dev_attr.attr,
255162306a36Sopenharmony_ci	&sensor_dev_attr_pwm4.dev_attr.attr,
255262306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_freq.dev_attr.attr,
255362306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr,
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_enable.dev_attr.attr,
255662306a36Sopenharmony_ci	&sensor_dev_attr_pwm5.dev_attr.attr,
255762306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_freq.dev_attr.attr,
255862306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr,
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_enable.dev_attr.attr,
256162306a36Sopenharmony_ci	&sensor_dev_attr_pwm6.dev_attr.attr,
256262306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_freq.dev_attr.attr,
256362306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr,
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	NULL
256662306a36Sopenharmony_ci};
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_cistatic const struct attribute_group it87_group_pwm = {
256962306a36Sopenharmony_ci	.attrs = it87_attributes_pwm,
257062306a36Sopenharmony_ci	.is_visible = it87_pwm_is_visible,
257162306a36Sopenharmony_ci};
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_cistatic umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
257462306a36Sopenharmony_ci					struct attribute *attr, int index)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
257762306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
257862306a36Sopenharmony_ci	int i = index / 11;	/* pwm index */
257962306a36Sopenharmony_ci	int a = index % 11;	/* attribute index */
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	if (index >= 33) {	/* pwm 4..6 */
258262306a36Sopenharmony_ci		i = (index - 33) / 6 + 3;
258362306a36Sopenharmony_ci		a = (index - 33) % 6 + 4;
258462306a36Sopenharmony_ci	}
258562306a36Sopenharmony_ci
258662306a36Sopenharmony_ci	if (!(data->has_pwm & BIT(i)))
258762306a36Sopenharmony_ci		return 0;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	if (has_newer_autopwm(data)) {
259062306a36Sopenharmony_ci		if (a < 4)	/* no auto point pwm */
259162306a36Sopenharmony_ci			return 0;
259262306a36Sopenharmony_ci		if (a == 8)	/* no auto_point4 */
259362306a36Sopenharmony_ci			return 0;
259462306a36Sopenharmony_ci	}
259562306a36Sopenharmony_ci	if (has_old_autopwm(data)) {
259662306a36Sopenharmony_ci		if (a >= 9)	/* no pwm_auto_start, pwm_auto_slope */
259762306a36Sopenharmony_ci			return 0;
259862306a36Sopenharmony_ci	}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci	return attr->mode;
260162306a36Sopenharmony_ci}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_cistatic struct attribute *it87_attributes_auto_pwm[] = {
260462306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
260562306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
260662306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
260762306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
260862306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
260962306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr,
261062306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
261162306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
261262306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
261362306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_start.dev_attr.attr,
261462306a36Sopenharmony_ci	&sensor_dev_attr_pwm1_auto_slope.dev_attr.attr,
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,	/* 11 */
261762306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
261862306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
261962306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
262062306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
262162306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr,
262262306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
262362306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
262462306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
262562306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_start.dev_attr.attr,
262662306a36Sopenharmony_ci	&sensor_dev_attr_pwm2_auto_slope.dev_attr.attr,
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,	/* 22 */
262962306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
263062306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
263162306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
263262306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
263362306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr,
263462306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
263562306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
263662306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
263762306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_start.dev_attr.attr,
263862306a36Sopenharmony_ci	&sensor_dev_attr_pwm3_auto_slope.dev_attr.attr,
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr,	/* 33 */
264162306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_point1_temp_hyst.dev_attr.attr,
264262306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr,
264362306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_point3_temp.dev_attr.attr,
264462306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_start.dev_attr.attr,
264562306a36Sopenharmony_ci	&sensor_dev_attr_pwm4_auto_slope.dev_attr.attr,
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_point1_temp.dev_attr.attr,
264862306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_point1_temp_hyst.dev_attr.attr,
264962306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_point2_temp.dev_attr.attr,
265062306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_point3_temp.dev_attr.attr,
265162306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_start.dev_attr.attr,
265262306a36Sopenharmony_ci	&sensor_dev_attr_pwm5_auto_slope.dev_attr.attr,
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_point1_temp.dev_attr.attr,
265562306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_point1_temp_hyst.dev_attr.attr,
265662306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_point2_temp.dev_attr.attr,
265762306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_point3_temp.dev_attr.attr,
265862306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_start.dev_attr.attr,
265962306a36Sopenharmony_ci	&sensor_dev_attr_pwm6_auto_slope.dev_attr.attr,
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	NULL,
266262306a36Sopenharmony_ci};
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_cistatic const struct attribute_group it87_group_auto_pwm = {
266562306a36Sopenharmony_ci	.attrs = it87_attributes_auto_pwm,
266662306a36Sopenharmony_ci	.is_visible = it87_auto_pwm_is_visible,
266762306a36Sopenharmony_ci};
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci/* SuperIO detection - will change isa_address if a chip is found */
267062306a36Sopenharmony_cistatic int __init it87_find(int sioaddr, unsigned short *address,
267162306a36Sopenharmony_ci			    struct it87_sio_data *sio_data, int chip_cnt)
267262306a36Sopenharmony_ci{
267362306a36Sopenharmony_ci	int err;
267462306a36Sopenharmony_ci	u16 chip_type;
267562306a36Sopenharmony_ci	const struct it87_devices *config = NULL;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	err = superio_enter(sioaddr);
267862306a36Sopenharmony_ci	if (err)
267962306a36Sopenharmony_ci		return err;
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	err = -ENODEV;
268262306a36Sopenharmony_ci	chip_type = superio_inw(sioaddr, DEVID);
268362306a36Sopenharmony_ci	/* check first for a valid chip before forcing chip id */
268462306a36Sopenharmony_ci	if (chip_type == 0xffff)
268562306a36Sopenharmony_ci		goto exit;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	if (force_id_cnt == 1) {
268862306a36Sopenharmony_ci		/* If only one value given use for all chips */
268962306a36Sopenharmony_ci		if (force_id[0])
269062306a36Sopenharmony_ci			chip_type = force_id[0];
269162306a36Sopenharmony_ci	} else if (force_id[chip_cnt])
269262306a36Sopenharmony_ci		chip_type = force_id[chip_cnt];
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	switch (chip_type) {
269562306a36Sopenharmony_ci	case IT8705F_DEVID:
269662306a36Sopenharmony_ci		sio_data->type = it87;
269762306a36Sopenharmony_ci		break;
269862306a36Sopenharmony_ci	case IT8712F_DEVID:
269962306a36Sopenharmony_ci		sio_data->type = it8712;
270062306a36Sopenharmony_ci		break;
270162306a36Sopenharmony_ci	case IT8716F_DEVID:
270262306a36Sopenharmony_ci	case IT8726F_DEVID:
270362306a36Sopenharmony_ci		sio_data->type = it8716;
270462306a36Sopenharmony_ci		break;
270562306a36Sopenharmony_ci	case IT8718F_DEVID:
270662306a36Sopenharmony_ci		sio_data->type = it8718;
270762306a36Sopenharmony_ci		break;
270862306a36Sopenharmony_ci	case IT8720F_DEVID:
270962306a36Sopenharmony_ci		sio_data->type = it8720;
271062306a36Sopenharmony_ci		break;
271162306a36Sopenharmony_ci	case IT8721F_DEVID:
271262306a36Sopenharmony_ci		sio_data->type = it8721;
271362306a36Sopenharmony_ci		break;
271462306a36Sopenharmony_ci	case IT8728F_DEVID:
271562306a36Sopenharmony_ci		sio_data->type = it8728;
271662306a36Sopenharmony_ci		break;
271762306a36Sopenharmony_ci	case IT8732F_DEVID:
271862306a36Sopenharmony_ci		sio_data->type = it8732;
271962306a36Sopenharmony_ci		break;
272062306a36Sopenharmony_ci	case IT8792E_DEVID:
272162306a36Sopenharmony_ci		sio_data->type = it8792;
272262306a36Sopenharmony_ci		break;
272362306a36Sopenharmony_ci	case IT8771E_DEVID:
272462306a36Sopenharmony_ci		sio_data->type = it8771;
272562306a36Sopenharmony_ci		break;
272662306a36Sopenharmony_ci	case IT8772E_DEVID:
272762306a36Sopenharmony_ci		sio_data->type = it8772;
272862306a36Sopenharmony_ci		break;
272962306a36Sopenharmony_ci	case IT8781F_DEVID:
273062306a36Sopenharmony_ci		sio_data->type = it8781;
273162306a36Sopenharmony_ci		break;
273262306a36Sopenharmony_ci	case IT8782F_DEVID:
273362306a36Sopenharmony_ci		sio_data->type = it8782;
273462306a36Sopenharmony_ci		break;
273562306a36Sopenharmony_ci	case IT8783E_DEVID:
273662306a36Sopenharmony_ci		sio_data->type = it8783;
273762306a36Sopenharmony_ci		break;
273862306a36Sopenharmony_ci	case IT8786E_DEVID:
273962306a36Sopenharmony_ci		sio_data->type = it8786;
274062306a36Sopenharmony_ci		break;
274162306a36Sopenharmony_ci	case IT8790E_DEVID:
274262306a36Sopenharmony_ci		sio_data->type = it8790;
274362306a36Sopenharmony_ci		break;
274462306a36Sopenharmony_ci	case IT8603E_DEVID:
274562306a36Sopenharmony_ci	case IT8623E_DEVID:
274662306a36Sopenharmony_ci		sio_data->type = it8603;
274762306a36Sopenharmony_ci		break;
274862306a36Sopenharmony_ci	case IT8620E_DEVID:
274962306a36Sopenharmony_ci		sio_data->type = it8620;
275062306a36Sopenharmony_ci		break;
275162306a36Sopenharmony_ci	case IT8622E_DEVID:
275262306a36Sopenharmony_ci		sio_data->type = it8622;
275362306a36Sopenharmony_ci		break;
275462306a36Sopenharmony_ci	case IT8628E_DEVID:
275562306a36Sopenharmony_ci		sio_data->type = it8628;
275662306a36Sopenharmony_ci		break;
275762306a36Sopenharmony_ci	case IT87952E_DEVID:
275862306a36Sopenharmony_ci		sio_data->type = it87952;
275962306a36Sopenharmony_ci		break;
276062306a36Sopenharmony_ci	case 0xffff:	/* No device at all */
276162306a36Sopenharmony_ci		goto exit;
276262306a36Sopenharmony_ci	default:
276362306a36Sopenharmony_ci		pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type);
276462306a36Sopenharmony_ci		goto exit;
276562306a36Sopenharmony_ci	}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	config = &it87_devices[sio_data->type];
276862306a36Sopenharmony_ci
276962306a36Sopenharmony_ci	superio_select(sioaddr, PME);
277062306a36Sopenharmony_ci	if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
277162306a36Sopenharmony_ci		pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
277262306a36Sopenharmony_ci			config->model, sioaddr);
277362306a36Sopenharmony_ci		goto exit;
277462306a36Sopenharmony_ci	}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci	*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
277762306a36Sopenharmony_ci	if (*address == 0) {
277862306a36Sopenharmony_ci		pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n",
277962306a36Sopenharmony_ci			config->model, sioaddr);
278062306a36Sopenharmony_ci		goto exit;
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	err = 0;
278462306a36Sopenharmony_ci	sio_data->sioaddr = sioaddr;
278562306a36Sopenharmony_ci	sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
278662306a36Sopenharmony_ci	pr_info("Found %s chip at 0x%x, revision %d\n",
278762306a36Sopenharmony_ci		it87_devices[sio_data->type].model,
278862306a36Sopenharmony_ci		*address, sio_data->revision);
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	/* in7 (VSB or VCCH5V) is always internal on some chips */
279162306a36Sopenharmony_ci	if (has_in7_internal(config))
279262306a36Sopenharmony_ci		sio_data->internal |= BIT(1);
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	/* in8 (Vbat) is always internal */
279562306a36Sopenharmony_ci	sio_data->internal |= BIT(2);
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	/* in9 (AVCC3), always internal if supported */
279862306a36Sopenharmony_ci	if (has_avcc3(config))
279962306a36Sopenharmony_ci		sio_data->internal |= BIT(3); /* in9 is AVCC */
280062306a36Sopenharmony_ci	else
280162306a36Sopenharmony_ci		sio_data->skip_in |= BIT(9);
280262306a36Sopenharmony_ci
280362306a36Sopenharmony_ci	if (!has_four_pwm(config))
280462306a36Sopenharmony_ci		sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
280562306a36Sopenharmony_ci	else if (!has_five_pwm(config))
280662306a36Sopenharmony_ci		sio_data->skip_pwm |= BIT(4) | BIT(5);
280762306a36Sopenharmony_ci	else if (!has_six_pwm(config))
280862306a36Sopenharmony_ci		sio_data->skip_pwm |= BIT(5);
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	if (!has_vid(config))
281162306a36Sopenharmony_ci		sio_data->skip_vid = 1;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	/* Read GPIO config and VID value from LDN 7 (GPIO) */
281462306a36Sopenharmony_ci	if (sio_data->type == it87) {
281562306a36Sopenharmony_ci		/* The IT8705F has a different LD number for GPIO */
281662306a36Sopenharmony_ci		superio_select(sioaddr, 5);
281762306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
281862306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
281962306a36Sopenharmony_ci	} else if (sio_data->type == it8783) {
282062306a36Sopenharmony_ci		int reg25, reg27, reg2a, reg2c, regef;
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci		reg25 = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
282562306a36Sopenharmony_ci		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
282662306a36Sopenharmony_ci		reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG);
282762306a36Sopenharmony_ci		reg2c = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
282862306a36Sopenharmony_ci		regef = superio_inb(sioaddr, IT87_SIO_SPI_REG);
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci		/* Check if fan3 is there or not */
283162306a36Sopenharmony_ci		if ((reg27 & BIT(0)) || !(reg2c & BIT(2)))
283262306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
283362306a36Sopenharmony_ci		if ((reg25 & BIT(4)) ||
283462306a36Sopenharmony_ci		    (!(reg2a & BIT(1)) && (regef & BIT(0))))
283562306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_ci		/* Check if fan2 is there or not */
283862306a36Sopenharmony_ci		if (reg27 & BIT(7))
283962306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
284062306a36Sopenharmony_ci		if (reg27 & BIT(3))
284162306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
284262306a36Sopenharmony_ci
284362306a36Sopenharmony_ci		/* VIN5 */
284462306a36Sopenharmony_ci		if ((reg27 & BIT(0)) || (reg2c & BIT(2)))
284562306a36Sopenharmony_ci			sio_data->skip_in |= BIT(5); /* No VIN5 */
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci		/* VIN6 */
284862306a36Sopenharmony_ci		if (reg27 & BIT(1))
284962306a36Sopenharmony_ci			sio_data->skip_in |= BIT(6); /* No VIN6 */
285062306a36Sopenharmony_ci
285162306a36Sopenharmony_ci		/*
285262306a36Sopenharmony_ci		 * VIN7
285362306a36Sopenharmony_ci		 * Does not depend on bit 2 of Reg2C, contrary to datasheet.
285462306a36Sopenharmony_ci		 */
285562306a36Sopenharmony_ci		if (reg27 & BIT(2)) {
285662306a36Sopenharmony_ci			/*
285762306a36Sopenharmony_ci			 * The data sheet is a bit unclear regarding the
285862306a36Sopenharmony_ci			 * internal voltage divider for VCCH5V. It says
285962306a36Sopenharmony_ci			 * "This bit enables and switches VIN7 (pin 91) to the
286062306a36Sopenharmony_ci			 * internal voltage divider for VCCH5V".
286162306a36Sopenharmony_ci			 * This is different to other chips, where the internal
286262306a36Sopenharmony_ci			 * voltage divider would connect VIN7 to an internal
286362306a36Sopenharmony_ci			 * voltage source. Maybe that is the case here as well.
286462306a36Sopenharmony_ci			 *
286562306a36Sopenharmony_ci			 * Since we don't know for sure, re-route it if that is
286662306a36Sopenharmony_ci			 * not the case, and ask the user to report if the
286762306a36Sopenharmony_ci			 * resulting voltage is sane.
286862306a36Sopenharmony_ci			 */
286962306a36Sopenharmony_ci			if (!(reg2c & BIT(1))) {
287062306a36Sopenharmony_ci				reg2c |= BIT(1);
287162306a36Sopenharmony_ci				superio_outb(sioaddr, IT87_SIO_PINX2_REG,
287262306a36Sopenharmony_ci					     reg2c);
287362306a36Sopenharmony_ci				sio_data->need_in7_reroute = true;
287462306a36Sopenharmony_ci				pr_notice("Routing internal VCCH5V to in7.\n");
287562306a36Sopenharmony_ci			}
287662306a36Sopenharmony_ci			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
287762306a36Sopenharmony_ci			pr_notice("Please report if it displays a reasonable voltage.\n");
287862306a36Sopenharmony_ci		}
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci		if (reg2c & BIT(0))
288162306a36Sopenharmony_ci			sio_data->internal |= BIT(0);
288262306a36Sopenharmony_ci		if (reg2c & BIT(1))
288362306a36Sopenharmony_ci			sio_data->internal |= BIT(1);
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
288662306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
288762306a36Sopenharmony_ci	} else if (sio_data->type == it8603) {
288862306a36Sopenharmony_ci		int reg27, reg29;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
289362306a36Sopenharmony_ci
289462306a36Sopenharmony_ci		/* Check if fan3 is there or not */
289562306a36Sopenharmony_ci		if (reg27 & BIT(6))
289662306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
289762306a36Sopenharmony_ci		if (reg27 & BIT(7))
289862306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci		/* Check if fan2 is there or not */
290162306a36Sopenharmony_ci		reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
290262306a36Sopenharmony_ci		if (reg29 & BIT(1))
290362306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
290462306a36Sopenharmony_ci		if (reg29 & BIT(2))
290562306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		sio_data->skip_in |= BIT(5); /* No VIN5 */
290862306a36Sopenharmony_ci		sio_data->skip_in |= BIT(6); /* No VIN6 */
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
291162306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
291262306a36Sopenharmony_ci	} else if (sio_data->type == it8620 || sio_data->type == it8628) {
291362306a36Sopenharmony_ci		int reg;
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci		/* Check for pwm5 */
291862306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
291962306a36Sopenharmony_ci		if (reg & BIT(6))
292062306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(4);
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci		/* Check for fan4, fan5 */
292362306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
292462306a36Sopenharmony_ci		if (!(reg & BIT(5)))
292562306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(3);
292662306a36Sopenharmony_ci		if (!(reg & BIT(4)))
292762306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(4);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci		/* Check for pwm3, fan3 */
293062306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
293162306a36Sopenharmony_ci		if (reg & BIT(6))
293262306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
293362306a36Sopenharmony_ci		if (reg & BIT(7))
293462306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci		/* Check for pwm4 */
293762306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
293862306a36Sopenharmony_ci		if (reg & BIT(2))
293962306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(3);
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci		/* Check for pwm2, fan2 */
294262306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
294362306a36Sopenharmony_ci		if (reg & BIT(1))
294462306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
294562306a36Sopenharmony_ci		if (reg & BIT(2))
294662306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
294762306a36Sopenharmony_ci		/* Check for pwm6, fan6 */
294862306a36Sopenharmony_ci		if (!(reg & BIT(7))) {
294962306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(5);
295062306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(5);
295162306a36Sopenharmony_ci		}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci		/* Check if AVCC is on VIN3 */
295462306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
295562306a36Sopenharmony_ci		if (reg & BIT(0))
295662306a36Sopenharmony_ci			sio_data->internal |= BIT(0);
295762306a36Sopenharmony_ci		else
295862306a36Sopenharmony_ci			sio_data->skip_in |= BIT(9);
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
296162306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
296262306a36Sopenharmony_ci	} else if (sio_data->type == it8622) {
296362306a36Sopenharmony_ci		int reg;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci		/* Check for pwm4, fan4 */
296862306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
296962306a36Sopenharmony_ci		if (reg & BIT(6))
297062306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(3);
297162306a36Sopenharmony_ci		if (reg & BIT(5))
297262306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(3);
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci		/* Check for pwm3, fan3, pwm5, fan5 */
297562306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
297662306a36Sopenharmony_ci		if (reg & BIT(6))
297762306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
297862306a36Sopenharmony_ci		if (reg & BIT(7))
297962306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
298062306a36Sopenharmony_ci		if (reg & BIT(3))
298162306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(4);
298262306a36Sopenharmony_ci		if (reg & BIT(1))
298362306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(4);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci		/* Check for pwm2, fan2 */
298662306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
298762306a36Sopenharmony_ci		if (reg & BIT(1))
298862306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
298962306a36Sopenharmony_ci		if (reg & BIT(2))
299062306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci		/* Check for AVCC */
299362306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
299462306a36Sopenharmony_ci		if (!(reg & BIT(0)))
299562306a36Sopenharmony_ci			sio_data->skip_in |= BIT(9);
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
299862306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
299962306a36Sopenharmony_ci	} else if (sio_data->type == it8732) {
300062306a36Sopenharmony_ci		int reg;
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci		/* Check for pwm2, fan2 */
300562306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
300662306a36Sopenharmony_ci		if (reg & BIT(1))
300762306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
300862306a36Sopenharmony_ci		if (reg & BIT(2))
300962306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci		/* Check for pwm3, fan3, fan4 */
301262306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
301362306a36Sopenharmony_ci		if (reg & BIT(6))
301462306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
301562306a36Sopenharmony_ci		if (reg & BIT(7))
301662306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
301762306a36Sopenharmony_ci		if (reg & BIT(5))
301862306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(3);
301962306a36Sopenharmony_ci
302062306a36Sopenharmony_ci		/* Check if AVCC is on VIN3 */
302162306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
302262306a36Sopenharmony_ci		if (reg & BIT(0))
302362306a36Sopenharmony_ci			sio_data->internal |= BIT(0);
302462306a36Sopenharmony_ci
302562306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
302662306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
302762306a36Sopenharmony_ci	} else {
302862306a36Sopenharmony_ci		int reg;
302962306a36Sopenharmony_ci		bool uart6;
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci		superio_select(sioaddr, GPIO);
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_ci		/* Check for fan4, fan5 */
303462306a36Sopenharmony_ci		if (has_five_fans(config)) {
303562306a36Sopenharmony_ci			reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
303662306a36Sopenharmony_ci			switch (sio_data->type) {
303762306a36Sopenharmony_ci			case it8718:
303862306a36Sopenharmony_ci				if (reg & BIT(5))
303962306a36Sopenharmony_ci					sio_data->skip_fan |= BIT(3);
304062306a36Sopenharmony_ci				if (reg & BIT(4))
304162306a36Sopenharmony_ci					sio_data->skip_fan |= BIT(4);
304262306a36Sopenharmony_ci				break;
304362306a36Sopenharmony_ci			case it8720:
304462306a36Sopenharmony_ci			case it8721:
304562306a36Sopenharmony_ci			case it8728:
304662306a36Sopenharmony_ci				if (!(reg & BIT(5)))
304762306a36Sopenharmony_ci					sio_data->skip_fan |= BIT(3);
304862306a36Sopenharmony_ci				if (!(reg & BIT(4)))
304962306a36Sopenharmony_ci					sio_data->skip_fan |= BIT(4);
305062306a36Sopenharmony_ci				break;
305162306a36Sopenharmony_ci			default:
305262306a36Sopenharmony_ci				break;
305362306a36Sopenharmony_ci			}
305462306a36Sopenharmony_ci		}
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
305762306a36Sopenharmony_ci		if (!sio_data->skip_vid) {
305862306a36Sopenharmony_ci			/* We need at least 4 VID pins */
305962306a36Sopenharmony_ci			if (reg & 0x0f) {
306062306a36Sopenharmony_ci				pr_info("VID is disabled (pins used for GPIO)\n");
306162306a36Sopenharmony_ci				sio_data->skip_vid = 1;
306262306a36Sopenharmony_ci			}
306362306a36Sopenharmony_ci		}
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci		/* Check if fan3 is there or not */
306662306a36Sopenharmony_ci		if (reg & BIT(6))
306762306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(2);
306862306a36Sopenharmony_ci		if (reg & BIT(7))
306962306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(2);
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci		/* Check if fan2 is there or not */
307262306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
307362306a36Sopenharmony_ci		if (reg & BIT(1))
307462306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(1);
307562306a36Sopenharmony_ci		if (reg & BIT(2))
307662306a36Sopenharmony_ci			sio_data->skip_fan |= BIT(1);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci		if ((sio_data->type == it8718 || sio_data->type == it8720) &&
307962306a36Sopenharmony_ci		    !(sio_data->skip_vid))
308062306a36Sopenharmony_ci			sio_data->vid_value = superio_inb(sioaddr,
308162306a36Sopenharmony_ci							  IT87_SIO_VID_REG);
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_ci		uart6 = sio_data->type == it8782 && (reg & BIT(2));
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci		/*
308862306a36Sopenharmony_ci		 * The IT8720F has no VIN7 pin, so VCCH5V should always be
308962306a36Sopenharmony_ci		 * routed internally to VIN7 with an internal divider.
309062306a36Sopenharmony_ci		 * Curiously, there still is a configuration bit to control
309162306a36Sopenharmony_ci		 * this, which means it can be set incorrectly. And even
309262306a36Sopenharmony_ci		 * more curiously, many boards out there are improperly
309362306a36Sopenharmony_ci		 * configured, even though the IT8720F datasheet claims
309462306a36Sopenharmony_ci		 * that the internal routing of VCCH5V to VIN7 is the default
309562306a36Sopenharmony_ci		 * setting. So we force the internal routing in this case.
309662306a36Sopenharmony_ci		 *
309762306a36Sopenharmony_ci		 * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
309862306a36Sopenharmony_ci		 * If UART6 is enabled, re-route VIN7 to the internal divider
309962306a36Sopenharmony_ci		 * if that is not already the case.
310062306a36Sopenharmony_ci		 */
310162306a36Sopenharmony_ci		if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) {
310262306a36Sopenharmony_ci			reg |= BIT(1);
310362306a36Sopenharmony_ci			superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
310462306a36Sopenharmony_ci			sio_data->need_in7_reroute = true;
310562306a36Sopenharmony_ci			pr_notice("Routing internal VCCH5V to in7\n");
310662306a36Sopenharmony_ci		}
310762306a36Sopenharmony_ci		if (reg & BIT(0))
310862306a36Sopenharmony_ci			sio_data->internal |= BIT(0);
310962306a36Sopenharmony_ci		if (reg & BIT(1))
311062306a36Sopenharmony_ci			sio_data->internal |= BIT(1);
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci		/*
311362306a36Sopenharmony_ci		 * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
311462306a36Sopenharmony_ci		 * While VIN7 can be routed to the internal voltage divider,
311562306a36Sopenharmony_ci		 * VIN5 and VIN6 are not available if UART6 is enabled.
311662306a36Sopenharmony_ci		 *
311762306a36Sopenharmony_ci		 * Also, temp3 is not available if UART6 is enabled and TEMPIN3
311862306a36Sopenharmony_ci		 * is the temperature source. Since we can not read the
311962306a36Sopenharmony_ci		 * temperature source here, skip_temp is preliminary.
312062306a36Sopenharmony_ci		 */
312162306a36Sopenharmony_ci		if (uart6) {
312262306a36Sopenharmony_ci			sio_data->skip_in |= BIT(5) | BIT(6);
312362306a36Sopenharmony_ci			sio_data->skip_temp |= BIT(2);
312462306a36Sopenharmony_ci		}
312562306a36Sopenharmony_ci
312662306a36Sopenharmony_ci		sio_data->beep_pin = superio_inb(sioaddr,
312762306a36Sopenharmony_ci						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
312862306a36Sopenharmony_ci	}
312962306a36Sopenharmony_ci	if (sio_data->beep_pin)
313062306a36Sopenharmony_ci		pr_info("Beeping is supported\n");
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	/* Set values based on DMI matches */
313362306a36Sopenharmony_ci	if (dmi_data)
313462306a36Sopenharmony_ci		sio_data->skip_pwm |= dmi_data->skip_pwm;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	if (config->smbus_bitmap) {
313762306a36Sopenharmony_ci		u8 reg;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci		superio_select(sioaddr, PME);
314062306a36Sopenharmony_ci		reg = superio_inb(sioaddr, IT87_SPECIAL_CFG_REG);
314162306a36Sopenharmony_ci		sio_data->ec_special_config = reg;
314262306a36Sopenharmony_ci		sio_data->smbus_bitmap = reg & config->smbus_bitmap;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ciexit:
314662306a36Sopenharmony_ci	superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
314762306a36Sopenharmony_ci	return err;
314862306a36Sopenharmony_ci}
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci/*
315162306a36Sopenharmony_ci * Some chips seem to have default value 0xff for all limit
315262306a36Sopenharmony_ci * registers. For low voltage limits it makes no sense and triggers
315362306a36Sopenharmony_ci * alarms, so change to 0 instead. For high temperature limits, it
315462306a36Sopenharmony_ci * means -1 degree C, which surprisingly doesn't trigger an alarm,
315562306a36Sopenharmony_ci * but is still confusing, so change to 127 degrees C.
315662306a36Sopenharmony_ci */
315762306a36Sopenharmony_cistatic void it87_check_limit_regs(struct it87_data *data)
315862306a36Sopenharmony_ci{
315962306a36Sopenharmony_ci	int i, reg;
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci	for (i = 0; i < NUM_VIN_LIMIT; i++) {
316262306a36Sopenharmony_ci		reg = it87_read_value(data, IT87_REG_VIN_MIN(i));
316362306a36Sopenharmony_ci		if (reg == 0xff)
316462306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
316562306a36Sopenharmony_ci	}
316662306a36Sopenharmony_ci	for (i = 0; i < NUM_TEMP_LIMIT; i++) {
316762306a36Sopenharmony_ci		reg = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
316862306a36Sopenharmony_ci		if (reg == 0xff)
316962306a36Sopenharmony_ci			it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
317062306a36Sopenharmony_ci	}
317162306a36Sopenharmony_ci}
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci/* Check if voltage monitors are reset manually or by some reason */
317462306a36Sopenharmony_cistatic void it87_check_voltage_monitors_reset(struct it87_data *data)
317562306a36Sopenharmony_ci{
317662306a36Sopenharmony_ci	int reg;
317762306a36Sopenharmony_ci
317862306a36Sopenharmony_ci	reg = it87_read_value(data, IT87_REG_VIN_ENABLE);
317962306a36Sopenharmony_ci	if ((reg & 0xff) == 0) {
318062306a36Sopenharmony_ci		/* Enable all voltage monitors */
318162306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
318262306a36Sopenharmony_ci	}
318362306a36Sopenharmony_ci}
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci/* Check if tachometers are reset manually or by some reason */
318662306a36Sopenharmony_cistatic void it87_check_tachometers_reset(struct platform_device *pdev)
318762306a36Sopenharmony_ci{
318862306a36Sopenharmony_ci	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
318962306a36Sopenharmony_ci	struct it87_data *data = platform_get_drvdata(pdev);
319062306a36Sopenharmony_ci	u8 mask, fan_main_ctrl;
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	mask = 0x70 & ~(sio_data->skip_fan << 4);
319362306a36Sopenharmony_ci	fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
319462306a36Sopenharmony_ci	if ((fan_main_ctrl & mask) == 0) {
319562306a36Sopenharmony_ci		/* Enable all fan tachometers */
319662306a36Sopenharmony_ci		fan_main_ctrl |= mask;
319762306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
319862306a36Sopenharmony_ci				 fan_main_ctrl);
319962306a36Sopenharmony_ci	}
320062306a36Sopenharmony_ci}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci/* Set tachometers to 16-bit mode if needed */
320362306a36Sopenharmony_cistatic void it87_check_tachometers_16bit_mode(struct platform_device *pdev)
320462306a36Sopenharmony_ci{
320562306a36Sopenharmony_ci	struct it87_data *data = platform_get_drvdata(pdev);
320662306a36Sopenharmony_ci	int reg;
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci	if (!has_fan16_config(data))
320962306a36Sopenharmony_ci		return;
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci	reg = it87_read_value(data, IT87_REG_FAN_16BIT);
321262306a36Sopenharmony_ci	if (~reg & 0x07 & data->has_fan) {
321362306a36Sopenharmony_ci		dev_dbg(&pdev->dev,
321462306a36Sopenharmony_ci			"Setting fan1-3 to 16-bit mode\n");
321562306a36Sopenharmony_ci		it87_write_value(data, IT87_REG_FAN_16BIT,
321662306a36Sopenharmony_ci				 reg | 0x07);
321762306a36Sopenharmony_ci	}
321862306a36Sopenharmony_ci}
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_cistatic void it87_start_monitoring(struct it87_data *data)
322162306a36Sopenharmony_ci{
322262306a36Sopenharmony_ci	it87_write_value(data, IT87_REG_CONFIG,
322362306a36Sopenharmony_ci			 (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
322462306a36Sopenharmony_ci			 | (update_vbat ? 0x41 : 0x01));
322562306a36Sopenharmony_ci}
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci/* Called when we have found a new IT87. */
322862306a36Sopenharmony_cistatic void it87_init_device(struct platform_device *pdev)
322962306a36Sopenharmony_ci{
323062306a36Sopenharmony_ci	struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
323162306a36Sopenharmony_ci	struct it87_data *data = platform_get_drvdata(pdev);
323262306a36Sopenharmony_ci	int tmp, i;
323362306a36Sopenharmony_ci
323462306a36Sopenharmony_ci	/*
323562306a36Sopenharmony_ci	 * For each PWM channel:
323662306a36Sopenharmony_ci	 * - If it is in automatic mode, setting to manual mode should set
323762306a36Sopenharmony_ci	 *   the fan to full speed by default.
323862306a36Sopenharmony_ci	 * - If it is in manual mode, we need a mapping to temperature
323962306a36Sopenharmony_ci	 *   channels to use when later setting to automatic mode later.
324062306a36Sopenharmony_ci	 *   Use a 1:1 mapping by default (we are clueless.)
324162306a36Sopenharmony_ci	 * In both cases, the value can (and should) be changed by the user
324262306a36Sopenharmony_ci	 * prior to switching to a different mode.
324362306a36Sopenharmony_ci	 * Note that this is no longer needed for the IT8721F and later, as
324462306a36Sopenharmony_ci	 * these have separate registers for the temperature mapping and the
324562306a36Sopenharmony_ci	 * manual duty cycle.
324662306a36Sopenharmony_ci	 */
324762306a36Sopenharmony_ci	for (i = 0; i < NUM_AUTO_PWM; i++) {
324862306a36Sopenharmony_ci		data->pwm_temp_map[i] = i;
324962306a36Sopenharmony_ci		data->pwm_duty[i] = 0x7f;	/* Full speed */
325062306a36Sopenharmony_ci		data->auto_pwm[i][3] = 0x7f;	/* Full speed, hard-coded */
325162306a36Sopenharmony_ci	}
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	it87_check_limit_regs(data);
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	/*
325662306a36Sopenharmony_ci	 * Temperature channels are not forcibly enabled, as they can be
325762306a36Sopenharmony_ci	 * set to two different sensor types and we can't guess which one
325862306a36Sopenharmony_ci	 * is correct for a given system. These channels can be enabled at
325962306a36Sopenharmony_ci	 * run-time through the temp{1-3}_type sysfs accessors if needed.
326062306a36Sopenharmony_ci	 */
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	it87_check_voltage_monitors_reset(data);
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	it87_check_tachometers_reset(pdev);
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
326762306a36Sopenharmony_ci	data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	it87_check_tachometers_16bit_mode(pdev);
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	/* Check for additional fans */
327262306a36Sopenharmony_ci	tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	if (has_four_fans(data) && (tmp & BIT(4)))
327562306a36Sopenharmony_ci		data->has_fan |= BIT(3); /* fan4 enabled */
327662306a36Sopenharmony_ci	if (has_five_fans(data) && (tmp & BIT(5)))
327762306a36Sopenharmony_ci		data->has_fan |= BIT(4); /* fan5 enabled */
327862306a36Sopenharmony_ci	if (has_six_fans(data) && (tmp & BIT(2)))
327962306a36Sopenharmony_ci		data->has_fan |= BIT(5); /* fan6 enabled */
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	/* Fan input pins may be used for alternative functions */
328262306a36Sopenharmony_ci	data->has_fan &= ~sio_data->skip_fan;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	/* Check if pwm5, pwm6 are enabled */
328562306a36Sopenharmony_ci	if (has_six_pwm(data)) {
328662306a36Sopenharmony_ci		/* The following code may be IT8620E specific */
328762306a36Sopenharmony_ci		tmp = it87_read_value(data, IT87_REG_FAN_DIV);
328862306a36Sopenharmony_ci		if ((tmp & 0xc0) == 0xc0)
328962306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(4);
329062306a36Sopenharmony_ci		if (!(tmp & BIT(3)))
329162306a36Sopenharmony_ci			sio_data->skip_pwm |= BIT(5);
329262306a36Sopenharmony_ci	}
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_ci	it87_start_monitoring(data);
329562306a36Sopenharmony_ci}
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci/* Return 1 if and only if the PWM interface is safe to use */
329862306a36Sopenharmony_cistatic int it87_check_pwm(struct device *dev)
329962306a36Sopenharmony_ci{
330062306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
330162306a36Sopenharmony_ci	/*
330262306a36Sopenharmony_ci	 * Some BIOSes fail to correctly configure the IT87 fans. All fans off
330362306a36Sopenharmony_ci	 * and polarity set to active low is sign that this is the case so we
330462306a36Sopenharmony_ci	 * disable pwm control to protect the user.
330562306a36Sopenharmony_ci	 */
330662306a36Sopenharmony_ci	int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	if ((tmp & 0x87) == 0) {
330962306a36Sopenharmony_ci		if (fix_pwm_polarity) {
331062306a36Sopenharmony_ci			/*
331162306a36Sopenharmony_ci			 * The user asks us to attempt a chip reconfiguration.
331262306a36Sopenharmony_ci			 * This means switching to active high polarity and
331362306a36Sopenharmony_ci			 * inverting all fan speed values.
331462306a36Sopenharmony_ci			 */
331562306a36Sopenharmony_ci			int i;
331662306a36Sopenharmony_ci			u8 pwm[3];
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci			for (i = 0; i < ARRAY_SIZE(pwm); i++)
331962306a36Sopenharmony_ci				pwm[i] = it87_read_value(data,
332062306a36Sopenharmony_ci							 IT87_REG_PWM[i]);
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci			/*
332362306a36Sopenharmony_ci			 * If any fan is in automatic pwm mode, the polarity
332462306a36Sopenharmony_ci			 * might be correct, as suspicious as it seems, so we
332562306a36Sopenharmony_ci			 * better don't change anything (but still disable the
332662306a36Sopenharmony_ci			 * PWM interface).
332762306a36Sopenharmony_ci			 */
332862306a36Sopenharmony_ci			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
332962306a36Sopenharmony_ci				dev_info(dev,
333062306a36Sopenharmony_ci					 "Reconfiguring PWM to active high polarity\n");
333162306a36Sopenharmony_ci				it87_write_value(data, IT87_REG_FAN_CTL,
333262306a36Sopenharmony_ci						 tmp | 0x87);
333362306a36Sopenharmony_ci				for (i = 0; i < 3; i++)
333462306a36Sopenharmony_ci					it87_write_value(data,
333562306a36Sopenharmony_ci							 IT87_REG_PWM[i],
333662306a36Sopenharmony_ci							 0x7f & ~pwm[i]);
333762306a36Sopenharmony_ci				return 1;
333862306a36Sopenharmony_ci			}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci			dev_info(dev,
334162306a36Sopenharmony_ci				 "PWM configuration is too broken to be fixed\n");
334262306a36Sopenharmony_ci		}
334362306a36Sopenharmony_ci
334462306a36Sopenharmony_ci		return 0;
334562306a36Sopenharmony_ci	} else if (fix_pwm_polarity) {
334662306a36Sopenharmony_ci		dev_info(dev,
334762306a36Sopenharmony_ci			 "PWM configuration looks sane, won't touch\n");
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci	return 1;
335162306a36Sopenharmony_ci}
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_cistatic int it87_probe(struct platform_device *pdev)
335462306a36Sopenharmony_ci{
335562306a36Sopenharmony_ci	struct it87_data *data;
335662306a36Sopenharmony_ci	struct resource *res;
335762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
335862306a36Sopenharmony_ci	struct it87_sio_data *sio_data = dev_get_platdata(dev);
335962306a36Sopenharmony_ci	int enable_pwm_interface;
336062306a36Sopenharmony_ci	struct device *hwmon_dev;
336162306a36Sopenharmony_ci	int err;
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
336462306a36Sopenharmony_ci	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
336562306a36Sopenharmony_ci				 DRVNAME)) {
336662306a36Sopenharmony_ci		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
336762306a36Sopenharmony_ci			(unsigned long)res->start,
336862306a36Sopenharmony_ci			(unsigned long)(res->start + IT87_EC_EXTENT - 1));
336962306a36Sopenharmony_ci		return -EBUSY;
337062306a36Sopenharmony_ci	}
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
337362306a36Sopenharmony_ci	if (!data)
337462306a36Sopenharmony_ci		return -ENOMEM;
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	data->addr = res->start;
337762306a36Sopenharmony_ci	data->sioaddr = sio_data->sioaddr;
337862306a36Sopenharmony_ci	data->type = sio_data->type;
337962306a36Sopenharmony_ci	data->smbus_bitmap = sio_data->smbus_bitmap;
338062306a36Sopenharmony_ci	data->ec_special_config = sio_data->ec_special_config;
338162306a36Sopenharmony_ci	data->features = it87_devices[sio_data->type].features;
338262306a36Sopenharmony_ci	data->peci_mask = it87_devices[sio_data->type].peci_mask;
338362306a36Sopenharmony_ci	data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
338462306a36Sopenharmony_ci	/*
338562306a36Sopenharmony_ci	 * IT8705F Datasheet 0.4.1, 3h == Version G.
338662306a36Sopenharmony_ci	 * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
338762306a36Sopenharmony_ci	 * These are the first revisions with 16-bit tachometer support.
338862306a36Sopenharmony_ci	 */
338962306a36Sopenharmony_ci	switch (data->type) {
339062306a36Sopenharmony_ci	case it87:
339162306a36Sopenharmony_ci		if (sio_data->revision >= 0x03) {
339262306a36Sopenharmony_ci			data->features &= ~FEAT_OLD_AUTOPWM;
339362306a36Sopenharmony_ci			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS;
339462306a36Sopenharmony_ci		}
339562306a36Sopenharmony_ci		break;
339662306a36Sopenharmony_ci	case it8712:
339762306a36Sopenharmony_ci		if (sio_data->revision >= 0x08) {
339862306a36Sopenharmony_ci			data->features &= ~FEAT_OLD_AUTOPWM;
339962306a36Sopenharmony_ci			data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS |
340062306a36Sopenharmony_ci					  FEAT_FIVE_FANS;
340162306a36Sopenharmony_ci		}
340262306a36Sopenharmony_ci		break;
340362306a36Sopenharmony_ci	default:
340462306a36Sopenharmony_ci		break;
340562306a36Sopenharmony_ci	}
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	platform_set_drvdata(pdev, data);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci	mutex_init(&data->update_lock);
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	err = smbus_disable(data);
341262306a36Sopenharmony_ci	if (err)
341362306a36Sopenharmony_ci		return err;
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	/* Now, we do the remaining detection. */
341662306a36Sopenharmony_ci	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
341762306a36Sopenharmony_ci	    it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
341862306a36Sopenharmony_ci		smbus_enable(data);
341962306a36Sopenharmony_ci		return -ENODEV;
342062306a36Sopenharmony_ci	}
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	/* Check PWM configuration */
342362306a36Sopenharmony_ci	enable_pwm_interface = it87_check_pwm(dev);
342462306a36Sopenharmony_ci	if (!enable_pwm_interface)
342562306a36Sopenharmony_ci		dev_info(dev,
342662306a36Sopenharmony_ci			 "Detected broken BIOS defaults, disabling PWM interface\n");
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	/* Starting with IT8721F, we handle scaling of internal voltages */
342962306a36Sopenharmony_ci	if (has_scaling(data)) {
343062306a36Sopenharmony_ci		if (sio_data->internal & BIT(0))
343162306a36Sopenharmony_ci			data->in_scaled |= BIT(3);	/* in3 is AVCC */
343262306a36Sopenharmony_ci		if (sio_data->internal & BIT(1))
343362306a36Sopenharmony_ci			data->in_scaled |= BIT(7);	/* in7 is VSB */
343462306a36Sopenharmony_ci		if (sio_data->internal & BIT(2))
343562306a36Sopenharmony_ci			data->in_scaled |= BIT(8);	/* in8 is Vbat */
343662306a36Sopenharmony_ci		if (sio_data->internal & BIT(3))
343762306a36Sopenharmony_ci			data->in_scaled |= BIT(9);	/* in9 is AVCC */
343862306a36Sopenharmony_ci	} else if (sio_data->type == it8781 || sio_data->type == it8782 ||
343962306a36Sopenharmony_ci		   sio_data->type == it8783) {
344062306a36Sopenharmony_ci		if (sio_data->internal & BIT(0))
344162306a36Sopenharmony_ci			data->in_scaled |= BIT(3);	/* in3 is VCC5V */
344262306a36Sopenharmony_ci		if (sio_data->internal & BIT(1))
344362306a36Sopenharmony_ci			data->in_scaled |= BIT(7);	/* in7 is VCCH5V */
344462306a36Sopenharmony_ci	}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci	data->has_temp = 0x07;
344762306a36Sopenharmony_ci	if (sio_data->skip_temp & BIT(2)) {
344862306a36Sopenharmony_ci		if (sio_data->type == it8782 &&
344962306a36Sopenharmony_ci		    !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
345062306a36Sopenharmony_ci			data->has_temp &= ~BIT(2);
345162306a36Sopenharmony_ci	}
345262306a36Sopenharmony_ci
345362306a36Sopenharmony_ci	data->in_internal = sio_data->internal;
345462306a36Sopenharmony_ci	data->need_in7_reroute = sio_data->need_in7_reroute;
345562306a36Sopenharmony_ci	data->has_in = 0x3ff & ~sio_data->skip_in;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	if (has_four_temp(data)) {
345862306a36Sopenharmony_ci		data->has_temp |= BIT(3);
345962306a36Sopenharmony_ci	} else if (has_six_temp(data)) {
346062306a36Sopenharmony_ci		u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
346162306a36Sopenharmony_ci
346262306a36Sopenharmony_ci		/* Check for additional temperature sensors */
346362306a36Sopenharmony_ci		if ((reg & 0x03) >= 0x02)
346462306a36Sopenharmony_ci			data->has_temp |= BIT(3);
346562306a36Sopenharmony_ci		if (((reg >> 2) & 0x03) >= 0x02)
346662306a36Sopenharmony_ci			data->has_temp |= BIT(4);
346762306a36Sopenharmony_ci		if (((reg >> 4) & 0x03) >= 0x02)
346862306a36Sopenharmony_ci			data->has_temp |= BIT(5);
346962306a36Sopenharmony_ci
347062306a36Sopenharmony_ci		/* Check for additional voltage sensors */
347162306a36Sopenharmony_ci		if ((reg & 0x03) == 0x01)
347262306a36Sopenharmony_ci			data->has_in |= BIT(10);
347362306a36Sopenharmony_ci		if (((reg >> 2) & 0x03) == 0x01)
347462306a36Sopenharmony_ci			data->has_in |= BIT(11);
347562306a36Sopenharmony_ci		if (((reg >> 4) & 0x03) == 0x01)
347662306a36Sopenharmony_ci			data->has_in |= BIT(12);
347762306a36Sopenharmony_ci	}
347862306a36Sopenharmony_ci
347962306a36Sopenharmony_ci	data->has_beep = !!sio_data->beep_pin;
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ci	/* Initialize the IT87 chip */
348262306a36Sopenharmony_ci	it87_init_device(pdev);
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	smbus_enable(data);
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ci	if (!sio_data->skip_vid) {
348762306a36Sopenharmony_ci		data->has_vid = true;
348862306a36Sopenharmony_ci		data->vrm = vid_which_vrm();
348962306a36Sopenharmony_ci		/* VID reading from Super-I/O config space if available */
349062306a36Sopenharmony_ci		data->vid = sio_data->vid_value;
349162306a36Sopenharmony_ci	}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	/* Prepare for sysfs hooks */
349462306a36Sopenharmony_ci	data->groups[0] = &it87_group;
349562306a36Sopenharmony_ci	data->groups[1] = &it87_group_in;
349662306a36Sopenharmony_ci	data->groups[2] = &it87_group_temp;
349762306a36Sopenharmony_ci	data->groups[3] = &it87_group_fan;
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_ci	if (enable_pwm_interface) {
350062306a36Sopenharmony_ci		data->has_pwm = BIT(ARRAY_SIZE(IT87_REG_PWM)) - 1;
350162306a36Sopenharmony_ci		data->has_pwm &= ~sio_data->skip_pwm;
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci		data->groups[4] = &it87_group_pwm;
350462306a36Sopenharmony_ci		if (has_old_autopwm(data) || has_newer_autopwm(data))
350562306a36Sopenharmony_ci			data->groups[5] = &it87_group_auto_pwm;
350662306a36Sopenharmony_ci	}
350762306a36Sopenharmony_ci
350862306a36Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_groups(dev,
350962306a36Sopenharmony_ci					it87_devices[sio_data->type].name,
351062306a36Sopenharmony_ci					data, data->groups);
351162306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
351262306a36Sopenharmony_ci}
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_cistatic void it87_resume_sio(struct platform_device *pdev)
351562306a36Sopenharmony_ci{
351662306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(&pdev->dev);
351762306a36Sopenharmony_ci	int err;
351862306a36Sopenharmony_ci	int reg2c;
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	if (!data->need_in7_reroute)
352162306a36Sopenharmony_ci		return;
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	err = superio_enter(data->sioaddr);
352462306a36Sopenharmony_ci	if (err) {
352562306a36Sopenharmony_ci		dev_warn(&pdev->dev,
352662306a36Sopenharmony_ci			 "Unable to enter Super I/O to reroute in7 (%d)",
352762306a36Sopenharmony_ci			 err);
352862306a36Sopenharmony_ci		return;
352962306a36Sopenharmony_ci	}
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci	superio_select(data->sioaddr, GPIO);
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci	reg2c = superio_inb(data->sioaddr, IT87_SIO_PINX2_REG);
353462306a36Sopenharmony_ci	if (!(reg2c & BIT(1))) {
353562306a36Sopenharmony_ci		dev_dbg(&pdev->dev,
353662306a36Sopenharmony_ci			"Routing internal VCCH5V to in7 again");
353762306a36Sopenharmony_ci
353862306a36Sopenharmony_ci		reg2c |= BIT(1);
353962306a36Sopenharmony_ci		superio_outb(data->sioaddr, IT87_SIO_PINX2_REG,
354062306a36Sopenharmony_ci			     reg2c);
354162306a36Sopenharmony_ci	}
354262306a36Sopenharmony_ci
354362306a36Sopenharmony_ci	superio_exit(data->sioaddr, has_conf_noexit(data));
354462306a36Sopenharmony_ci}
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_cistatic int it87_resume(struct device *dev)
354762306a36Sopenharmony_ci{
354862306a36Sopenharmony_ci	struct platform_device *pdev = to_platform_device(dev);
354962306a36Sopenharmony_ci	struct it87_data *data = dev_get_drvdata(dev);
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	it87_resume_sio(pdev);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	it87_lock(data);
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	it87_check_pwm(dev);
355662306a36Sopenharmony_ci	it87_check_limit_regs(data);
355762306a36Sopenharmony_ci	it87_check_voltage_monitors_reset(data);
355862306a36Sopenharmony_ci	it87_check_tachometers_reset(pdev);
355962306a36Sopenharmony_ci	it87_check_tachometers_16bit_mode(pdev);
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	it87_start_monitoring(data);
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ci	/* force update */
356462306a36Sopenharmony_ci	data->valid = false;
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	it87_unlock(data);
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	it87_update_device(dev);
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	return 0;
357162306a36Sopenharmony_ci}
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume);
357462306a36Sopenharmony_ci
357562306a36Sopenharmony_cistatic struct platform_driver it87_driver = {
357662306a36Sopenharmony_ci	.driver = {
357762306a36Sopenharmony_ci		.name	= DRVNAME,
357862306a36Sopenharmony_ci		.pm     = pm_sleep_ptr(&it87_dev_pm_ops),
357962306a36Sopenharmony_ci	},
358062306a36Sopenharmony_ci	.probe	= it87_probe,
358162306a36Sopenharmony_ci};
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_cistatic int __init it87_device_add(int index, unsigned short address,
358462306a36Sopenharmony_ci				  const struct it87_sio_data *sio_data)
358562306a36Sopenharmony_ci{
358662306a36Sopenharmony_ci	struct platform_device *pdev;
358762306a36Sopenharmony_ci	struct resource res = {
358862306a36Sopenharmony_ci		.start	= address + IT87_EC_OFFSET,
358962306a36Sopenharmony_ci		.end	= address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,
359062306a36Sopenharmony_ci		.name	= DRVNAME,
359162306a36Sopenharmony_ci		.flags	= IORESOURCE_IO,
359262306a36Sopenharmony_ci	};
359362306a36Sopenharmony_ci	int err;
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci	err = acpi_check_resource_conflict(&res);
359662306a36Sopenharmony_ci	if (err) {
359762306a36Sopenharmony_ci		if (!ignore_resource_conflict)
359862306a36Sopenharmony_ci			return err;
359962306a36Sopenharmony_ci	}
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci	pdev = platform_device_alloc(DRVNAME, address);
360262306a36Sopenharmony_ci	if (!pdev)
360362306a36Sopenharmony_ci		return -ENOMEM;
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	err = platform_device_add_resources(pdev, &res, 1);
360662306a36Sopenharmony_ci	if (err) {
360762306a36Sopenharmony_ci		pr_err("Device resource addition failed (%d)\n", err);
360862306a36Sopenharmony_ci		goto exit_device_put;
360962306a36Sopenharmony_ci	}
361062306a36Sopenharmony_ci
361162306a36Sopenharmony_ci	err = platform_device_add_data(pdev, sio_data,
361262306a36Sopenharmony_ci				       sizeof(struct it87_sio_data));
361362306a36Sopenharmony_ci	if (err) {
361462306a36Sopenharmony_ci		pr_err("Platform data allocation failed\n");
361562306a36Sopenharmony_ci		goto exit_device_put;
361662306a36Sopenharmony_ci	}
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ci	err = platform_device_add(pdev);
361962306a36Sopenharmony_ci	if (err) {
362062306a36Sopenharmony_ci		pr_err("Device addition failed (%d)\n", err);
362162306a36Sopenharmony_ci		goto exit_device_put;
362262306a36Sopenharmony_ci	}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	it87_pdev[index] = pdev;
362562306a36Sopenharmony_ci	return 0;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ciexit_device_put:
362862306a36Sopenharmony_ci	platform_device_put(pdev);
362962306a36Sopenharmony_ci	return err;
363062306a36Sopenharmony_ci}
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ci/* callback function for DMI */
363362306a36Sopenharmony_cistatic int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
363462306a36Sopenharmony_ci{
363562306a36Sopenharmony_ci	dmi_data = dmi_entry->driver_data;
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	if (dmi_data && dmi_data->skip_pwm)
363862306a36Sopenharmony_ci		pr_info("Disabling pwm2 due to hardware constraints\n");
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	return 1;
364162306a36Sopenharmony_ci}
364262306a36Sopenharmony_ci
364362306a36Sopenharmony_ci/*
364462306a36Sopenharmony_ci * On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
364562306a36Sopenharmony_ci * (IT8792E) needs to be in configuration mode before accessing the first
364662306a36Sopenharmony_ci * due to a bug in IT8792E which otherwise results in LPC bus access errors.
364762306a36Sopenharmony_ci * This needs to be done before accessing the first Super-IO chip since
364862306a36Sopenharmony_ci * the second chip may have been accessed prior to loading this driver.
364962306a36Sopenharmony_ci *
365062306a36Sopenharmony_ci * The problem is also reported to affect IT8795E, which is used on X299 boards
365162306a36Sopenharmony_ci * and has the same chip ID as IT8792E (0x8733). It also appears to affect
365262306a36Sopenharmony_ci * systems with IT8790E, which is used on some Z97X-Gaming boards as well as
365362306a36Sopenharmony_ci * Z87X-OC.
365462306a36Sopenharmony_ci * DMI entries for those systems will be added as they become available and
365562306a36Sopenharmony_ci * as the problem is confirmed to affect those boards.
365662306a36Sopenharmony_ci */
365762306a36Sopenharmony_cistatic int it87_sio_force(const struct dmi_system_id *dmi_entry)
365862306a36Sopenharmony_ci{
365962306a36Sopenharmony_ci	__superio_enter(REG_4E);
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci	return it87_dmi_cb(dmi_entry);
366262306a36Sopenharmony_ci};
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_ci/*
366562306a36Sopenharmony_ci * On the Shuttle SN68PT, FAN_CTL2 is apparently not
366662306a36Sopenharmony_ci * connected to a fan, but to something else. One user
366762306a36Sopenharmony_ci * has reported instant system power-off when changing
366862306a36Sopenharmony_ci * the PWM2 duty cycle, so we disable it.
366962306a36Sopenharmony_ci * I use the board name string as the trigger in case
367062306a36Sopenharmony_ci * the same board is ever used in other systems.
367162306a36Sopenharmony_ci */
367262306a36Sopenharmony_cistatic struct it87_dmi_data nvidia_fn68pt = {
367362306a36Sopenharmony_ci	.skip_pwm = BIT(1),
367462306a36Sopenharmony_ci};
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci#define IT87_DMI_MATCH_VND(vendor, name, cb, data) \
367762306a36Sopenharmony_ci	{ \
367862306a36Sopenharmony_ci		.callback = cb, \
367962306a36Sopenharmony_ci		.matches = { \
368062306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \
368162306a36Sopenharmony_ci			DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
368262306a36Sopenharmony_ci		}, \
368362306a36Sopenharmony_ci		.driver_data = data, \
368462306a36Sopenharmony_ci	}
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci#define IT87_DMI_MATCH_GBT(name, cb, data) \
368762306a36Sopenharmony_ci	IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_cistatic const struct dmi_system_id it87_dmi_table[] __initconst = {
369062306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
369162306a36Sopenharmony_ci		/* ? + IT8792E/IT8795E */
369262306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
369362306a36Sopenharmony_ci		/* ? + IT8792E/IT8795E */
369462306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
369562306a36Sopenharmony_ci		/* ? + IT8790E */
369662306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
369762306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
369862306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
369962306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
370062306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
370162306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
370262306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
370362306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
370462306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
370562306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
370662306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
370762306a36Sopenharmony_ci		/* IT8688E + IT8792E/IT8795E */
370862306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
370962306a36Sopenharmony_ci		/* IT8689E + IT87952E */
371062306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
371162306a36Sopenharmony_ci		/* IT8689E + IT87952E */
371262306a36Sopenharmony_ci	IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
371362306a36Sopenharmony_ci		/* IT8689E + IT87952E */
371462306a36Sopenharmony_ci	IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
371562306a36Sopenharmony_ci	{ }
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci};
371862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(dmi, it87_dmi_table);
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_cistatic int __init sm_it87_init(void)
372162306a36Sopenharmony_ci{
372262306a36Sopenharmony_ci	int sioaddr[2] = { REG_2E, REG_4E };
372362306a36Sopenharmony_ci	struct it87_sio_data sio_data;
372462306a36Sopenharmony_ci	unsigned short isa_address[2];
372562306a36Sopenharmony_ci	bool found = false;
372662306a36Sopenharmony_ci	int i, err;
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci	err = platform_driver_register(&it87_driver);
372962306a36Sopenharmony_ci	if (err)
373062306a36Sopenharmony_ci		return err;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	dmi_check_system(it87_dmi_table);
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
373562306a36Sopenharmony_ci		memset(&sio_data, 0, sizeof(struct it87_sio_data));
373662306a36Sopenharmony_ci		isa_address[i] = 0;
373762306a36Sopenharmony_ci		err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i);
373862306a36Sopenharmony_ci		if (err || isa_address[i] == 0)
373962306a36Sopenharmony_ci			continue;
374062306a36Sopenharmony_ci		/*
374162306a36Sopenharmony_ci		 * Don't register second chip if its ISA address matches
374262306a36Sopenharmony_ci		 * the first chip's ISA address.
374362306a36Sopenharmony_ci		 */
374462306a36Sopenharmony_ci		if (i && isa_address[i] == isa_address[0])
374562306a36Sopenharmony_ci			break;
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci		err = it87_device_add(i, isa_address[i], &sio_data);
374862306a36Sopenharmony_ci		if (err)
374962306a36Sopenharmony_ci			goto exit_dev_unregister;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci		found = true;
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci		/*
375462306a36Sopenharmony_ci		 * IT8705F may respond on both SIO addresses.
375562306a36Sopenharmony_ci		 * Stop probing after finding one.
375662306a36Sopenharmony_ci		 */
375762306a36Sopenharmony_ci		if (sio_data.type == it87)
375862306a36Sopenharmony_ci			break;
375962306a36Sopenharmony_ci	}
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	if (!found) {
376262306a36Sopenharmony_ci		err = -ENODEV;
376362306a36Sopenharmony_ci		goto exit_unregister;
376462306a36Sopenharmony_ci	}
376562306a36Sopenharmony_ci	return 0;
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ciexit_dev_unregister:
376862306a36Sopenharmony_ci	/* NULL check handled by platform_device_unregister */
376962306a36Sopenharmony_ci	platform_device_unregister(it87_pdev[0]);
377062306a36Sopenharmony_ciexit_unregister:
377162306a36Sopenharmony_ci	platform_driver_unregister(&it87_driver);
377262306a36Sopenharmony_ci	return err;
377362306a36Sopenharmony_ci}
377462306a36Sopenharmony_ci
377562306a36Sopenharmony_cistatic void __exit sm_it87_exit(void)
377662306a36Sopenharmony_ci{
377762306a36Sopenharmony_ci	/* NULL check handled by platform_device_unregister */
377862306a36Sopenharmony_ci	platform_device_unregister(it87_pdev[1]);
377962306a36Sopenharmony_ci	platform_device_unregister(it87_pdev[0]);
378062306a36Sopenharmony_ci	platform_driver_unregister(&it87_driver);
378162306a36Sopenharmony_ci}
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ciMODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
378462306a36Sopenharmony_ciMODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_cimodule_param_array(force_id, ushort, &force_id_cnt, 0);
378762306a36Sopenharmony_ciMODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)");
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_cimodule_param(ignore_resource_conflict, bool, 0);
379062306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_cimodule_param(update_vbat, bool, 0);
379362306a36Sopenharmony_ciMODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_cimodule_param(fix_pwm_polarity, bool, 0);
379662306a36Sopenharmony_ciMODULE_PARM_DESC(fix_pwm_polarity,
379762306a36Sopenharmony_ci		 "Force PWM polarity to active high (DANGEROUS)");
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_cimodule_init(sm_it87_init);
380262306a36Sopenharmony_cimodule_exit(sm_it87_exit);
3803