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