18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * it87.c - Part of lm_sensors, Linux kernel modules for hardware 48c2ecf20Sopenharmony_ci * monitoring. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * The IT8705F is an LPC-based Super I/O part that contains UARTs, a 78c2ecf20Sopenharmony_ci * parallel port, an IR port, a MIDI port, a floppy controller, etc., in 88c2ecf20Sopenharmony_ci * addition to an Environment Controller (Enhanced Hardware Monitor and 98c2ecf20Sopenharmony_ci * Fan Controller) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This driver supports only the Environment Controller in the IT8705F and 128c2ecf20Sopenharmony_ci * similar parts. The other devices are supported by different drivers. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Supports: IT8603E Super I/O chip w/LPC interface 158c2ecf20Sopenharmony_ci * IT8620E Super I/O chip w/LPC interface 168c2ecf20Sopenharmony_ci * IT8622E Super I/O chip w/LPC interface 178c2ecf20Sopenharmony_ci * IT8623E Super I/O chip w/LPC interface 188c2ecf20Sopenharmony_ci * IT8628E Super I/O chip w/LPC interface 198c2ecf20Sopenharmony_ci * IT8705F Super I/O chip w/LPC interface 208c2ecf20Sopenharmony_ci * IT8712F Super I/O chip w/LPC interface 218c2ecf20Sopenharmony_ci * IT8716F Super I/O chip w/LPC interface 228c2ecf20Sopenharmony_ci * IT8718F Super I/O chip w/LPC interface 238c2ecf20Sopenharmony_ci * IT8720F Super I/O chip w/LPC interface 248c2ecf20Sopenharmony_ci * IT8721F Super I/O chip w/LPC interface 258c2ecf20Sopenharmony_ci * IT8726F Super I/O chip w/LPC interface 268c2ecf20Sopenharmony_ci * IT8728F Super I/O chip w/LPC interface 278c2ecf20Sopenharmony_ci * IT8732F Super I/O chip w/LPC interface 288c2ecf20Sopenharmony_ci * IT8758E Super I/O chip w/LPC interface 298c2ecf20Sopenharmony_ci * IT8771E Super I/O chip w/LPC interface 308c2ecf20Sopenharmony_ci * IT8772E Super I/O chip w/LPC interface 318c2ecf20Sopenharmony_ci * IT8781F Super I/O chip w/LPC interface 328c2ecf20Sopenharmony_ci * IT8782F Super I/O chip w/LPC interface 338c2ecf20Sopenharmony_ci * IT8783E/F Super I/O chip w/LPC interface 348c2ecf20Sopenharmony_ci * IT8786E Super I/O chip w/LPC interface 358c2ecf20Sopenharmony_ci * IT8790E Super I/O chip w/LPC interface 368c2ecf20Sopenharmony_ci * IT8792E Super I/O chip w/LPC interface 378c2ecf20Sopenharmony_ci * Sis950 A clone of the IT8705F 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Copyright (C) 2001 Chris Gauthron 408c2ecf20Sopenharmony_ci * Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.de> 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <linux/bitops.h> 468c2ecf20Sopenharmony_ci#include <linux/module.h> 478c2ecf20Sopenharmony_ci#include <linux/init.h> 488c2ecf20Sopenharmony_ci#include <linux/slab.h> 498c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 508c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 518c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 528c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 538c2ecf20Sopenharmony_ci#include <linux/hwmon-vid.h> 548c2ecf20Sopenharmony_ci#include <linux/err.h> 558c2ecf20Sopenharmony_ci#include <linux/mutex.h> 568c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 578c2ecf20Sopenharmony_ci#include <linux/string.h> 588c2ecf20Sopenharmony_ci#include <linux/dmi.h> 598c2ecf20Sopenharmony_ci#include <linux/acpi.h> 608c2ecf20Sopenharmony_ci#include <linux/io.h> 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define DRVNAME "it87" 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cienum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, 658c2ecf20Sopenharmony_ci it8771, it8772, it8781, it8782, it8783, it8786, it8790, 668c2ecf20Sopenharmony_ci it8792, it8603, it8620, it8622, it8628 }; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic unsigned short force_id; 698c2ecf20Sopenharmony_cimodule_param(force_id, ushort, 0); 708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_id, "Override the detected device ID"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic struct platform_device *it87_pdev[2]; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define REG_2E 0x2e /* The register to read/write */ 758c2ecf20Sopenharmony_ci#define REG_4E 0x4e /* Secondary register to read/write */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define DEV 0x07 /* Register: Logical device select */ 788c2ecf20Sopenharmony_ci#define PME 0x04 /* The device with the fan registers in it */ 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* The device with the IT8718F/IT8720F VID value in it */ 818c2ecf20Sopenharmony_ci#define GPIO 0x07 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define DEVID 0x20 /* Register: Device ID */ 848c2ecf20Sopenharmony_ci#define DEVREV 0x22 /* Register: Device Revision */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline int superio_inb(int ioreg, int reg) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci outb(reg, ioreg); 898c2ecf20Sopenharmony_ci return inb(ioreg + 1); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline void superio_outb(int ioreg, int reg, int val) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci outb(reg, ioreg); 958c2ecf20Sopenharmony_ci outb(val, ioreg + 1); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int superio_inw(int ioreg, int reg) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int val; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci outb(reg++, ioreg); 1038c2ecf20Sopenharmony_ci val = inb(ioreg + 1) << 8; 1048c2ecf20Sopenharmony_ci outb(reg, ioreg); 1058c2ecf20Sopenharmony_ci val |= inb(ioreg + 1); 1068c2ecf20Sopenharmony_ci return val; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void superio_select(int ioreg, int ldn) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci outb(DEV, ioreg); 1128c2ecf20Sopenharmony_ci outb(ldn, ioreg + 1); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic inline int superio_enter(int ioreg) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci /* 1188c2ecf20Sopenharmony_ci * Try to reserve ioreg and ioreg + 1 for exclusive access. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci if (!request_muxed_region(ioreg, 2, DRVNAME)) 1218c2ecf20Sopenharmony_ci return -EBUSY; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci outb(0x87, ioreg); 1248c2ecf20Sopenharmony_ci outb(0x01, ioreg); 1258c2ecf20Sopenharmony_ci outb(0x55, ioreg); 1268c2ecf20Sopenharmony_ci outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg); 1278c2ecf20Sopenharmony_ci return 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic inline void superio_exit(int ioreg) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci outb(0x02, ioreg); 1338c2ecf20Sopenharmony_ci outb(0x02, ioreg + 1); 1348c2ecf20Sopenharmony_ci release_region(ioreg, 2); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Logical device 4 registers */ 1388c2ecf20Sopenharmony_ci#define IT8712F_DEVID 0x8712 1398c2ecf20Sopenharmony_ci#define IT8705F_DEVID 0x8705 1408c2ecf20Sopenharmony_ci#define IT8716F_DEVID 0x8716 1418c2ecf20Sopenharmony_ci#define IT8718F_DEVID 0x8718 1428c2ecf20Sopenharmony_ci#define IT8720F_DEVID 0x8720 1438c2ecf20Sopenharmony_ci#define IT8721F_DEVID 0x8721 1448c2ecf20Sopenharmony_ci#define IT8726F_DEVID 0x8726 1458c2ecf20Sopenharmony_ci#define IT8728F_DEVID 0x8728 1468c2ecf20Sopenharmony_ci#define IT8732F_DEVID 0x8732 1478c2ecf20Sopenharmony_ci#define IT8792E_DEVID 0x8733 1488c2ecf20Sopenharmony_ci#define IT8771E_DEVID 0x8771 1498c2ecf20Sopenharmony_ci#define IT8772E_DEVID 0x8772 1508c2ecf20Sopenharmony_ci#define IT8781F_DEVID 0x8781 1518c2ecf20Sopenharmony_ci#define IT8782F_DEVID 0x8782 1528c2ecf20Sopenharmony_ci#define IT8783E_DEVID 0x8783 1538c2ecf20Sopenharmony_ci#define IT8786E_DEVID 0x8786 1548c2ecf20Sopenharmony_ci#define IT8790E_DEVID 0x8790 1558c2ecf20Sopenharmony_ci#define IT8603E_DEVID 0x8603 1568c2ecf20Sopenharmony_ci#define IT8620E_DEVID 0x8620 1578c2ecf20Sopenharmony_ci#define IT8622E_DEVID 0x8622 1588c2ecf20Sopenharmony_ci#define IT8623E_DEVID 0x8623 1598c2ecf20Sopenharmony_ci#define IT8628E_DEVID 0x8628 1608c2ecf20Sopenharmony_ci#define IT87_ACT_REG 0x30 1618c2ecf20Sopenharmony_ci#define IT87_BASE_REG 0x60 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/* Logical device 7 registers (IT8712F and later) */ 1648c2ecf20Sopenharmony_ci#define IT87_SIO_GPIO1_REG 0x25 1658c2ecf20Sopenharmony_ci#define IT87_SIO_GPIO2_REG 0x26 1668c2ecf20Sopenharmony_ci#define IT87_SIO_GPIO3_REG 0x27 1678c2ecf20Sopenharmony_ci#define IT87_SIO_GPIO4_REG 0x28 1688c2ecf20Sopenharmony_ci#define IT87_SIO_GPIO5_REG 0x29 1698c2ecf20Sopenharmony_ci#define IT87_SIO_PINX1_REG 0x2a /* Pin selection */ 1708c2ecf20Sopenharmony_ci#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */ 1718c2ecf20Sopenharmony_ci#define IT87_SIO_SPI_REG 0xef /* SPI function pin select */ 1728c2ecf20Sopenharmony_ci#define IT87_SIO_VID_REG 0xfc /* VID value */ 1738c2ecf20Sopenharmony_ci#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */ 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci/* Update battery voltage after every reading if true */ 1768c2ecf20Sopenharmony_cistatic bool update_vbat; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* Not all BIOSes properly configure the PWM registers */ 1798c2ecf20Sopenharmony_cistatic bool fix_pwm_polarity; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* Many IT87 constants specified below */ 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/* Length of ISA address segment */ 1848c2ecf20Sopenharmony_ci#define IT87_EXTENT 8 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* Length of ISA address segment for Environmental Controller */ 1878c2ecf20Sopenharmony_ci#define IT87_EC_EXTENT 2 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* Offset of EC registers from ISA base address */ 1908c2ecf20Sopenharmony_ci#define IT87_EC_OFFSET 5 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* Where are the ISA address/data registers relative to the EC base address */ 1938c2ecf20Sopenharmony_ci#define IT87_ADDR_REG_OFFSET 0 1948c2ecf20Sopenharmony_ci#define IT87_DATA_REG_OFFSET 1 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/*----- The IT87 registers -----*/ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#define IT87_REG_CONFIG 0x00 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define IT87_REG_ALARM1 0x01 2018c2ecf20Sopenharmony_ci#define IT87_REG_ALARM2 0x02 2028c2ecf20Sopenharmony_ci#define IT87_REG_ALARM3 0x03 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * The IT8718F and IT8720F have the VID value in a different register, in 2068c2ecf20Sopenharmony_ci * Super-I/O configuration space. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci#define IT87_REG_VID 0x0a 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b 2118c2ecf20Sopenharmony_ci * for fan divisors. Later IT8712F revisions must use 16-bit tachometer 2128c2ecf20Sopenharmony_ci * mode. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci#define IT87_REG_FAN_DIV 0x0b 2158c2ecf20Sopenharmony_ci#define IT87_REG_FAN_16BIT 0x0c 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* 2188c2ecf20Sopenharmony_ci * Monitors: 2198c2ecf20Sopenharmony_ci * - up to 13 voltage (0 to 7, battery, avcc, 10 to 12) 2208c2ecf20Sopenharmony_ci * - up to 6 temp (1 to 6) 2218c2ecf20Sopenharmony_ci * - up to 6 fan (1 to 6) 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c }; 2258c2ecf20Sopenharmony_cistatic const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e }; 2268c2ecf20Sopenharmony_cistatic const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d }; 2278c2ecf20Sopenharmony_cistatic const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f }; 2288c2ecf20Sopenharmony_cistatic const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci#define IT87_REG_FAN_MAIN_CTRL 0x13 2318c2ecf20Sopenharmony_ci#define IT87_REG_FAN_CTL 0x14 2328c2ecf20Sopenharmony_cistatic const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }; 2338c2ecf20Sopenharmony_cistatic const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab }; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 2368c2ecf20Sopenharmony_ci 0x27, 0x28, 0x2f, 0x2c, 0x2d, 0x2e }; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define IT87_REG_TEMP(nr) (0x29 + (nr)) 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#define IT87_REG_VIN_MAX(nr) (0x30 + (nr) * 2) 2418c2ecf20Sopenharmony_ci#define IT87_REG_VIN_MIN(nr) (0x31 + (nr) * 2) 2428c2ecf20Sopenharmony_ci#define IT87_REG_TEMP_HIGH(nr) (0x40 + (nr) * 2) 2438c2ecf20Sopenharmony_ci#define IT87_REG_TEMP_LOW(nr) (0x41 + (nr) * 2) 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci#define IT87_REG_VIN_ENABLE 0x50 2468c2ecf20Sopenharmony_ci#define IT87_REG_TEMP_ENABLE 0x51 2478c2ecf20Sopenharmony_ci#define IT87_REG_TEMP_EXTRA 0x55 2488c2ecf20Sopenharmony_ci#define IT87_REG_BEEP_ENABLE 0x5c 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci#define IT87_REG_CHIPID 0x58 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 }; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define IT87_REG_AUTO_TEMP(nr, i) (IT87_REG_AUTO_BASE[nr] + (i)) 2558c2ecf20Sopenharmony_ci#define IT87_REG_AUTO_PWM(nr, i) (IT87_REG_AUTO_BASE[nr] + 5 + (i)) 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define IT87_REG_TEMP456_ENABLE 0x77 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#define NUM_VIN ARRAY_SIZE(IT87_REG_VIN) 2608c2ecf20Sopenharmony_ci#define NUM_VIN_LIMIT 8 2618c2ecf20Sopenharmony_ci#define NUM_TEMP 6 2628c2ecf20Sopenharmony_ci#define NUM_TEMP_OFFSET ARRAY_SIZE(IT87_REG_TEMP_OFFSET) 2638c2ecf20Sopenharmony_ci#define NUM_TEMP_LIMIT 3 2648c2ecf20Sopenharmony_ci#define NUM_FAN ARRAY_SIZE(IT87_REG_FAN) 2658c2ecf20Sopenharmony_ci#define NUM_FAN_DIV 3 2668c2ecf20Sopenharmony_ci#define NUM_PWM ARRAY_SIZE(IT87_REG_PWM) 2678c2ecf20Sopenharmony_ci#define NUM_AUTO_PWM ARRAY_SIZE(IT87_REG_PWM) 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistruct it87_devices { 2708c2ecf20Sopenharmony_ci const char *name; 2718c2ecf20Sopenharmony_ci const char * const suffix; 2728c2ecf20Sopenharmony_ci u32 features; 2738c2ecf20Sopenharmony_ci u8 peci_mask; 2748c2ecf20Sopenharmony_ci u8 old_peci_mask; 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci#define FEAT_12MV_ADC BIT(0) 2788c2ecf20Sopenharmony_ci#define FEAT_NEWER_AUTOPWM BIT(1) 2798c2ecf20Sopenharmony_ci#define FEAT_OLD_AUTOPWM BIT(2) 2808c2ecf20Sopenharmony_ci#define FEAT_16BIT_FANS BIT(3) 2818c2ecf20Sopenharmony_ci#define FEAT_TEMP_OFFSET BIT(4) 2828c2ecf20Sopenharmony_ci#define FEAT_TEMP_PECI BIT(5) 2838c2ecf20Sopenharmony_ci#define FEAT_TEMP_OLD_PECI BIT(6) 2848c2ecf20Sopenharmony_ci#define FEAT_FAN16_CONFIG BIT(7) /* Need to enable 16-bit fans */ 2858c2ecf20Sopenharmony_ci#define FEAT_FIVE_FANS BIT(8) /* Supports five fans */ 2868c2ecf20Sopenharmony_ci#define FEAT_VID BIT(9) /* Set if chip supports VID */ 2878c2ecf20Sopenharmony_ci#define FEAT_IN7_INTERNAL BIT(10) /* Set if in7 is internal */ 2888c2ecf20Sopenharmony_ci#define FEAT_SIX_FANS BIT(11) /* Supports six fans */ 2898c2ecf20Sopenharmony_ci#define FEAT_10_9MV_ADC BIT(12) 2908c2ecf20Sopenharmony_ci#define FEAT_AVCC3 BIT(13) /* Chip supports in9/AVCC3 */ 2918c2ecf20Sopenharmony_ci#define FEAT_FIVE_PWM BIT(14) /* Chip supports 5 pwm chn */ 2928c2ecf20Sopenharmony_ci#define FEAT_SIX_PWM BIT(15) /* Chip supports 6 pwm chn */ 2938c2ecf20Sopenharmony_ci#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */ 2948c2ecf20Sopenharmony_ci#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */ 2958c2ecf20Sopenharmony_ci#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */ 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic const struct it87_devices it87_devices[] = { 2988c2ecf20Sopenharmony_ci [it87] = { 2998c2ecf20Sopenharmony_ci .name = "it87", 3008c2ecf20Sopenharmony_ci .suffix = "F", 3018c2ecf20Sopenharmony_ci .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */ 3028c2ecf20Sopenharmony_ci }, 3038c2ecf20Sopenharmony_ci [it8712] = { 3048c2ecf20Sopenharmony_ci .name = "it8712", 3058c2ecf20Sopenharmony_ci .suffix = "F", 3068c2ecf20Sopenharmony_ci .features = FEAT_OLD_AUTOPWM | FEAT_VID, 3078c2ecf20Sopenharmony_ci /* may need to overwrite */ 3088c2ecf20Sopenharmony_ci }, 3098c2ecf20Sopenharmony_ci [it8716] = { 3108c2ecf20Sopenharmony_ci .name = "it8716", 3118c2ecf20Sopenharmony_ci .suffix = "F", 3128c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID 3138c2ecf20Sopenharmony_ci | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2, 3148c2ecf20Sopenharmony_ci }, 3158c2ecf20Sopenharmony_ci [it8718] = { 3168c2ecf20Sopenharmony_ci .name = "it8718", 3178c2ecf20Sopenharmony_ci .suffix = "F", 3188c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID 3198c2ecf20Sopenharmony_ci | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS 3208c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 3218c2ecf20Sopenharmony_ci .old_peci_mask = 0x4, 3228c2ecf20Sopenharmony_ci }, 3238c2ecf20Sopenharmony_ci [it8720] = { 3248c2ecf20Sopenharmony_ci .name = "it8720", 3258c2ecf20Sopenharmony_ci .suffix = "F", 3268c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID 3278c2ecf20Sopenharmony_ci | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS 3288c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 3298c2ecf20Sopenharmony_ci .old_peci_mask = 0x4, 3308c2ecf20Sopenharmony_ci }, 3318c2ecf20Sopenharmony_ci [it8721] = { 3328c2ecf20Sopenharmony_ci .name = "it8721", 3338c2ecf20Sopenharmony_ci .suffix = "F", 3348c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 3358c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI 3368c2ecf20Sopenharmony_ci | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL 3378c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 3388c2ecf20Sopenharmony_ci .peci_mask = 0x05, 3398c2ecf20Sopenharmony_ci .old_peci_mask = 0x02, /* Actually reports PCH */ 3408c2ecf20Sopenharmony_ci }, 3418c2ecf20Sopenharmony_ci [it8728] = { 3428c2ecf20Sopenharmony_ci .name = "it8728", 3438c2ecf20Sopenharmony_ci .suffix = "F", 3448c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 3458c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS 3468c2ecf20Sopenharmony_ci | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2, 3478c2ecf20Sopenharmony_ci .peci_mask = 0x07, 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci [it8732] = { 3508c2ecf20Sopenharmony_ci .name = "it8732", 3518c2ecf20Sopenharmony_ci .suffix = "F", 3528c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS 3538c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI 3548c2ecf20Sopenharmony_ci | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, 3558c2ecf20Sopenharmony_ci .peci_mask = 0x07, 3568c2ecf20Sopenharmony_ci .old_peci_mask = 0x02, /* Actually reports PCH */ 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci [it8771] = { 3598c2ecf20Sopenharmony_ci .name = "it8771", 3608c2ecf20Sopenharmony_ci .suffix = "E", 3618c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 3628c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL 3638c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 3648c2ecf20Sopenharmony_ci /* PECI: guesswork */ 3658c2ecf20Sopenharmony_ci /* 12mV ADC (OHM) */ 3668c2ecf20Sopenharmony_ci /* 16 bit fans (OHM) */ 3678c2ecf20Sopenharmony_ci /* three fans, always 16 bit (guesswork) */ 3688c2ecf20Sopenharmony_ci .peci_mask = 0x07, 3698c2ecf20Sopenharmony_ci }, 3708c2ecf20Sopenharmony_ci [it8772] = { 3718c2ecf20Sopenharmony_ci .name = "it8772", 3728c2ecf20Sopenharmony_ci .suffix = "E", 3738c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 3748c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL 3758c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 3768c2ecf20Sopenharmony_ci /* PECI (coreboot) */ 3778c2ecf20Sopenharmony_ci /* 12mV ADC (HWSensors4, OHM) */ 3788c2ecf20Sopenharmony_ci /* 16 bit fans (HWSensors4, OHM) */ 3798c2ecf20Sopenharmony_ci /* three fans, always 16 bit (datasheet) */ 3808c2ecf20Sopenharmony_ci .peci_mask = 0x07, 3818c2ecf20Sopenharmony_ci }, 3828c2ecf20Sopenharmony_ci [it8781] = { 3838c2ecf20Sopenharmony_ci .name = "it8781", 3848c2ecf20Sopenharmony_ci .suffix = "F", 3858c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET 3868c2ecf20Sopenharmony_ci | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, 3878c2ecf20Sopenharmony_ci .old_peci_mask = 0x4, 3888c2ecf20Sopenharmony_ci }, 3898c2ecf20Sopenharmony_ci [it8782] = { 3908c2ecf20Sopenharmony_ci .name = "it8782", 3918c2ecf20Sopenharmony_ci .suffix = "F", 3928c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET 3938c2ecf20Sopenharmony_ci | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, 3948c2ecf20Sopenharmony_ci .old_peci_mask = 0x4, 3958c2ecf20Sopenharmony_ci }, 3968c2ecf20Sopenharmony_ci [it8783] = { 3978c2ecf20Sopenharmony_ci .name = "it8783", 3988c2ecf20Sopenharmony_ci .suffix = "E/F", 3998c2ecf20Sopenharmony_ci .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET 4008c2ecf20Sopenharmony_ci | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2, 4018c2ecf20Sopenharmony_ci .old_peci_mask = 0x4, 4028c2ecf20Sopenharmony_ci }, 4038c2ecf20Sopenharmony_ci [it8786] = { 4048c2ecf20Sopenharmony_ci .name = "it8786", 4058c2ecf20Sopenharmony_ci .suffix = "E", 4068c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4078c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL 4088c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 4098c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4108c2ecf20Sopenharmony_ci }, 4118c2ecf20Sopenharmony_ci [it8790] = { 4128c2ecf20Sopenharmony_ci .name = "it8790", 4138c2ecf20Sopenharmony_ci .suffix = "E", 4148c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4158c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL 4168c2ecf20Sopenharmony_ci | FEAT_PWM_FREQ2, 4178c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci [it8792] = { 4208c2ecf20Sopenharmony_ci .name = "it8792", 4218c2ecf20Sopenharmony_ci .suffix = "E", 4228c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS 4238c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI 4248c2ecf20Sopenharmony_ci | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, 4258c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4268c2ecf20Sopenharmony_ci .old_peci_mask = 0x02, /* Actually reports PCH */ 4278c2ecf20Sopenharmony_ci }, 4288c2ecf20Sopenharmony_ci [it8603] = { 4298c2ecf20Sopenharmony_ci .name = "it8603", 4308c2ecf20Sopenharmony_ci .suffix = "E", 4318c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4328c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL 4338c2ecf20Sopenharmony_ci | FEAT_AVCC3 | FEAT_PWM_FREQ2, 4348c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4358c2ecf20Sopenharmony_ci }, 4368c2ecf20Sopenharmony_ci [it8620] = { 4378c2ecf20Sopenharmony_ci .name = "it8620", 4388c2ecf20Sopenharmony_ci .suffix = "E", 4398c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4408c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS 4418c2ecf20Sopenharmony_ci | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 4428c2ecf20Sopenharmony_ci | FEAT_SIX_TEMP | FEAT_VIN3_5V, 4438c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4448c2ecf20Sopenharmony_ci }, 4458c2ecf20Sopenharmony_ci [it8622] = { 4468c2ecf20Sopenharmony_ci .name = "it8622", 4478c2ecf20Sopenharmony_ci .suffix = "E", 4488c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4498c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS 4508c2ecf20Sopenharmony_ci | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 4518c2ecf20Sopenharmony_ci | FEAT_AVCC3 | FEAT_VIN3_5V, 4528c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4538c2ecf20Sopenharmony_ci }, 4548c2ecf20Sopenharmony_ci [it8628] = { 4558c2ecf20Sopenharmony_ci .name = "it8628", 4568c2ecf20Sopenharmony_ci .suffix = "E", 4578c2ecf20Sopenharmony_ci .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS 4588c2ecf20Sopenharmony_ci | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS 4598c2ecf20Sopenharmony_ci | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 4608c2ecf20Sopenharmony_ci | FEAT_SIX_TEMP | FEAT_VIN3_5V, 4618c2ecf20Sopenharmony_ci .peci_mask = 0x07, 4628c2ecf20Sopenharmony_ci }, 4638c2ecf20Sopenharmony_ci}; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) 4668c2ecf20Sopenharmony_ci#define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) 4678c2ecf20Sopenharmony_ci#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC) 4688c2ecf20Sopenharmony_ci#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) 4698c2ecf20Sopenharmony_ci#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) 4708c2ecf20Sopenharmony_ci#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) 4718c2ecf20Sopenharmony_ci#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \ 4728c2ecf20Sopenharmony_ci ((data)->peci_mask & BIT(nr))) 4738c2ecf20Sopenharmony_ci#define has_temp_old_peci(data, nr) \ 4748c2ecf20Sopenharmony_ci (((data)->features & FEAT_TEMP_OLD_PECI) && \ 4758c2ecf20Sopenharmony_ci ((data)->old_peci_mask & BIT(nr))) 4768c2ecf20Sopenharmony_ci#define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG) 4778c2ecf20Sopenharmony_ci#define has_five_fans(data) ((data)->features & (FEAT_FIVE_FANS | \ 4788c2ecf20Sopenharmony_ci FEAT_SIX_FANS)) 4798c2ecf20Sopenharmony_ci#define has_vid(data) ((data)->features & FEAT_VID) 4808c2ecf20Sopenharmony_ci#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) 4818c2ecf20Sopenharmony_ci#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS) 4828c2ecf20Sopenharmony_ci#define has_avcc3(data) ((data)->features & FEAT_AVCC3) 4838c2ecf20Sopenharmony_ci#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \ 4848c2ecf20Sopenharmony_ci | FEAT_SIX_PWM)) 4858c2ecf20Sopenharmony_ci#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) 4868c2ecf20Sopenharmony_ci#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) 4878c2ecf20Sopenharmony_ci#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP) 4888c2ecf20Sopenharmony_ci#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V) 4898c2ecf20Sopenharmony_ci#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \ 4908c2ecf20Sopenharmony_ci FEAT_10_9MV_ADC)) 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistruct it87_sio_data { 4938c2ecf20Sopenharmony_ci int sioaddr; 4948c2ecf20Sopenharmony_ci enum chips type; 4958c2ecf20Sopenharmony_ci /* Values read from Super-I/O config space */ 4968c2ecf20Sopenharmony_ci u8 revision; 4978c2ecf20Sopenharmony_ci u8 vid_value; 4988c2ecf20Sopenharmony_ci u8 beep_pin; 4998c2ecf20Sopenharmony_ci u8 internal; /* Internal sensors can be labeled */ 5008c2ecf20Sopenharmony_ci bool need_in7_reroute; 5018c2ecf20Sopenharmony_ci /* Features skipped based on config or DMI */ 5028c2ecf20Sopenharmony_ci u16 skip_in; 5038c2ecf20Sopenharmony_ci u8 skip_vid; 5048c2ecf20Sopenharmony_ci u8 skip_fan; 5058c2ecf20Sopenharmony_ci u8 skip_pwm; 5068c2ecf20Sopenharmony_ci u8 skip_temp; 5078c2ecf20Sopenharmony_ci}; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/* 5108c2ecf20Sopenharmony_ci * For each registered chip, we need to keep some data in memory. 5118c2ecf20Sopenharmony_ci * The structure is dynamically allocated. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_cistruct it87_data { 5148c2ecf20Sopenharmony_ci const struct attribute_group *groups[7]; 5158c2ecf20Sopenharmony_ci int sioaddr; 5168c2ecf20Sopenharmony_ci enum chips type; 5178c2ecf20Sopenharmony_ci u32 features; 5188c2ecf20Sopenharmony_ci u8 peci_mask; 5198c2ecf20Sopenharmony_ci u8 old_peci_mask; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci unsigned short addr; 5228c2ecf20Sopenharmony_ci const char *name; 5238c2ecf20Sopenharmony_ci struct mutex update_lock; 5248c2ecf20Sopenharmony_ci char valid; /* !=0 if following fields are valid */ 5258c2ecf20Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci u16 in_scaled; /* Internal voltage sensors are scaled */ 5288c2ecf20Sopenharmony_ci u16 in_internal; /* Bitfield, internal sensors (for labels) */ 5298c2ecf20Sopenharmony_ci u16 has_in; /* Bitfield, voltage sensors enabled */ 5308c2ecf20Sopenharmony_ci u8 in[NUM_VIN][3]; /* [nr][0]=in, [1]=min, [2]=max */ 5318c2ecf20Sopenharmony_ci bool need_in7_reroute; 5328c2ecf20Sopenharmony_ci u8 has_fan; /* Bitfield, fans enabled */ 5338c2ecf20Sopenharmony_ci u16 fan[NUM_FAN][2]; /* Register values, [nr][0]=fan, [1]=min */ 5348c2ecf20Sopenharmony_ci u8 has_temp; /* Bitfield, temp sensors enabled */ 5358c2ecf20Sopenharmony_ci s8 temp[NUM_TEMP][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */ 5368c2ecf20Sopenharmony_ci u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */ 5378c2ecf20Sopenharmony_ci u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */ 5388c2ecf20Sopenharmony_ci u8 fan_div[NUM_FAN_DIV];/* Register encoding, shifted right */ 5398c2ecf20Sopenharmony_ci bool has_vid; /* True if VID supported */ 5408c2ecf20Sopenharmony_ci u8 vid; /* Register encoding, combined */ 5418c2ecf20Sopenharmony_ci u8 vrm; 5428c2ecf20Sopenharmony_ci u32 alarms; /* Register encoding, combined */ 5438c2ecf20Sopenharmony_ci bool has_beep; /* true if beep supported */ 5448c2ecf20Sopenharmony_ci u8 beeps; /* Register encoding */ 5458c2ecf20Sopenharmony_ci u8 fan_main_ctrl; /* Register value */ 5468c2ecf20Sopenharmony_ci u8 fan_ctl; /* Register value */ 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* 5498c2ecf20Sopenharmony_ci * The following 3 arrays correspond to the same registers up to 5508c2ecf20Sopenharmony_ci * the IT8720F. The meaning of bits 6-0 depends on the value of bit 5518c2ecf20Sopenharmony_ci * 7, and we want to preserve settings on mode changes, so we have 5528c2ecf20Sopenharmony_ci * to track all values separately. 5538c2ecf20Sopenharmony_ci * Starting with the IT8721F, the manual PWM duty cycles are stored 5548c2ecf20Sopenharmony_ci * in separate registers (8-bit values), so the separate tracking 5558c2ecf20Sopenharmony_ci * is no longer needed, but it is still done to keep the driver 5568c2ecf20Sopenharmony_ci * simple. 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci u8 has_pwm; /* Bitfield, pwm control enabled */ 5598c2ecf20Sopenharmony_ci u8 pwm_ctrl[NUM_PWM]; /* Register value */ 5608c2ecf20Sopenharmony_ci u8 pwm_duty[NUM_PWM]; /* Manual PWM value set by user */ 5618c2ecf20Sopenharmony_ci u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci /* Automatic fan speed control registers */ 5648c2ecf20Sopenharmony_ci u8 auto_pwm[NUM_AUTO_PWM][4]; /* [nr][3] is hard-coded */ 5658c2ecf20Sopenharmony_ci s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */ 5668c2ecf20Sopenharmony_ci}; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int adc_lsb(const struct it87_data *data, int nr) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci int lsb; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (has_12mv_adc(data)) 5738c2ecf20Sopenharmony_ci lsb = 120; 5748c2ecf20Sopenharmony_ci else if (has_10_9mv_adc(data)) 5758c2ecf20Sopenharmony_ci lsb = 109; 5768c2ecf20Sopenharmony_ci else 5778c2ecf20Sopenharmony_ci lsb = 160; 5788c2ecf20Sopenharmony_ci if (data->in_scaled & BIT(nr)) 5798c2ecf20Sopenharmony_ci lsb <<= 1; 5808c2ecf20Sopenharmony_ci return lsb; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic u8 in_to_reg(const struct it87_data *data, int nr, long val) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci val = DIV_ROUND_CLOSEST(val * 10, adc_lsb(data, nr)); 5868c2ecf20Sopenharmony_ci return clamp_val(val, 0, 255); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int in_from_reg(const struct it87_data *data, int nr, int val) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci return DIV_ROUND_CLOSEST(val * adc_lsb(data, nr), 10); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic inline u8 FAN_TO_REG(long rpm, int div) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci if (rpm == 0) 5978c2ecf20Sopenharmony_ci return 255; 5988c2ecf20Sopenharmony_ci rpm = clamp_val(rpm, 1, 1000000); 5998c2ecf20Sopenharmony_ci return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_cistatic inline u16 FAN16_TO_REG(long rpm) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci if (rpm == 0) 6058c2ecf20Sopenharmony_ci return 0xffff; 6068c2ecf20Sopenharmony_ci return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe); 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci#define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \ 6108c2ecf20Sopenharmony_ci 1350000 / ((val) * (div))) 6118c2ecf20Sopenharmony_ci/* The divider is fixed to 2 in 16-bit mode */ 6128c2ecf20Sopenharmony_ci#define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ 6138c2ecf20Sopenharmony_ci 1350000 / ((val) * 2)) 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \ 6168c2ecf20Sopenharmony_ci ((val) + 500) / 1000), -128, 127)) 6178c2ecf20Sopenharmony_ci#define TEMP_FROM_REG(val) ((val) * 1000) 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic u8 pwm_to_reg(const struct it87_data *data, long val) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) 6228c2ecf20Sopenharmony_ci return val; 6238c2ecf20Sopenharmony_ci else 6248c2ecf20Sopenharmony_ci return val >> 1; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic int pwm_from_reg(const struct it87_data *data, u8 reg) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) 6308c2ecf20Sopenharmony_ci return reg; 6318c2ecf20Sopenharmony_ci else 6328c2ecf20Sopenharmony_ci return (reg & 0x7f) << 1; 6338c2ecf20Sopenharmony_ci} 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_cistatic int DIV_TO_REG(int val) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci int answer = 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci while (answer < 7 && (val >>= 1)) 6408c2ecf20Sopenharmony_ci answer++; 6418c2ecf20Sopenharmony_ci return answer; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci#define DIV_FROM_REG(val) BIT(val) 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci/* 6478c2ecf20Sopenharmony_ci * PWM base frequencies. The frequency has to be divided by either 128 or 256, 6488c2ecf20Sopenharmony_ci * depending on the chip type, to calculate the actual PWM frequency. 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * Some of the chip datasheets suggest a base frequency of 51 kHz instead 6518c2ecf20Sopenharmony_ci * of 750 kHz for the slowest base frequency, resulting in a PWM frequency 6528c2ecf20Sopenharmony_ci * of 200 Hz. Sometimes both PWM frequency select registers are affected, 6538c2ecf20Sopenharmony_ci * sometimes just one. It is unknown if this is a datasheet error or real, 6548c2ecf20Sopenharmony_ci * so this is ignored for now. 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_cistatic const unsigned int pwm_freq[8] = { 6578c2ecf20Sopenharmony_ci 48000000, 6588c2ecf20Sopenharmony_ci 24000000, 6598c2ecf20Sopenharmony_ci 12000000, 6608c2ecf20Sopenharmony_ci 8000000, 6618c2ecf20Sopenharmony_ci 6000000, 6628c2ecf20Sopenharmony_ci 3000000, 6638c2ecf20Sopenharmony_ci 1500000, 6648c2ecf20Sopenharmony_ci 750000, 6658c2ecf20Sopenharmony_ci}; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci/* 6688c2ecf20Sopenharmony_ci * Must be called with data->update_lock held, except during initialization. 6698c2ecf20Sopenharmony_ci * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, 6708c2ecf20Sopenharmony_ci * would slow down the IT87 access and should not be necessary. 6718c2ecf20Sopenharmony_ci */ 6728c2ecf20Sopenharmony_cistatic int it87_read_value(struct it87_data *data, u8 reg) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); 6758c2ecf20Sopenharmony_ci return inb_p(data->addr + IT87_DATA_REG_OFFSET); 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/* 6798c2ecf20Sopenharmony_ci * Must be called with data->update_lock held, except during initialization. 6808c2ecf20Sopenharmony_ci * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks, 6818c2ecf20Sopenharmony_ci * would slow down the IT87 access and should not be necessary. 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_cistatic void it87_write_value(struct it87_data *data, u8 reg, u8 value) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET); 6868c2ecf20Sopenharmony_ci outb_p(value, data->addr + IT87_DATA_REG_OFFSET); 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic void it87_update_pwm_ctrl(struct it87_data *data, int nr) 6908c2ecf20Sopenharmony_ci{ 6918c2ecf20Sopenharmony_ci data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]); 6928c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) { 6938c2ecf20Sopenharmony_ci data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; 6948c2ecf20Sopenharmony_ci data->pwm_duty[nr] = it87_read_value(data, 6958c2ecf20Sopenharmony_ci IT87_REG_PWM_DUTY[nr]); 6968c2ecf20Sopenharmony_ci } else { 6978c2ecf20Sopenharmony_ci if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ 6988c2ecf20Sopenharmony_ci data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03; 6998c2ecf20Sopenharmony_ci else /* Manual mode */ 7008c2ecf20Sopenharmony_ci data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (has_old_autopwm(data)) { 7048c2ecf20Sopenharmony_ci int i; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci for (i = 0; i < 5 ; i++) 7078c2ecf20Sopenharmony_ci data->auto_temp[nr][i] = it87_read_value(data, 7088c2ecf20Sopenharmony_ci IT87_REG_AUTO_TEMP(nr, i)); 7098c2ecf20Sopenharmony_ci for (i = 0; i < 3 ; i++) 7108c2ecf20Sopenharmony_ci data->auto_pwm[nr][i] = it87_read_value(data, 7118c2ecf20Sopenharmony_ci IT87_REG_AUTO_PWM(nr, i)); 7128c2ecf20Sopenharmony_ci } else if (has_newer_autopwm(data)) { 7138c2ecf20Sopenharmony_ci int i; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* 7168c2ecf20Sopenharmony_ci * 0: temperature hysteresis (base + 5) 7178c2ecf20Sopenharmony_ci * 1: fan off temperature (base + 0) 7188c2ecf20Sopenharmony_ci * 2: fan start temperature (base + 1) 7198c2ecf20Sopenharmony_ci * 3: fan max temperature (base + 2) 7208c2ecf20Sopenharmony_ci */ 7218c2ecf20Sopenharmony_ci data->auto_temp[nr][0] = 7228c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 5)); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci for (i = 0; i < 3 ; i++) 7258c2ecf20Sopenharmony_ci data->auto_temp[nr][i + 1] = 7268c2ecf20Sopenharmony_ci it87_read_value(data, 7278c2ecf20Sopenharmony_ci IT87_REG_AUTO_TEMP(nr, i)); 7288c2ecf20Sopenharmony_ci /* 7298c2ecf20Sopenharmony_ci * 0: start pwm value (base + 3) 7308c2ecf20Sopenharmony_ci * 1: pwm slope (base + 4, 1/8th pwm) 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ci data->auto_pwm[nr][0] = 7338c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 3)); 7348c2ecf20Sopenharmony_ci data->auto_pwm[nr][1] = 7358c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_AUTO_TEMP(nr, 4)); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic struct it87_data *it87_update_device(struct device *dev) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 7428c2ecf20Sopenharmony_ci int i; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || 7478c2ecf20Sopenharmony_ci !data->valid) { 7488c2ecf20Sopenharmony_ci if (update_vbat) { 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * Cleared after each update, so reenable. Value 7518c2ecf20Sopenharmony_ci * returned by this read will be previous value 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_CONFIG, 7548c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_CONFIG) | 0x40); 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci for (i = 0; i < NUM_VIN; i++) { 7578c2ecf20Sopenharmony_ci if (!(data->has_in & BIT(i))) 7588c2ecf20Sopenharmony_ci continue; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci data->in[i][0] = 7618c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_VIN[i]); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* VBAT and AVCC don't have limit registers */ 7648c2ecf20Sopenharmony_ci if (i >= NUM_VIN_LIMIT) 7658c2ecf20Sopenharmony_ci continue; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci data->in[i][1] = 7688c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_VIN_MIN(i)); 7698c2ecf20Sopenharmony_ci data->in[i][2] = 7708c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_VIN_MAX(i)); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FAN; i++) { 7748c2ecf20Sopenharmony_ci /* Skip disabled fans */ 7758c2ecf20Sopenharmony_ci if (!(data->has_fan & BIT(i))) 7768c2ecf20Sopenharmony_ci continue; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci data->fan[i][1] = 7798c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_FAN_MIN[i]); 7808c2ecf20Sopenharmony_ci data->fan[i][0] = it87_read_value(data, 7818c2ecf20Sopenharmony_ci IT87_REG_FAN[i]); 7828c2ecf20Sopenharmony_ci /* Add high byte if in 16-bit mode */ 7838c2ecf20Sopenharmony_ci if (has_16bit_fans(data)) { 7848c2ecf20Sopenharmony_ci data->fan[i][0] |= it87_read_value(data, 7858c2ecf20Sopenharmony_ci IT87_REG_FANX[i]) << 8; 7868c2ecf20Sopenharmony_ci data->fan[i][1] |= it87_read_value(data, 7878c2ecf20Sopenharmony_ci IT87_REG_FANX_MIN[i]) << 8; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TEMP; i++) { 7918c2ecf20Sopenharmony_ci if (!(data->has_temp & BIT(i))) 7928c2ecf20Sopenharmony_ci continue; 7938c2ecf20Sopenharmony_ci data->temp[i][0] = 7948c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_TEMP(i)); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (has_temp_offset(data) && i < NUM_TEMP_OFFSET) 7978c2ecf20Sopenharmony_ci data->temp[i][3] = 7988c2ecf20Sopenharmony_ci it87_read_value(data, 7998c2ecf20Sopenharmony_ci IT87_REG_TEMP_OFFSET[i]); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (i >= NUM_TEMP_LIMIT) 8028c2ecf20Sopenharmony_ci continue; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci data->temp[i][1] = 8058c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_TEMP_LOW(i)); 8068c2ecf20Sopenharmony_ci data->temp[i][2] = 8078c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_TEMP_HIGH(i)); 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Newer chips don't have clock dividers */ 8118c2ecf20Sopenharmony_ci if ((data->has_fan & 0x07) && !has_16bit_fans(data)) { 8128c2ecf20Sopenharmony_ci i = it87_read_value(data, IT87_REG_FAN_DIV); 8138c2ecf20Sopenharmony_ci data->fan_div[0] = i & 0x07; 8148c2ecf20Sopenharmony_ci data->fan_div[1] = (i >> 3) & 0x07; 8158c2ecf20Sopenharmony_ci data->fan_div[2] = (i & 0x40) ? 3 : 1; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci data->alarms = 8198c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_ALARM1) | 8208c2ecf20Sopenharmony_ci (it87_read_value(data, IT87_REG_ALARM2) << 8) | 8218c2ecf20Sopenharmony_ci (it87_read_value(data, IT87_REG_ALARM3) << 16); 8228c2ecf20Sopenharmony_ci data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci data->fan_main_ctrl = it87_read_value(data, 8258c2ecf20Sopenharmony_ci IT87_REG_FAN_MAIN_CTRL); 8268c2ecf20Sopenharmony_ci data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL); 8278c2ecf20Sopenharmony_ci for (i = 0; i < NUM_PWM; i++) { 8288c2ecf20Sopenharmony_ci if (!(data->has_pwm & BIT(i))) 8298c2ecf20Sopenharmony_ci continue; 8308c2ecf20Sopenharmony_ci it87_update_pwm_ctrl(data, i); 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); 8348c2ecf20Sopenharmony_ci data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * The IT8705F does not have VID capability. 8378c2ecf20Sopenharmony_ci * The IT8718F and later don't use IT87_REG_VID for the 8388c2ecf20Sopenharmony_ci * same purpose. 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci if (data->type == it8712 || data->type == it8716) { 8418c2ecf20Sopenharmony_ci data->vid = it87_read_value(data, IT87_REG_VID); 8428c2ecf20Sopenharmony_ci /* 8438c2ecf20Sopenharmony_ci * The older IT8712F revisions had only 5 VID pins, 8448c2ecf20Sopenharmony_ci * but we assume it is always safe to read 6 bits. 8458c2ecf20Sopenharmony_ci */ 8468c2ecf20Sopenharmony_ci data->vid &= 0x3f; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci data->last_updated = jiffies; 8498c2ecf20Sopenharmony_ci data->valid = 1; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci return data; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic ssize_t show_in(struct device *dev, struct device_attribute *attr, 8588c2ecf20Sopenharmony_ci char *buf) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 8618c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 8628c2ecf20Sopenharmony_ci int index = sattr->index; 8638c2ecf20Sopenharmony_ci int nr = sattr->nr; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index])); 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic ssize_t set_in(struct device *dev, struct device_attribute *attr, 8698c2ecf20Sopenharmony_ci const char *buf, size_t count) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 8728c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 8738c2ecf20Sopenharmony_ci int index = sattr->index; 8748c2ecf20Sopenharmony_ci int nr = sattr->nr; 8758c2ecf20Sopenharmony_ci unsigned long val; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 8788c2ecf20Sopenharmony_ci return -EINVAL; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 8818c2ecf20Sopenharmony_ci data->in[nr][index] = in_to_reg(data, nr, val); 8828c2ecf20Sopenharmony_ci it87_write_value(data, 8838c2ecf20Sopenharmony_ci index == 1 ? IT87_REG_VIN_MIN(nr) 8848c2ecf20Sopenharmony_ci : IT87_REG_VIN_MAX(nr), 8858c2ecf20Sopenharmony_ci data->in[nr][index]); 8868c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8878c2ecf20Sopenharmony_ci return count; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0); 8918c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in, 8928c2ecf20Sopenharmony_ci 0, 1); 8938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in, 8948c2ecf20Sopenharmony_ci 0, 2); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0); 8978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in, 8988c2ecf20Sopenharmony_ci 1, 1); 8998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in, 9008c2ecf20Sopenharmony_ci 1, 2); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0); 9038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in, 9048c2ecf20Sopenharmony_ci 2, 1); 9058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in, 9068c2ecf20Sopenharmony_ci 2, 2); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0); 9098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in, 9108c2ecf20Sopenharmony_ci 3, 1); 9118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in, 9128c2ecf20Sopenharmony_ci 3, 2); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0); 9158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in, 9168c2ecf20Sopenharmony_ci 4, 1); 9178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in, 9188c2ecf20Sopenharmony_ci 4, 2); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0); 9218c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in, 9228c2ecf20Sopenharmony_ci 5, 1); 9238c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in, 9248c2ecf20Sopenharmony_ci 5, 2); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0); 9278c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in, 9288c2ecf20Sopenharmony_ci 6, 1); 9298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in, 9308c2ecf20Sopenharmony_ci 6, 2); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0); 9338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in, 9348c2ecf20Sopenharmony_ci 7, 1); 9358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in, 9368c2ecf20Sopenharmony_ci 7, 2); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0); 9398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0); 9408c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in, NULL, 10, 0); 9418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in, NULL, 11, 0); 9428c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in, NULL, 12, 0); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci/* Up to 6 temperatures */ 9458c2ecf20Sopenharmony_cistatic ssize_t show_temp(struct device *dev, struct device_attribute *attr, 9468c2ecf20Sopenharmony_ci char *buf) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 9498c2ecf20Sopenharmony_ci int nr = sattr->nr; 9508c2ecf20Sopenharmony_ci int index = sattr->index; 9518c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic ssize_t set_temp(struct device *dev, struct device_attribute *attr, 9578c2ecf20Sopenharmony_ci const char *buf, size_t count) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 9608c2ecf20Sopenharmony_ci int nr = sattr->nr; 9618c2ecf20Sopenharmony_ci int index = sattr->index; 9628c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 9638c2ecf20Sopenharmony_ci long val; 9648c2ecf20Sopenharmony_ci u8 reg, regval; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0) 9678c2ecf20Sopenharmony_ci return -EINVAL; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci switch (index) { 9728c2ecf20Sopenharmony_ci default: 9738c2ecf20Sopenharmony_ci case 1: 9748c2ecf20Sopenharmony_ci reg = IT87_REG_TEMP_LOW(nr); 9758c2ecf20Sopenharmony_ci break; 9768c2ecf20Sopenharmony_ci case 2: 9778c2ecf20Sopenharmony_ci reg = IT87_REG_TEMP_HIGH(nr); 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci case 3: 9808c2ecf20Sopenharmony_ci regval = it87_read_value(data, IT87_REG_BEEP_ENABLE); 9818c2ecf20Sopenharmony_ci if (!(regval & 0x80)) { 9828c2ecf20Sopenharmony_ci regval |= 0x80; 9838c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_BEEP_ENABLE, regval); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci data->valid = 0; 9868c2ecf20Sopenharmony_ci reg = IT87_REG_TEMP_OFFSET[nr]; 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci data->temp[nr][index] = TEMP_TO_REG(val); 9918c2ecf20Sopenharmony_ci it87_write_value(data, reg, data->temp[nr][index]); 9928c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 9938c2ecf20Sopenharmony_ci return count; 9948c2ecf20Sopenharmony_ci} 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); 9978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, 9988c2ecf20Sopenharmony_ci 0, 1); 9998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, 10008c2ecf20Sopenharmony_ci 0, 2); 10018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp, 10028c2ecf20Sopenharmony_ci set_temp, 0, 3); 10038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0); 10048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, 10058c2ecf20Sopenharmony_ci 1, 1); 10068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, 10078c2ecf20Sopenharmony_ci 1, 2); 10088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp, 10098c2ecf20Sopenharmony_ci set_temp, 1, 3); 10108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0); 10118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, 10128c2ecf20Sopenharmony_ci 2, 1); 10138c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, 10148c2ecf20Sopenharmony_ci 2, 2); 10158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp, 10168c2ecf20Sopenharmony_ci set_temp, 2, 3); 10178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0); 10188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0); 10198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_cistatic ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, 10228c2ecf20Sopenharmony_ci char *buf) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 10258c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 10268c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 10278c2ecf20Sopenharmony_ci u8 reg = data->sensor; /* In case value is updated while used */ 10288c2ecf20Sopenharmony_ci u8 extra = data->extra; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) || 10318c2ecf20Sopenharmony_ci (has_temp_old_peci(data, nr) && (extra & 0x80))) 10328c2ecf20Sopenharmony_ci return sprintf(buf, "6\n"); /* Intel PECI */ 10338c2ecf20Sopenharmony_ci if (reg & (1 << nr)) 10348c2ecf20Sopenharmony_ci return sprintf(buf, "3\n"); /* thermal diode */ 10358c2ecf20Sopenharmony_ci if (reg & (8 << nr)) 10368c2ecf20Sopenharmony_ci return sprintf(buf, "4\n"); /* thermistor */ 10378c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); /* disabled */ 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic ssize_t set_temp_type(struct device *dev, struct device_attribute *attr, 10418c2ecf20Sopenharmony_ci const char *buf, size_t count) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 10448c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 10478c2ecf20Sopenharmony_ci long val; 10488c2ecf20Sopenharmony_ci u8 reg, extra; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0) 10518c2ecf20Sopenharmony_ci return -EINVAL; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_TEMP_ENABLE); 10548c2ecf20Sopenharmony_ci reg &= ~(1 << nr); 10558c2ecf20Sopenharmony_ci reg &= ~(8 << nr); 10568c2ecf20Sopenharmony_ci if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6)) 10578c2ecf20Sopenharmony_ci reg &= 0x3f; 10588c2ecf20Sopenharmony_ci extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); 10598c2ecf20Sopenharmony_ci if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6)) 10608c2ecf20Sopenharmony_ci extra &= 0x7f; 10618c2ecf20Sopenharmony_ci if (val == 2) { /* backwards compatibility */ 10628c2ecf20Sopenharmony_ci dev_warn(dev, 10638c2ecf20Sopenharmony_ci "Sensor type 2 is deprecated, please use 4 instead\n"); 10648c2ecf20Sopenharmony_ci val = 4; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci /* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */ 10678c2ecf20Sopenharmony_ci if (val == 3) 10688c2ecf20Sopenharmony_ci reg |= 1 << nr; 10698c2ecf20Sopenharmony_ci else if (val == 4) 10708c2ecf20Sopenharmony_ci reg |= 8 << nr; 10718c2ecf20Sopenharmony_ci else if (has_temp_peci(data, nr) && val == 6) 10728c2ecf20Sopenharmony_ci reg |= (nr + 1) << 6; 10738c2ecf20Sopenharmony_ci else if (has_temp_old_peci(data, nr) && val == 6) 10748c2ecf20Sopenharmony_ci extra |= 0x80; 10758c2ecf20Sopenharmony_ci else if (val != 0) 10768c2ecf20Sopenharmony_ci return -EINVAL; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 10798c2ecf20Sopenharmony_ci data->sensor = reg; 10808c2ecf20Sopenharmony_ci data->extra = extra; 10818c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor); 10828c2ecf20Sopenharmony_ci if (has_temp_old_peci(data, nr)) 10838c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); 10848c2ecf20Sopenharmony_ci data->valid = 0; /* Force cache refresh */ 10858c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 10868c2ecf20Sopenharmony_ci return count; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type, 10908c2ecf20Sopenharmony_ci set_temp_type, 0); 10918c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type, 10928c2ecf20Sopenharmony_ci set_temp_type, 1); 10938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, 10948c2ecf20Sopenharmony_ci set_temp_type, 2); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci/* 6 Fans */ 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int pwm_mode(const struct it87_data *data, int nr) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr))) 11018c2ecf20Sopenharmony_ci return 0; /* Full speed */ 11028c2ecf20Sopenharmony_ci if (data->pwm_ctrl[nr] & 0x80) 11038c2ecf20Sopenharmony_ci return 2; /* Automatic mode */ 11048c2ecf20Sopenharmony_ci if ((data->type == it8603 || nr >= 3) && 11058c2ecf20Sopenharmony_ci data->pwm_duty[nr] == pwm_to_reg(data, 0xff)) 11068c2ecf20Sopenharmony_ci return 0; /* Full speed */ 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci return 1; /* Manual mode */ 11098c2ecf20Sopenharmony_ci} 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic ssize_t show_fan(struct device *dev, struct device_attribute *attr, 11128c2ecf20Sopenharmony_ci char *buf) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 11158c2ecf20Sopenharmony_ci int nr = sattr->nr; 11168c2ecf20Sopenharmony_ci int index = sattr->index; 11178c2ecf20Sopenharmony_ci int speed; 11188c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci speed = has_16bit_fans(data) ? 11218c2ecf20Sopenharmony_ci FAN16_FROM_REG(data->fan[nr][index]) : 11228c2ecf20Sopenharmony_ci FAN_FROM_REG(data->fan[nr][index], 11238c2ecf20Sopenharmony_ci DIV_FROM_REG(data->fan_div[nr])); 11248c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", speed); 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, 11288c2ecf20Sopenharmony_ci char *buf) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 11318c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 11328c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr])); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic ssize_t show_pwm_enable(struct device *dev, 11388c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 11418c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 11428c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", pwm_mode(data, nr)); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic ssize_t show_pwm(struct device *dev, struct device_attribute *attr, 11488c2ecf20Sopenharmony_ci char *buf) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 11518c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 11528c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 11558c2ecf20Sopenharmony_ci pwm_from_reg(data, data->pwm_duty[nr])); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, 11598c2ecf20Sopenharmony_ci char *buf) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 11628c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 11638c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 11648c2ecf20Sopenharmony_ci unsigned int freq; 11658c2ecf20Sopenharmony_ci int index; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (has_pwm_freq2(data) && nr == 1) 11688c2ecf20Sopenharmony_ci index = (data->extra >> 4) & 0x07; 11698c2ecf20Sopenharmony_ci else 11708c2ecf20Sopenharmony_ci index = (data->fan_ctl >> 4) & 0x07; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci freq = pwm_freq[index] / (has_newer_autopwm(data) ? 256 : 128); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", freq); 11758c2ecf20Sopenharmony_ci} 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_cistatic ssize_t set_fan(struct device *dev, struct device_attribute *attr, 11788c2ecf20Sopenharmony_ci const char *buf, size_t count) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); 11818c2ecf20Sopenharmony_ci int nr = sattr->nr; 11828c2ecf20Sopenharmony_ci int index = sattr->index; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 11858c2ecf20Sopenharmony_ci long val; 11868c2ecf20Sopenharmony_ci u8 reg; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0) 11898c2ecf20Sopenharmony_ci return -EINVAL; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (has_16bit_fans(data)) { 11948c2ecf20Sopenharmony_ci data->fan[nr][index] = FAN16_TO_REG(val); 11958c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MIN[nr], 11968c2ecf20Sopenharmony_ci data->fan[nr][index] & 0xff); 11978c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FANX_MIN[nr], 11988c2ecf20Sopenharmony_ci data->fan[nr][index] >> 8); 11998c2ecf20Sopenharmony_ci } else { 12008c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_FAN_DIV); 12018c2ecf20Sopenharmony_ci switch (nr) { 12028c2ecf20Sopenharmony_ci case 0: 12038c2ecf20Sopenharmony_ci data->fan_div[nr] = reg & 0x07; 12048c2ecf20Sopenharmony_ci break; 12058c2ecf20Sopenharmony_ci case 1: 12068c2ecf20Sopenharmony_ci data->fan_div[nr] = (reg >> 3) & 0x07; 12078c2ecf20Sopenharmony_ci break; 12088c2ecf20Sopenharmony_ci case 2: 12098c2ecf20Sopenharmony_ci data->fan_div[nr] = (reg & 0x40) ? 3 : 1; 12108c2ecf20Sopenharmony_ci break; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci data->fan[nr][index] = 12138c2ecf20Sopenharmony_ci FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 12148c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MIN[nr], 12158c2ecf20Sopenharmony_ci data->fan[nr][index]); 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12198c2ecf20Sopenharmony_ci return count; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, 12238c2ecf20Sopenharmony_ci const char *buf, size_t count) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 12268c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 12278c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 12288c2ecf20Sopenharmony_ci unsigned long val; 12298c2ecf20Sopenharmony_ci int min; 12308c2ecf20Sopenharmony_ci u8 old; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 12338c2ecf20Sopenharmony_ci return -EINVAL; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12368c2ecf20Sopenharmony_ci old = it87_read_value(data, IT87_REG_FAN_DIV); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci /* Save fan min limit */ 12398c2ecf20Sopenharmony_ci min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr])); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci switch (nr) { 12428c2ecf20Sopenharmony_ci case 0: 12438c2ecf20Sopenharmony_ci case 1: 12448c2ecf20Sopenharmony_ci data->fan_div[nr] = DIV_TO_REG(val); 12458c2ecf20Sopenharmony_ci break; 12468c2ecf20Sopenharmony_ci case 2: 12478c2ecf20Sopenharmony_ci if (val < 8) 12488c2ecf20Sopenharmony_ci data->fan_div[nr] = 1; 12498c2ecf20Sopenharmony_ci else 12508c2ecf20Sopenharmony_ci data->fan_div[nr] = 3; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci val = old & 0x80; 12538c2ecf20Sopenharmony_ci val |= (data->fan_div[0] & 0x07); 12548c2ecf20Sopenharmony_ci val |= (data->fan_div[1] & 0x07) << 3; 12558c2ecf20Sopenharmony_ci if (data->fan_div[2] == 3) 12568c2ecf20Sopenharmony_ci val |= 0x1 << 6; 12578c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_DIV, val); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Restore fan min limit */ 12608c2ecf20Sopenharmony_ci data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 12618c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]); 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12648c2ecf20Sopenharmony_ci return count; 12658c2ecf20Sopenharmony_ci} 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci/* Returns 0 if OK, -EINVAL otherwise */ 12688c2ecf20Sopenharmony_cistatic int check_trip_points(struct device *dev, int nr) 12698c2ecf20Sopenharmony_ci{ 12708c2ecf20Sopenharmony_ci const struct it87_data *data = dev_get_drvdata(dev); 12718c2ecf20Sopenharmony_ci int i, err = 0; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (has_old_autopwm(data)) { 12748c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 12758c2ecf20Sopenharmony_ci if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1]) 12768c2ecf20Sopenharmony_ci err = -EINVAL; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 12798c2ecf20Sopenharmony_ci if (data->auto_pwm[nr][i] > data->auto_pwm[nr][i + 1]) 12808c2ecf20Sopenharmony_ci err = -EINVAL; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci } else if (has_newer_autopwm(data)) { 12838c2ecf20Sopenharmony_ci for (i = 1; i < 3; i++) { 12848c2ecf20Sopenharmony_ci if (data->auto_temp[nr][i] > data->auto_temp[nr][i + 1]) 12858c2ecf20Sopenharmony_ci err = -EINVAL; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (err) { 12908c2ecf20Sopenharmony_ci dev_err(dev, 12918c2ecf20Sopenharmony_ci "Inconsistent trip points, not switching to automatic mode\n"); 12928c2ecf20Sopenharmony_ci dev_err(dev, "Adjust the trip points and try again\n"); 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci return err; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, 12988c2ecf20Sopenharmony_ci const char *buf, size_t count) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 13018c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 13028c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 13038c2ecf20Sopenharmony_ci long val; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2) 13068c2ecf20Sopenharmony_ci return -EINVAL; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci /* Check trip points before switching to automatic mode */ 13098c2ecf20Sopenharmony_ci if (val == 2) { 13108c2ecf20Sopenharmony_ci if (check_trip_points(dev, nr) < 0) 13118c2ecf20Sopenharmony_ci return -EINVAL; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (val == 0) { 13178c2ecf20Sopenharmony_ci if (nr < 3 && data->type != it8603) { 13188c2ecf20Sopenharmony_ci int tmp; 13198c2ecf20Sopenharmony_ci /* make sure the fan is on when in on/off mode */ 13208c2ecf20Sopenharmony_ci tmp = it87_read_value(data, IT87_REG_FAN_CTL); 13218c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_CTL, tmp | BIT(nr)); 13228c2ecf20Sopenharmony_ci /* set on/off mode */ 13238c2ecf20Sopenharmony_ci data->fan_main_ctrl &= ~BIT(nr); 13248c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, 13258c2ecf20Sopenharmony_ci data->fan_main_ctrl); 13268c2ecf20Sopenharmony_ci } else { 13278c2ecf20Sopenharmony_ci u8 ctrl; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci /* No on/off mode, set maximum pwm value */ 13308c2ecf20Sopenharmony_ci data->pwm_duty[nr] = pwm_to_reg(data, 0xff); 13318c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM_DUTY[nr], 13328c2ecf20Sopenharmony_ci data->pwm_duty[nr]); 13338c2ecf20Sopenharmony_ci /* and set manual mode */ 13348c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) { 13358c2ecf20Sopenharmony_ci ctrl = (data->pwm_ctrl[nr] & 0x7c) | 13368c2ecf20Sopenharmony_ci data->pwm_temp_map[nr]; 13378c2ecf20Sopenharmony_ci } else { 13388c2ecf20Sopenharmony_ci ctrl = data->pwm_duty[nr]; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci data->pwm_ctrl[nr] = ctrl; 13418c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM[nr], ctrl); 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci } else { 13448c2ecf20Sopenharmony_ci u8 ctrl; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) { 13478c2ecf20Sopenharmony_ci ctrl = (data->pwm_ctrl[nr] & 0x7c) | 13488c2ecf20Sopenharmony_ci data->pwm_temp_map[nr]; 13498c2ecf20Sopenharmony_ci if (val != 1) 13508c2ecf20Sopenharmony_ci ctrl |= 0x80; 13518c2ecf20Sopenharmony_ci } else { 13528c2ecf20Sopenharmony_ci ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80); 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci data->pwm_ctrl[nr] = ctrl; 13558c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM[nr], ctrl); 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (data->type != it8603 && nr < 3) { 13588c2ecf20Sopenharmony_ci /* set SmartGuardian mode */ 13598c2ecf20Sopenharmony_ci data->fan_main_ctrl |= BIT(nr); 13608c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, 13618c2ecf20Sopenharmony_ci data->fan_main_ctrl); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13668c2ecf20Sopenharmony_ci return count; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic ssize_t set_pwm(struct device *dev, struct device_attribute *attr, 13708c2ecf20Sopenharmony_ci const char *buf, size_t count) 13718c2ecf20Sopenharmony_ci{ 13728c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 13738c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 13748c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 13758c2ecf20Sopenharmony_ci long val; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255) 13788c2ecf20Sopenharmony_ci return -EINVAL; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13818c2ecf20Sopenharmony_ci it87_update_pwm_ctrl(data, nr); 13828c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) { 13838c2ecf20Sopenharmony_ci /* 13848c2ecf20Sopenharmony_ci * If we are in automatic mode, the PWM duty cycle register 13858c2ecf20Sopenharmony_ci * is read-only so we can't write the value. 13868c2ecf20Sopenharmony_ci */ 13878c2ecf20Sopenharmony_ci if (data->pwm_ctrl[nr] & 0x80) { 13888c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13898c2ecf20Sopenharmony_ci return -EBUSY; 13908c2ecf20Sopenharmony_ci } 13918c2ecf20Sopenharmony_ci data->pwm_duty[nr] = pwm_to_reg(data, val); 13928c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM_DUTY[nr], 13938c2ecf20Sopenharmony_ci data->pwm_duty[nr]); 13948c2ecf20Sopenharmony_ci } else { 13958c2ecf20Sopenharmony_ci data->pwm_duty[nr] = pwm_to_reg(data, val); 13968c2ecf20Sopenharmony_ci /* 13978c2ecf20Sopenharmony_ci * If we are in manual mode, write the duty cycle immediately; 13988c2ecf20Sopenharmony_ci * otherwise, just store it for later use. 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_ci if (!(data->pwm_ctrl[nr] & 0x80)) { 14018c2ecf20Sopenharmony_ci data->pwm_ctrl[nr] = data->pwm_duty[nr]; 14028c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM[nr], 14038c2ecf20Sopenharmony_ci data->pwm_ctrl[nr]); 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14078c2ecf20Sopenharmony_ci return count; 14088c2ecf20Sopenharmony_ci} 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr, 14118c2ecf20Sopenharmony_ci const char *buf, size_t count) 14128c2ecf20Sopenharmony_ci{ 14138c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 14148c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 14158c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 14168c2ecf20Sopenharmony_ci unsigned long val; 14178c2ecf20Sopenharmony_ci int i; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 14208c2ecf20Sopenharmony_ci return -EINVAL; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 1000000); 14238c2ecf20Sopenharmony_ci val *= has_newer_autopwm(data) ? 256 : 128; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci /* Search for the nearest available frequency */ 14268c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 14278c2ecf20Sopenharmony_ci if (val > (pwm_freq[i] + pwm_freq[i + 1]) / 2) 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci } 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14328c2ecf20Sopenharmony_ci if (nr == 0) { 14338c2ecf20Sopenharmony_ci data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f; 14348c2ecf20Sopenharmony_ci data->fan_ctl |= i << 4; 14358c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl); 14368c2ecf20Sopenharmony_ci } else { 14378c2ecf20Sopenharmony_ci data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x8f; 14388c2ecf20Sopenharmony_ci data->extra |= i << 4; 14398c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return count; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic ssize_t show_pwm_temp_map(struct device *dev, 14478c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 14508c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 14518c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 14528c2ecf20Sopenharmony_ci int map; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci map = data->pwm_temp_map[nr]; 14558c2ecf20Sopenharmony_ci if (map >= 3) 14568c2ecf20Sopenharmony_ci map = 0; /* Should never happen */ 14578c2ecf20Sopenharmony_ci if (nr >= 3) /* pwm channels 3..6 map to temp4..6 */ 14588c2ecf20Sopenharmony_ci map += 3; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (int)BIT(map)); 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic ssize_t set_pwm_temp_map(struct device *dev, 14648c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 14658c2ecf20Sopenharmony_ci size_t count) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 14688c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 14698c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 14708c2ecf20Sopenharmony_ci long val; 14718c2ecf20Sopenharmony_ci u8 reg; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0) 14748c2ecf20Sopenharmony_ci return -EINVAL; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (nr >= 3) 14778c2ecf20Sopenharmony_ci val -= 3; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci switch (val) { 14808c2ecf20Sopenharmony_ci case BIT(0): 14818c2ecf20Sopenharmony_ci reg = 0x00; 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci case BIT(1): 14848c2ecf20Sopenharmony_ci reg = 0x01; 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci case BIT(2): 14878c2ecf20Sopenharmony_ci reg = 0x02; 14888c2ecf20Sopenharmony_ci break; 14898c2ecf20Sopenharmony_ci default: 14908c2ecf20Sopenharmony_ci return -EINVAL; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14948c2ecf20Sopenharmony_ci it87_update_pwm_ctrl(data, nr); 14958c2ecf20Sopenharmony_ci data->pwm_temp_map[nr] = reg; 14968c2ecf20Sopenharmony_ci /* 14978c2ecf20Sopenharmony_ci * If we are in automatic mode, write the temp mapping immediately; 14988c2ecf20Sopenharmony_ci * otherwise, just store it for later use. 14998c2ecf20Sopenharmony_ci */ 15008c2ecf20Sopenharmony_ci if (data->pwm_ctrl[nr] & 0x80) { 15018c2ecf20Sopenharmony_ci data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) | 15028c2ecf20Sopenharmony_ci data->pwm_temp_map[nr]; 15038c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]); 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15068c2ecf20Sopenharmony_ci return count; 15078c2ecf20Sopenharmony_ci} 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_cistatic ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr, 15108c2ecf20Sopenharmony_ci char *buf) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 15138c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15148c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15158c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15168c2ecf20Sopenharmony_ci int point = sensor_attr->index; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 15198c2ecf20Sopenharmony_ci pwm_from_reg(data, data->auto_pwm[nr][point])); 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_cistatic ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr, 15238c2ecf20Sopenharmony_ci const char *buf, size_t count) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 15268c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15278c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15288c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15298c2ecf20Sopenharmony_ci int point = sensor_attr->index; 15308c2ecf20Sopenharmony_ci int regaddr; 15318c2ecf20Sopenharmony_ci long val; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255) 15348c2ecf20Sopenharmony_ci return -EINVAL; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15378c2ecf20Sopenharmony_ci data->auto_pwm[nr][point] = pwm_to_reg(data, val); 15388c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) 15398c2ecf20Sopenharmony_ci regaddr = IT87_REG_AUTO_TEMP(nr, 3); 15408c2ecf20Sopenharmony_ci else 15418c2ecf20Sopenharmony_ci regaddr = IT87_REG_AUTO_PWM(nr, point); 15428c2ecf20Sopenharmony_ci it87_write_value(data, regaddr, data->auto_pwm[nr][point]); 15438c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15448c2ecf20Sopenharmony_ci return count; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cistatic ssize_t show_auto_pwm_slope(struct device *dev, 15488c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 15498c2ecf20Sopenharmony_ci{ 15508c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 15518c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 15528c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic ssize_t set_auto_pwm_slope(struct device *dev, 15588c2ecf20Sopenharmony_ci struct device_attribute *attr, 15598c2ecf20Sopenharmony_ci const char *buf, size_t count) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 15628c2ecf20Sopenharmony_ci struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); 15638c2ecf20Sopenharmony_ci int nr = sensor_attr->index; 15648c2ecf20Sopenharmony_ci unsigned long val; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0 || val > 127) 15678c2ecf20Sopenharmony_ci return -EINVAL; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15708c2ecf20Sopenharmony_ci data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val; 15718c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4), 15728c2ecf20Sopenharmony_ci data->auto_pwm[nr][1]); 15738c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15748c2ecf20Sopenharmony_ci return count; 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr, 15788c2ecf20Sopenharmony_ci char *buf) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 15818c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15828c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15838c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15848c2ecf20Sopenharmony_ci int point = sensor_attr->index; 15858c2ecf20Sopenharmony_ci int reg; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci if (has_old_autopwm(data) || point) 15888c2ecf20Sopenharmony_ci reg = data->auto_temp[nr][point]; 15898c2ecf20Sopenharmony_ci else 15908c2ecf20Sopenharmony_ci reg = data->auto_temp[nr][1] - (data->auto_temp[nr][0] & 0x1f); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", TEMP_FROM_REG(reg)); 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr, 15968c2ecf20Sopenharmony_ci const char *buf, size_t count) 15978c2ecf20Sopenharmony_ci{ 15988c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 15998c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 16008c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 16018c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 16028c2ecf20Sopenharmony_ci int point = sensor_attr->index; 16038c2ecf20Sopenharmony_ci long val; 16048c2ecf20Sopenharmony_ci int reg; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000) 16078c2ecf20Sopenharmony_ci return -EINVAL; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 16108c2ecf20Sopenharmony_ci if (has_newer_autopwm(data) && !point) { 16118c2ecf20Sopenharmony_ci reg = data->auto_temp[nr][1] - TEMP_TO_REG(val); 16128c2ecf20Sopenharmony_ci reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0); 16138c2ecf20Sopenharmony_ci data->auto_temp[nr][0] = reg; 16148c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 5), reg); 16158c2ecf20Sopenharmony_ci } else { 16168c2ecf20Sopenharmony_ci reg = TEMP_TO_REG(val); 16178c2ecf20Sopenharmony_ci data->auto_temp[nr][point] = reg; 16188c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) 16198c2ecf20Sopenharmony_ci point--; 16208c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg); 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 16238c2ecf20Sopenharmony_ci return count; 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0); 16278c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16288c2ecf20Sopenharmony_ci 0, 1); 16298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, 16308c2ecf20Sopenharmony_ci set_fan_div, 0); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0); 16338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16348c2ecf20Sopenharmony_ci 1, 1); 16358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div, 16368c2ecf20Sopenharmony_ci set_fan_div, 1); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0); 16398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16408c2ecf20Sopenharmony_ci 2, 1); 16418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div, 16428c2ecf20Sopenharmony_ci set_fan_div, 2); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0); 16458c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16468c2ecf20Sopenharmony_ci 3, 1); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0); 16498c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16508c2ecf20Sopenharmony_ci 4, 1); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan6_input, S_IRUGO, show_fan, NULL, 5, 0); 16538c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(fan6_min, S_IRUGO | S_IWUSR, show_fan, set_fan, 16548c2ecf20Sopenharmony_ci 5, 1); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, 16578c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 0); 16588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); 16598c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, 16608c2ecf20Sopenharmony_ci set_pwm_freq, 0); 16618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO, 16628c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 0); 16638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, 16648c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 0, 0); 16658c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, 16668c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 0, 1); 16678c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, 16688c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 0, 2); 16698c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO, 16708c2ecf20Sopenharmony_ci show_auto_pwm, NULL, 0, 3); 16718c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, 16728c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 0, 1); 16738c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 16748c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 0, 0); 16758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, 16768c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 0, 2); 16778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, 16788c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 0, 3); 16798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, 16808c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 0, 4); 16818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm1_auto_start, S_IRUGO | S_IWUSR, 16828c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 0, 0); 16838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm1_auto_slope, S_IRUGO | S_IWUSR, 16848c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 0); 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, 16878c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 1); 16888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1); 16898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, set_pwm_freq, 1); 16908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO, 16918c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 1); 16928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, 16938c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 1, 0); 16948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, 16958c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 1, 1); 16968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, 16978c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 1, 2); 16988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO, 16998c2ecf20Sopenharmony_ci show_auto_pwm, NULL, 1, 3); 17008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, 17018c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 1, 1); 17028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 17038c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 1, 0); 17048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, 17058c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 1, 2); 17068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, 17078c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 1, 3); 17088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, 17098c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 1, 4); 17108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm2_auto_start, S_IRUGO | S_IWUSR, 17118c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 1, 0); 17128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm2_auto_slope, S_IRUGO | S_IWUSR, 17138c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 1); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, 17168c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 2); 17178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2); 17188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL, 2); 17198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO, 17208c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 2); 17218c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, 17228c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 2, 0); 17238c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, 17248c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 2, 1); 17258c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, 17268c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 2, 2); 17278c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO, 17288c2ecf20Sopenharmony_ci show_auto_pwm, NULL, 2, 3); 17298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, 17308c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 1); 17318c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 17328c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 0); 17338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, 17348c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 2); 17358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, 17368c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 3); 17378c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, 17388c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 4); 17398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm3_auto_start, S_IRUGO | S_IWUSR, 17408c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 2, 0); 17418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm3_auto_slope, S_IRUGO | S_IWUSR, 17428c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 2); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR, 17458c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 3); 17468c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 3); 17478c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_freq, S_IRUGO, show_pwm_freq, NULL, 3); 17488c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IRUGO, 17498c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 3); 17508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp, S_IRUGO | S_IWUSR, 17518c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 1); 17528c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 17538c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 0); 17548c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point2_temp, S_IRUGO | S_IWUSR, 17558c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 2); 17568c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_point3_temp, S_IRUGO | S_IWUSR, 17578c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 3); 17588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm4_auto_start, S_IRUGO | S_IWUSR, 17598c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 3, 0); 17608c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm4_auto_slope, S_IRUGO | S_IWUSR, 17618c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 3); 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_enable, S_IRUGO | S_IWUSR, 17648c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 4); 17658c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 4); 17668c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_freq, S_IRUGO, show_pwm_freq, NULL, 4); 17678c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_auto_channels_temp, S_IRUGO, 17688c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 4); 17698c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp, S_IRUGO | S_IWUSR, 17708c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 1); 17718c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 17728c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 0); 17738c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point2_temp, S_IRUGO | S_IWUSR, 17748c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 2); 17758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_point3_temp, S_IRUGO | S_IWUSR, 17768c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 3); 17778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm5_auto_start, S_IRUGO | S_IWUSR, 17788c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 4, 0); 17798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm5_auto_slope, S_IRUGO | S_IWUSR, 17808c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 4); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_enable, S_IRUGO | S_IWUSR, 17838c2ecf20Sopenharmony_ci show_pwm_enable, set_pwm_enable, 5); 17848c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 5); 17858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_freq, S_IRUGO, show_pwm_freq, NULL, 5); 17868c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_auto_channels_temp, S_IRUGO, 17878c2ecf20Sopenharmony_ci show_pwm_temp_map, set_pwm_temp_map, 5); 17888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp, S_IRUGO | S_IWUSR, 17898c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 1); 17908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, 17918c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 0); 17928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point2_temp, S_IRUGO | S_IWUSR, 17938c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 2); 17948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_point3_temp, S_IRUGO | S_IWUSR, 17958c2ecf20Sopenharmony_ci show_auto_temp, set_auto_temp, 2, 3); 17968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2(pwm6_auto_start, S_IRUGO | S_IWUSR, 17978c2ecf20Sopenharmony_ci show_auto_pwm, set_auto_pwm, 5, 0); 17988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(pwm6_auto_slope, S_IRUGO | S_IWUSR, 17998c2ecf20Sopenharmony_ci show_auto_pwm_slope, set_auto_pwm_slope, 5); 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci/* Alarms */ 18028c2ecf20Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 18038c2ecf20Sopenharmony_ci char *buf) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", data->alarms); 18088c2ecf20Sopenharmony_ci} 18098c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic ssize_t show_alarm(struct device *dev, struct device_attribute *attr, 18128c2ecf20Sopenharmony_ci char *buf) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 18158c2ecf20Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1); 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic ssize_t clear_intrusion(struct device *dev, 18218c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 18228c2ecf20Sopenharmony_ci size_t count) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 18258c2ecf20Sopenharmony_ci int config; 18268c2ecf20Sopenharmony_ci long val; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || val != 0) 18298c2ecf20Sopenharmony_ci return -EINVAL; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 18328c2ecf20Sopenharmony_ci config = it87_read_value(data, IT87_REG_CONFIG); 18338c2ecf20Sopenharmony_ci if (config < 0) { 18348c2ecf20Sopenharmony_ci count = config; 18358c2ecf20Sopenharmony_ci } else { 18368c2ecf20Sopenharmony_ci config |= BIT(5); 18378c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_CONFIG, config); 18388c2ecf20Sopenharmony_ci /* Invalidate cache to force re-read */ 18398c2ecf20Sopenharmony_ci data->valid = 0; 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci return count; 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 8); 18478c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 9); 18488c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 10); 18498c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 11); 18508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 12); 18518c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 13); 18528c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 14); 18538c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 15); 18548c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 0); 18558c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 1); 18568c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 2); 18578c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 3); 18588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 6); 18598c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 7); 18608c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16); 18618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17); 18628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18); 18638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, 18648c2ecf20Sopenharmony_ci show_alarm, clear_intrusion, 4); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic ssize_t show_beep(struct device *dev, struct device_attribute *attr, 18678c2ecf20Sopenharmony_ci char *buf) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 18708c2ecf20Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1); 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_cistatic ssize_t set_beep(struct device *dev, struct device_attribute *attr, 18768c2ecf20Sopenharmony_ci const char *buf, size_t count) 18778c2ecf20Sopenharmony_ci{ 18788c2ecf20Sopenharmony_ci int bitnr = to_sensor_dev_attr(attr)->index; 18798c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 18808c2ecf20Sopenharmony_ci long val; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1)) 18838c2ecf20Sopenharmony_ci return -EINVAL; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 18868c2ecf20Sopenharmony_ci data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE); 18878c2ecf20Sopenharmony_ci if (val) 18888c2ecf20Sopenharmony_ci data->beeps |= BIT(bitnr); 18898c2ecf20Sopenharmony_ci else 18908c2ecf20Sopenharmony_ci data->beeps &= ~BIT(bitnr); 18918c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps); 18928c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 18938c2ecf20Sopenharmony_ci return count; 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in0_beep, S_IRUGO | S_IWUSR, 18978c2ecf20Sopenharmony_ci show_beep, set_beep, 1); 18988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in1_beep, S_IRUGO, show_beep, NULL, 1); 18998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in2_beep, S_IRUGO, show_beep, NULL, 1); 19008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_beep, S_IRUGO, show_beep, NULL, 1); 19018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in4_beep, S_IRUGO, show_beep, NULL, 1); 19028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in5_beep, S_IRUGO, show_beep, NULL, 1); 19038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in6_beep, S_IRUGO, show_beep, NULL, 1); 19048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_beep, S_IRUGO, show_beep, NULL, 1); 19058c2ecf20Sopenharmony_ci/* fanX_beep writability is set later */ 19068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan1_beep, S_IRUGO, show_beep, set_beep, 0); 19078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan2_beep, S_IRUGO, show_beep, set_beep, 0); 19088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan3_beep, S_IRUGO, show_beep, set_beep, 0); 19098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan4_beep, S_IRUGO, show_beep, set_beep, 0); 19108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan5_beep, S_IRUGO, show_beep, set_beep, 0); 19118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(fan6_beep, S_IRUGO, show_beep, set_beep, 0); 19128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, 19138c2ecf20Sopenharmony_ci show_beep, set_beep, 2); 19148c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2); 19158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_cistatic ssize_t vrm_show(struct device *dev, struct device_attribute *attr, 19188c2ecf20Sopenharmony_ci char *buf) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", data->vrm); 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic ssize_t vrm_store(struct device *dev, struct device_attribute *attr, 19268c2ecf20Sopenharmony_ci const char *buf, size_t count) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 19298c2ecf20Sopenharmony_ci unsigned long val; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 19328c2ecf20Sopenharmony_ci return -EINVAL; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci data->vrm = val; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci return count; 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(vrm); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_cistatic ssize_t cpu0_vid_show(struct device *dev, 19418c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci struct it87_data *data = it87_update_device(dev); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm)); 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(cpu0_vid); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cistatic ssize_t show_label(struct device *dev, struct device_attribute *attr, 19508c2ecf20Sopenharmony_ci char *buf) 19518c2ecf20Sopenharmony_ci{ 19528c2ecf20Sopenharmony_ci static const char * const labels[] = { 19538c2ecf20Sopenharmony_ci "+5V", 19548c2ecf20Sopenharmony_ci "5VSB", 19558c2ecf20Sopenharmony_ci "Vbat", 19568c2ecf20Sopenharmony_ci "AVCC", 19578c2ecf20Sopenharmony_ci }; 19588c2ecf20Sopenharmony_ci static const char * const labels_it8721[] = { 19598c2ecf20Sopenharmony_ci "+3.3V", 19608c2ecf20Sopenharmony_ci "3VSB", 19618c2ecf20Sopenharmony_ci "Vbat", 19628c2ecf20Sopenharmony_ci "+3.3V", 19638c2ecf20Sopenharmony_ci }; 19648c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 19658c2ecf20Sopenharmony_ci int nr = to_sensor_dev_attr(attr)->index; 19668c2ecf20Sopenharmony_ci const char *label; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci if (has_vin3_5v(data) && nr == 0) 19698c2ecf20Sopenharmony_ci label = labels[0]; 19708c2ecf20Sopenharmony_ci else if (has_12mv_adc(data) || has_10_9mv_adc(data)) 19718c2ecf20Sopenharmony_ci label = labels_it8721[nr]; 19728c2ecf20Sopenharmony_ci else 19738c2ecf20Sopenharmony_ci label = labels[nr]; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", label); 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); 19788c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); 19798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2); 19808c2ecf20Sopenharmony_ci/* AVCC3 */ 19818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_cistatic umode_t it87_in_is_visible(struct kobject *kobj, 19848c2ecf20Sopenharmony_ci struct attribute *attr, int index) 19858c2ecf20Sopenharmony_ci{ 19868c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 19878c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 19888c2ecf20Sopenharmony_ci int i = index / 5; /* voltage index */ 19898c2ecf20Sopenharmony_ci int a = index % 5; /* attribute index */ 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (index >= 40) { /* in8 and higher only have input attributes */ 19928c2ecf20Sopenharmony_ci i = index - 40 + 8; 19938c2ecf20Sopenharmony_ci a = 0; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci if (!(data->has_in & BIT(i))) 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (a == 4 && !data->has_beep) 20008c2ecf20Sopenharmony_ci return 0; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci return attr->mode; 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes_in[] = { 20068c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_input.dev_attr.attr, 20078c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_min.dev_attr.attr, 20088c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_max.dev_attr.attr, 20098c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_alarm.dev_attr.attr, 20108c2ecf20Sopenharmony_ci &sensor_dev_attr_in0_beep.dev_attr.attr, /* 4 */ 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 20138c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr.attr, 20148c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr.attr, 20158c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_alarm.dev_attr.attr, 20168c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_beep.dev_attr.attr, /* 9 */ 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 20198c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_min.dev_attr.attr, 20208c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_max.dev_attr.attr, 20218c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_alarm.dev_attr.attr, 20228c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_beep.dev_attr.attr, /* 14 */ 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 20258c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_min.dev_attr.attr, 20268c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_max.dev_attr.attr, 20278c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_alarm.dev_attr.attr, 20288c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_beep.dev_attr.attr, /* 19 */ 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 20318c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_min.dev_attr.attr, 20328c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_max.dev_attr.attr, 20338c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_alarm.dev_attr.attr, 20348c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_beep.dev_attr.attr, /* 24 */ 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr.attr, 20378c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_min.dev_attr.attr, 20388c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_max.dev_attr.attr, 20398c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_alarm.dev_attr.attr, 20408c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_beep.dev_attr.attr, /* 29 */ 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_input.dev_attr.attr, 20438c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_min.dev_attr.attr, 20448c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_max.dev_attr.attr, 20458c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_alarm.dev_attr.attr, 20468c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_beep.dev_attr.attr, /* 34 */ 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_input.dev_attr.attr, 20498c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_min.dev_attr.attr, 20508c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_max.dev_attr.attr, 20518c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_alarm.dev_attr.attr, 20528c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_beep.dev_attr.attr, /* 39 */ 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_input.dev_attr.attr, /* 40 */ 20558c2ecf20Sopenharmony_ci &sensor_dev_attr_in9_input.dev_attr.attr, 20568c2ecf20Sopenharmony_ci &sensor_dev_attr_in10_input.dev_attr.attr, 20578c2ecf20Sopenharmony_ci &sensor_dev_attr_in11_input.dev_attr.attr, 20588c2ecf20Sopenharmony_ci &sensor_dev_attr_in12_input.dev_attr.attr, 20598c2ecf20Sopenharmony_ci NULL 20608c2ecf20Sopenharmony_ci}; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group_in = { 20638c2ecf20Sopenharmony_ci .attrs = it87_attributes_in, 20648c2ecf20Sopenharmony_ci .is_visible = it87_in_is_visible, 20658c2ecf20Sopenharmony_ci}; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_cistatic umode_t it87_temp_is_visible(struct kobject *kobj, 20688c2ecf20Sopenharmony_ci struct attribute *attr, int index) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 20718c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 20728c2ecf20Sopenharmony_ci int i = index / 7; /* temperature index */ 20738c2ecf20Sopenharmony_ci int a = index % 7; /* attribute index */ 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci if (index >= 21) { 20768c2ecf20Sopenharmony_ci i = index - 21 + 3; 20778c2ecf20Sopenharmony_ci a = 0; 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (!(data->has_temp & BIT(i))) 20818c2ecf20Sopenharmony_ci return 0; 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci if (a == 5 && !has_temp_offset(data)) 20848c2ecf20Sopenharmony_ci return 0; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci if (a == 6 && !data->has_beep) 20878c2ecf20Sopenharmony_ci return 0; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci return attr->mode; 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes_temp[] = { 20938c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 20948c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 20958c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 20968c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_type.dev_attr.attr, 20978c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_alarm.dev_attr.attr, 20988c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_offset.dev_attr.attr, /* 5 */ 20998c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_beep.dev_attr.attr, /* 6 */ 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, /* 7 */ 21028c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 21038c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 21048c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_type.dev_attr.attr, 21058c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_alarm.dev_attr.attr, 21068c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_offset.dev_attr.attr, 21078c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_beep.dev_attr.attr, 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, /* 14 */ 21108c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 21118c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 21128c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_type.dev_attr.attr, 21138c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_alarm.dev_attr.attr, 21148c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_offset.dev_attr.attr, 21158c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_beep.dev_attr.attr, 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci &sensor_dev_attr_temp4_input.dev_attr.attr, /* 21 */ 21188c2ecf20Sopenharmony_ci &sensor_dev_attr_temp5_input.dev_attr.attr, 21198c2ecf20Sopenharmony_ci &sensor_dev_attr_temp6_input.dev_attr.attr, 21208c2ecf20Sopenharmony_ci NULL 21218c2ecf20Sopenharmony_ci}; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group_temp = { 21248c2ecf20Sopenharmony_ci .attrs = it87_attributes_temp, 21258c2ecf20Sopenharmony_ci .is_visible = it87_temp_is_visible, 21268c2ecf20Sopenharmony_ci}; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic umode_t it87_is_visible(struct kobject *kobj, 21298c2ecf20Sopenharmony_ci struct attribute *attr, int index) 21308c2ecf20Sopenharmony_ci{ 21318c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 21328c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if ((index == 2 || index == 3) && !data->has_vid) 21358c2ecf20Sopenharmony_ci return 0; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (index > 3 && !(data->in_internal & BIT(index - 4))) 21388c2ecf20Sopenharmony_ci return 0; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci return attr->mode; 21418c2ecf20Sopenharmony_ci} 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes[] = { 21448c2ecf20Sopenharmony_ci &dev_attr_alarms.attr, 21458c2ecf20Sopenharmony_ci &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, 21468c2ecf20Sopenharmony_ci &dev_attr_vrm.attr, /* 2 */ 21478c2ecf20Sopenharmony_ci &dev_attr_cpu0_vid.attr, /* 3 */ 21488c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_label.dev_attr.attr, /* 4 .. 7 */ 21498c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_label.dev_attr.attr, 21508c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_label.dev_attr.attr, 21518c2ecf20Sopenharmony_ci &sensor_dev_attr_in9_label.dev_attr.attr, 21528c2ecf20Sopenharmony_ci NULL 21538c2ecf20Sopenharmony_ci}; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group = { 21568c2ecf20Sopenharmony_ci .attrs = it87_attributes, 21578c2ecf20Sopenharmony_ci .is_visible = it87_is_visible, 21588c2ecf20Sopenharmony_ci}; 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_cistatic umode_t it87_fan_is_visible(struct kobject *kobj, 21618c2ecf20Sopenharmony_ci struct attribute *attr, int index) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 21648c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 21658c2ecf20Sopenharmony_ci int i = index / 5; /* fan index */ 21668c2ecf20Sopenharmony_ci int a = index % 5; /* attribute index */ 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (index >= 15) { /* fan 4..6 don't have divisor attributes */ 21698c2ecf20Sopenharmony_ci i = (index - 15) / 4 + 3; 21708c2ecf20Sopenharmony_ci a = (index - 15) % 4; 21718c2ecf20Sopenharmony_ci } 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (!(data->has_fan & BIT(i))) 21748c2ecf20Sopenharmony_ci return 0; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci if (a == 3) { /* beep */ 21778c2ecf20Sopenharmony_ci if (!data->has_beep) 21788c2ecf20Sopenharmony_ci return 0; 21798c2ecf20Sopenharmony_ci /* first fan beep attribute is writable */ 21808c2ecf20Sopenharmony_ci if (i == __ffs(data->has_fan)) 21818c2ecf20Sopenharmony_ci return attr->mode | S_IWUSR; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci if (a == 4 && has_16bit_fans(data)) /* divisor */ 21858c2ecf20Sopenharmony_ci return 0; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci return attr->mode; 21888c2ecf20Sopenharmony_ci} 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes_fan[] = { 21918c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 21928c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 21938c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_alarm.dev_attr.attr, 21948c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_beep.dev_attr.attr, /* 3 */ 21958c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_div.dev_attr.attr, /* 4 */ 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 21988c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 21998c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_alarm.dev_attr.attr, 22008c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_beep.dev_attr.attr, 22018c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_div.dev_attr.attr, /* 9 */ 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 22048c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_min.dev_attr.attr, 22058c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_alarm.dev_attr.attr, 22068c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_beep.dev_attr.attr, 22078c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_div.dev_attr.attr, /* 14 */ 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, /* 15 */ 22108c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_min.dev_attr.attr, 22118c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_alarm.dev_attr.attr, 22128c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_beep.dev_attr.attr, 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci &sensor_dev_attr_fan5_input.dev_attr.attr, /* 19 */ 22158c2ecf20Sopenharmony_ci &sensor_dev_attr_fan5_min.dev_attr.attr, 22168c2ecf20Sopenharmony_ci &sensor_dev_attr_fan5_alarm.dev_attr.attr, 22178c2ecf20Sopenharmony_ci &sensor_dev_attr_fan5_beep.dev_attr.attr, 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci &sensor_dev_attr_fan6_input.dev_attr.attr, /* 23 */ 22208c2ecf20Sopenharmony_ci &sensor_dev_attr_fan6_min.dev_attr.attr, 22218c2ecf20Sopenharmony_ci &sensor_dev_attr_fan6_alarm.dev_attr.attr, 22228c2ecf20Sopenharmony_ci &sensor_dev_attr_fan6_beep.dev_attr.attr, 22238c2ecf20Sopenharmony_ci NULL 22248c2ecf20Sopenharmony_ci}; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group_fan = { 22278c2ecf20Sopenharmony_ci .attrs = it87_attributes_fan, 22288c2ecf20Sopenharmony_ci .is_visible = it87_fan_is_visible, 22298c2ecf20Sopenharmony_ci}; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_cistatic umode_t it87_pwm_is_visible(struct kobject *kobj, 22328c2ecf20Sopenharmony_ci struct attribute *attr, int index) 22338c2ecf20Sopenharmony_ci{ 22348c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 22358c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 22368c2ecf20Sopenharmony_ci int i = index / 4; /* pwm index */ 22378c2ecf20Sopenharmony_ci int a = index % 4; /* attribute index */ 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci if (!(data->has_pwm & BIT(i))) 22408c2ecf20Sopenharmony_ci return 0; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci /* pwmX_auto_channels_temp is only writable if auto pwm is supported */ 22438c2ecf20Sopenharmony_ci if (a == 3 && (has_old_autopwm(data) || has_newer_autopwm(data))) 22448c2ecf20Sopenharmony_ci return attr->mode | S_IWUSR; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci /* pwm2_freq is writable if there are two pwm frequency selects */ 22478c2ecf20Sopenharmony_ci if (has_pwm_freq2(data) && i == 1 && a == 2) 22488c2ecf20Sopenharmony_ci return attr->mode | S_IWUSR; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci return attr->mode; 22518c2ecf20Sopenharmony_ci} 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes_pwm[] = { 22548c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr.attr, 22558c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 22568c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr.attr, 22578c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr.attr, 22608c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 22618c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr.attr, 22628c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_enable.dev_attr.attr, 22658c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3.dev_attr.attr, 22668c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_freq.dev_attr.attr, 22678c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_enable.dev_attr.attr, 22708c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4.dev_attr.attr, 22718c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_freq.dev_attr.attr, 22728c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr, 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_enable.dev_attr.attr, 22758c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5.dev_attr.attr, 22768c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_freq.dev_attr.attr, 22778c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_channels_temp.dev_attr.attr, 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_enable.dev_attr.attr, 22808c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6.dev_attr.attr, 22818c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_freq.dev_attr.attr, 22828c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_channels_temp.dev_attr.attr, 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci NULL 22858c2ecf20Sopenharmony_ci}; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group_pwm = { 22888c2ecf20Sopenharmony_ci .attrs = it87_attributes_pwm, 22898c2ecf20Sopenharmony_ci .is_visible = it87_pwm_is_visible, 22908c2ecf20Sopenharmony_ci}; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_cistatic umode_t it87_auto_pwm_is_visible(struct kobject *kobj, 22938c2ecf20Sopenharmony_ci struct attribute *attr, int index) 22948c2ecf20Sopenharmony_ci{ 22958c2ecf20Sopenharmony_ci struct device *dev = container_of(kobj, struct device, kobj); 22968c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 22978c2ecf20Sopenharmony_ci int i = index / 11; /* pwm index */ 22988c2ecf20Sopenharmony_ci int a = index % 11; /* attribute index */ 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci if (index >= 33) { /* pwm 4..6 */ 23018c2ecf20Sopenharmony_ci i = (index - 33) / 6 + 3; 23028c2ecf20Sopenharmony_ci a = (index - 33) % 6 + 4; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (!(data->has_pwm & BIT(i))) 23068c2ecf20Sopenharmony_ci return 0; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci if (has_newer_autopwm(data)) { 23098c2ecf20Sopenharmony_ci if (a < 4) /* no auto point pwm */ 23108c2ecf20Sopenharmony_ci return 0; 23118c2ecf20Sopenharmony_ci if (a == 8) /* no auto_point4 */ 23128c2ecf20Sopenharmony_ci return 0; 23138c2ecf20Sopenharmony_ci } 23148c2ecf20Sopenharmony_ci if (has_old_autopwm(data)) { 23158c2ecf20Sopenharmony_ci if (a >= 9) /* no pwm_auto_start, pwm_auto_slope */ 23168c2ecf20Sopenharmony_ci return 0; 23178c2ecf20Sopenharmony_ci } 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci return attr->mode; 23208c2ecf20Sopenharmony_ci} 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_cistatic struct attribute *it87_attributes_auto_pwm[] = { 23238c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 23248c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 23258c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, 23268c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr, 23278c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, 23288c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point1_temp_hyst.dev_attr.attr, 23298c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, 23308c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr, 23318c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr, 23328c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_start.dev_attr.attr, 23338c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_slope.dev_attr.attr, 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, /* 11 */ 23368c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, 23378c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr, 23388c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr, 23398c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, 23408c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point1_temp_hyst.dev_attr.attr, 23418c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, 23428c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr, 23438c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr, 23448c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_start.dev_attr.attr, 23458c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_slope.dev_attr.attr, 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, /* 22 */ 23488c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, 23498c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr, 23508c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr, 23518c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, 23528c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point1_temp_hyst.dev_attr.attr, 23538c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, 23548c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr, 23558c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr, 23568c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_start.dev_attr.attr, 23578c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm3_auto_slope.dev_attr.attr, 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, /* 33 */ 23608c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point1_temp_hyst.dev_attr.attr, 23618c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr, 23628c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_point3_temp.dev_attr.attr, 23638c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_start.dev_attr.attr, 23648c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm4_auto_slope.dev_attr.attr, 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_point1_temp.dev_attr.attr, 23678c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_point1_temp_hyst.dev_attr.attr, 23688c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_point2_temp.dev_attr.attr, 23698c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_point3_temp.dev_attr.attr, 23708c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_start.dev_attr.attr, 23718c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm5_auto_slope.dev_attr.attr, 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_point1_temp.dev_attr.attr, 23748c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_point1_temp_hyst.dev_attr.attr, 23758c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_point2_temp.dev_attr.attr, 23768c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_point3_temp.dev_attr.attr, 23778c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_start.dev_attr.attr, 23788c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm6_auto_slope.dev_attr.attr, 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci NULL, 23818c2ecf20Sopenharmony_ci}; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_cistatic const struct attribute_group it87_group_auto_pwm = { 23848c2ecf20Sopenharmony_ci .attrs = it87_attributes_auto_pwm, 23858c2ecf20Sopenharmony_ci .is_visible = it87_auto_pwm_is_visible, 23868c2ecf20Sopenharmony_ci}; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci/* SuperIO detection - will change isa_address if a chip is found */ 23898c2ecf20Sopenharmony_cistatic int __init it87_find(int sioaddr, unsigned short *address, 23908c2ecf20Sopenharmony_ci struct it87_sio_data *sio_data) 23918c2ecf20Sopenharmony_ci{ 23928c2ecf20Sopenharmony_ci int err; 23938c2ecf20Sopenharmony_ci u16 chip_type; 23948c2ecf20Sopenharmony_ci const char *board_vendor, *board_name; 23958c2ecf20Sopenharmony_ci const struct it87_devices *config; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci err = superio_enter(sioaddr); 23988c2ecf20Sopenharmony_ci if (err) 23998c2ecf20Sopenharmony_ci return err; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci err = -ENODEV; 24028c2ecf20Sopenharmony_ci chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci switch (chip_type) { 24058c2ecf20Sopenharmony_ci case IT8705F_DEVID: 24068c2ecf20Sopenharmony_ci sio_data->type = it87; 24078c2ecf20Sopenharmony_ci break; 24088c2ecf20Sopenharmony_ci case IT8712F_DEVID: 24098c2ecf20Sopenharmony_ci sio_data->type = it8712; 24108c2ecf20Sopenharmony_ci break; 24118c2ecf20Sopenharmony_ci case IT8716F_DEVID: 24128c2ecf20Sopenharmony_ci case IT8726F_DEVID: 24138c2ecf20Sopenharmony_ci sio_data->type = it8716; 24148c2ecf20Sopenharmony_ci break; 24158c2ecf20Sopenharmony_ci case IT8718F_DEVID: 24168c2ecf20Sopenharmony_ci sio_data->type = it8718; 24178c2ecf20Sopenharmony_ci break; 24188c2ecf20Sopenharmony_ci case IT8720F_DEVID: 24198c2ecf20Sopenharmony_ci sio_data->type = it8720; 24208c2ecf20Sopenharmony_ci break; 24218c2ecf20Sopenharmony_ci case IT8721F_DEVID: 24228c2ecf20Sopenharmony_ci sio_data->type = it8721; 24238c2ecf20Sopenharmony_ci break; 24248c2ecf20Sopenharmony_ci case IT8728F_DEVID: 24258c2ecf20Sopenharmony_ci sio_data->type = it8728; 24268c2ecf20Sopenharmony_ci break; 24278c2ecf20Sopenharmony_ci case IT8732F_DEVID: 24288c2ecf20Sopenharmony_ci sio_data->type = it8732; 24298c2ecf20Sopenharmony_ci break; 24308c2ecf20Sopenharmony_ci case IT8792E_DEVID: 24318c2ecf20Sopenharmony_ci sio_data->type = it8792; 24328c2ecf20Sopenharmony_ci break; 24338c2ecf20Sopenharmony_ci case IT8771E_DEVID: 24348c2ecf20Sopenharmony_ci sio_data->type = it8771; 24358c2ecf20Sopenharmony_ci break; 24368c2ecf20Sopenharmony_ci case IT8772E_DEVID: 24378c2ecf20Sopenharmony_ci sio_data->type = it8772; 24388c2ecf20Sopenharmony_ci break; 24398c2ecf20Sopenharmony_ci case IT8781F_DEVID: 24408c2ecf20Sopenharmony_ci sio_data->type = it8781; 24418c2ecf20Sopenharmony_ci break; 24428c2ecf20Sopenharmony_ci case IT8782F_DEVID: 24438c2ecf20Sopenharmony_ci sio_data->type = it8782; 24448c2ecf20Sopenharmony_ci break; 24458c2ecf20Sopenharmony_ci case IT8783E_DEVID: 24468c2ecf20Sopenharmony_ci sio_data->type = it8783; 24478c2ecf20Sopenharmony_ci break; 24488c2ecf20Sopenharmony_ci case IT8786E_DEVID: 24498c2ecf20Sopenharmony_ci sio_data->type = it8786; 24508c2ecf20Sopenharmony_ci break; 24518c2ecf20Sopenharmony_ci case IT8790E_DEVID: 24528c2ecf20Sopenharmony_ci sio_data->type = it8790; 24538c2ecf20Sopenharmony_ci break; 24548c2ecf20Sopenharmony_ci case IT8603E_DEVID: 24558c2ecf20Sopenharmony_ci case IT8623E_DEVID: 24568c2ecf20Sopenharmony_ci sio_data->type = it8603; 24578c2ecf20Sopenharmony_ci break; 24588c2ecf20Sopenharmony_ci case IT8620E_DEVID: 24598c2ecf20Sopenharmony_ci sio_data->type = it8620; 24608c2ecf20Sopenharmony_ci break; 24618c2ecf20Sopenharmony_ci case IT8622E_DEVID: 24628c2ecf20Sopenharmony_ci sio_data->type = it8622; 24638c2ecf20Sopenharmony_ci break; 24648c2ecf20Sopenharmony_ci case IT8628E_DEVID: 24658c2ecf20Sopenharmony_ci sio_data->type = it8628; 24668c2ecf20Sopenharmony_ci break; 24678c2ecf20Sopenharmony_ci case 0xffff: /* No device at all */ 24688c2ecf20Sopenharmony_ci goto exit; 24698c2ecf20Sopenharmony_ci default: 24708c2ecf20Sopenharmony_ci pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type); 24718c2ecf20Sopenharmony_ci goto exit; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci superio_select(sioaddr, PME); 24758c2ecf20Sopenharmony_ci if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) { 24768c2ecf20Sopenharmony_ci pr_info("Device not activated, skipping\n"); 24778c2ecf20Sopenharmony_ci goto exit; 24788c2ecf20Sopenharmony_ci } 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci *address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1); 24818c2ecf20Sopenharmony_ci if (*address == 0) { 24828c2ecf20Sopenharmony_ci pr_info("Base address not set, skipping\n"); 24838c2ecf20Sopenharmony_ci goto exit; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci err = 0; 24878c2ecf20Sopenharmony_ci sio_data->sioaddr = sioaddr; 24888c2ecf20Sopenharmony_ci sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f; 24898c2ecf20Sopenharmony_ci pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type, 24908c2ecf20Sopenharmony_ci it87_devices[sio_data->type].suffix, 24918c2ecf20Sopenharmony_ci *address, sio_data->revision); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci config = &it87_devices[sio_data->type]; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci /* in7 (VSB or VCCH5V) is always internal on some chips */ 24968c2ecf20Sopenharmony_ci if (has_in7_internal(config)) 24978c2ecf20Sopenharmony_ci sio_data->internal |= BIT(1); 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci /* in8 (Vbat) is always internal */ 25008c2ecf20Sopenharmony_ci sio_data->internal |= BIT(2); 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci /* in9 (AVCC3), always internal if supported */ 25038c2ecf20Sopenharmony_ci if (has_avcc3(config)) 25048c2ecf20Sopenharmony_ci sio_data->internal |= BIT(3); /* in9 is AVCC */ 25058c2ecf20Sopenharmony_ci else 25068c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(9); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci if (!has_five_pwm(config)) 25098c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5); 25108c2ecf20Sopenharmony_ci else if (!has_six_pwm(config)) 25118c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(5); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci if (!has_vid(config)) 25148c2ecf20Sopenharmony_ci sio_data->skip_vid = 1; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci /* Read GPIO config and VID value from LDN 7 (GPIO) */ 25178c2ecf20Sopenharmony_ci if (sio_data->type == it87) { 25188c2ecf20Sopenharmony_ci /* The IT8705F has a different LD number for GPIO */ 25198c2ecf20Sopenharmony_ci superio_select(sioaddr, 5); 25208c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 25218c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 25228c2ecf20Sopenharmony_ci } else if (sio_data->type == it8783) { 25238c2ecf20Sopenharmony_ci int reg25, reg27, reg2a, reg2c, regef; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci superio_select(sioaddr, GPIO); 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ci reg25 = superio_inb(sioaddr, IT87_SIO_GPIO1_REG); 25288c2ecf20Sopenharmony_ci reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); 25298c2ecf20Sopenharmony_ci reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG); 25308c2ecf20Sopenharmony_ci reg2c = superio_inb(sioaddr, IT87_SIO_PINX2_REG); 25318c2ecf20Sopenharmony_ci regef = superio_inb(sioaddr, IT87_SIO_SPI_REG); 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci /* Check if fan3 is there or not */ 25348c2ecf20Sopenharmony_ci if ((reg27 & BIT(0)) || !(reg2c & BIT(2))) 25358c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(2); 25368c2ecf20Sopenharmony_ci if ((reg25 & BIT(4)) || 25378c2ecf20Sopenharmony_ci (!(reg2a & BIT(1)) && (regef & BIT(0)))) 25388c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(2); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci /* Check if fan2 is there or not */ 25418c2ecf20Sopenharmony_ci if (reg27 & BIT(7)) 25428c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(1); 25438c2ecf20Sopenharmony_ci if (reg27 & BIT(3)) 25448c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(1); 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci /* VIN5 */ 25478c2ecf20Sopenharmony_ci if ((reg27 & BIT(0)) || (reg2c & BIT(2))) 25488c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(5); /* No VIN5 */ 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci /* VIN6 */ 25518c2ecf20Sopenharmony_ci if (reg27 & BIT(1)) 25528c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(6); /* No VIN6 */ 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci /* 25558c2ecf20Sopenharmony_ci * VIN7 25568c2ecf20Sopenharmony_ci * Does not depend on bit 2 of Reg2C, contrary to datasheet. 25578c2ecf20Sopenharmony_ci */ 25588c2ecf20Sopenharmony_ci if (reg27 & BIT(2)) { 25598c2ecf20Sopenharmony_ci /* 25608c2ecf20Sopenharmony_ci * The data sheet is a bit unclear regarding the 25618c2ecf20Sopenharmony_ci * internal voltage divider for VCCH5V. It says 25628c2ecf20Sopenharmony_ci * "This bit enables and switches VIN7 (pin 91) to the 25638c2ecf20Sopenharmony_ci * internal voltage divider for VCCH5V". 25648c2ecf20Sopenharmony_ci * This is different to other chips, where the internal 25658c2ecf20Sopenharmony_ci * voltage divider would connect VIN7 to an internal 25668c2ecf20Sopenharmony_ci * voltage source. Maybe that is the case here as well. 25678c2ecf20Sopenharmony_ci * 25688c2ecf20Sopenharmony_ci * Since we don't know for sure, re-route it if that is 25698c2ecf20Sopenharmony_ci * not the case, and ask the user to report if the 25708c2ecf20Sopenharmony_ci * resulting voltage is sane. 25718c2ecf20Sopenharmony_ci */ 25728c2ecf20Sopenharmony_ci if (!(reg2c & BIT(1))) { 25738c2ecf20Sopenharmony_ci reg2c |= BIT(1); 25748c2ecf20Sopenharmony_ci superio_outb(sioaddr, IT87_SIO_PINX2_REG, 25758c2ecf20Sopenharmony_ci reg2c); 25768c2ecf20Sopenharmony_ci sio_data->need_in7_reroute = true; 25778c2ecf20Sopenharmony_ci pr_notice("Routing internal VCCH5V to in7.\n"); 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n"); 25808c2ecf20Sopenharmony_ci pr_notice("Please report if it displays a reasonable voltage.\n"); 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (reg2c & BIT(0)) 25848c2ecf20Sopenharmony_ci sio_data->internal |= BIT(0); 25858c2ecf20Sopenharmony_ci if (reg2c & BIT(1)) 25868c2ecf20Sopenharmony_ci sio_data->internal |= BIT(1); 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 25898c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 25908c2ecf20Sopenharmony_ci } else if (sio_data->type == it8603) { 25918c2ecf20Sopenharmony_ci int reg27, reg29; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci superio_select(sioaddr, GPIO); 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci /* Check if fan3 is there or not */ 25988c2ecf20Sopenharmony_ci if (reg27 & BIT(6)) 25998c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(2); 26008c2ecf20Sopenharmony_ci if (reg27 & BIT(7)) 26018c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(2); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci /* Check if fan2 is there or not */ 26048c2ecf20Sopenharmony_ci reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); 26058c2ecf20Sopenharmony_ci if (reg29 & BIT(1)) 26068c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(1); 26078c2ecf20Sopenharmony_ci if (reg29 & BIT(2)) 26088c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(1); 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(5); /* No VIN5 */ 26118c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(6); /* No VIN6 */ 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 26148c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 26158c2ecf20Sopenharmony_ci } else if (sio_data->type == it8620 || sio_data->type == it8628) { 26168c2ecf20Sopenharmony_ci int reg; 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci superio_select(sioaddr, GPIO); 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci /* Check for pwm5 */ 26218c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG); 26228c2ecf20Sopenharmony_ci if (reg & BIT(6)) 26238c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(4); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci /* Check for fan4, fan5 */ 26268c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG); 26278c2ecf20Sopenharmony_ci if (!(reg & BIT(5))) 26288c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(3); 26298c2ecf20Sopenharmony_ci if (!(reg & BIT(4))) 26308c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(4); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* Check for pwm3, fan3 */ 26338c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); 26348c2ecf20Sopenharmony_ci if (reg & BIT(6)) 26358c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(2); 26368c2ecf20Sopenharmony_ci if (reg & BIT(7)) 26378c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(2); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci /* Check for pwm4 */ 26408c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG); 26418c2ecf20Sopenharmony_ci if (reg & BIT(2)) 26428c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(3); 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci /* Check for pwm2, fan2 */ 26458c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); 26468c2ecf20Sopenharmony_ci if (reg & BIT(1)) 26478c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(1); 26488c2ecf20Sopenharmony_ci if (reg & BIT(2)) 26498c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(1); 26508c2ecf20Sopenharmony_ci /* Check for pwm6, fan6 */ 26518c2ecf20Sopenharmony_ci if (!(reg & BIT(7))) { 26528c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(5); 26538c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(5); 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci /* Check if AVCC is on VIN3 */ 26578c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); 26588c2ecf20Sopenharmony_ci if (reg & BIT(0)) 26598c2ecf20Sopenharmony_ci sio_data->internal |= BIT(0); 26608c2ecf20Sopenharmony_ci else 26618c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(9); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 26648c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 26658c2ecf20Sopenharmony_ci } else if (sio_data->type == it8622) { 26668c2ecf20Sopenharmony_ci int reg; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci superio_select(sioaddr, GPIO); 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci /* Check for pwm4, fan4 */ 26718c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG); 26728c2ecf20Sopenharmony_ci if (reg & BIT(6)) 26738c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(3); 26748c2ecf20Sopenharmony_ci if (reg & BIT(5)) 26758c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(3); 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci /* Check for pwm3, fan3, pwm5, fan5 */ 26788c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); 26798c2ecf20Sopenharmony_ci if (reg & BIT(6)) 26808c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(2); 26818c2ecf20Sopenharmony_ci if (reg & BIT(7)) 26828c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(2); 26838c2ecf20Sopenharmony_ci if (reg & BIT(3)) 26848c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(4); 26858c2ecf20Sopenharmony_ci if (reg & BIT(1)) 26868c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(4); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci /* Check for pwm2, fan2 */ 26898c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); 26908c2ecf20Sopenharmony_ci if (reg & BIT(1)) 26918c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(1); 26928c2ecf20Sopenharmony_ci if (reg & BIT(2)) 26938c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(1); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci /* Check for AVCC */ 26968c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); 26978c2ecf20Sopenharmony_ci if (!(reg & BIT(0))) 26988c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(9); 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 27018c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 27028c2ecf20Sopenharmony_ci } else { 27038c2ecf20Sopenharmony_ci int reg; 27048c2ecf20Sopenharmony_ci bool uart6; 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_ci superio_select(sioaddr, GPIO); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci /* Check for fan4, fan5 */ 27098c2ecf20Sopenharmony_ci if (has_five_fans(config)) { 27108c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG); 27118c2ecf20Sopenharmony_ci switch (sio_data->type) { 27128c2ecf20Sopenharmony_ci case it8718: 27138c2ecf20Sopenharmony_ci if (reg & BIT(5)) 27148c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(3); 27158c2ecf20Sopenharmony_ci if (reg & BIT(4)) 27168c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(4); 27178c2ecf20Sopenharmony_ci break; 27188c2ecf20Sopenharmony_ci case it8720: 27198c2ecf20Sopenharmony_ci case it8721: 27208c2ecf20Sopenharmony_ci case it8728: 27218c2ecf20Sopenharmony_ci if (!(reg & BIT(5))) 27228c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(3); 27238c2ecf20Sopenharmony_ci if (!(reg & BIT(4))) 27248c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(4); 27258c2ecf20Sopenharmony_ci break; 27268c2ecf20Sopenharmony_ci default: 27278c2ecf20Sopenharmony_ci break; 27288c2ecf20Sopenharmony_ci } 27298c2ecf20Sopenharmony_ci } 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); 27328c2ecf20Sopenharmony_ci if (!sio_data->skip_vid) { 27338c2ecf20Sopenharmony_ci /* We need at least 4 VID pins */ 27348c2ecf20Sopenharmony_ci if (reg & 0x0f) { 27358c2ecf20Sopenharmony_ci pr_info("VID is disabled (pins used for GPIO)\n"); 27368c2ecf20Sopenharmony_ci sio_data->skip_vid = 1; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci } 27398c2ecf20Sopenharmony_ci 27408c2ecf20Sopenharmony_ci /* Check if fan3 is there or not */ 27418c2ecf20Sopenharmony_ci if (reg & BIT(6)) 27428c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(2); 27438c2ecf20Sopenharmony_ci if (reg & BIT(7)) 27448c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(2); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci /* Check if fan2 is there or not */ 27478c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); 27488c2ecf20Sopenharmony_ci if (reg & BIT(1)) 27498c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(1); 27508c2ecf20Sopenharmony_ci if (reg & BIT(2)) 27518c2ecf20Sopenharmony_ci sio_data->skip_fan |= BIT(1); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci if ((sio_data->type == it8718 || sio_data->type == it8720) && 27548c2ecf20Sopenharmony_ci !(sio_data->skip_vid)) 27558c2ecf20Sopenharmony_ci sio_data->vid_value = superio_inb(sioaddr, 27568c2ecf20Sopenharmony_ci IT87_SIO_VID_REG); 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci uart6 = sio_data->type == it8782 && (reg & BIT(2)); 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci /* 27638c2ecf20Sopenharmony_ci * The IT8720F has no VIN7 pin, so VCCH5V should always be 27648c2ecf20Sopenharmony_ci * routed internally to VIN7 with an internal divider. 27658c2ecf20Sopenharmony_ci * Curiously, there still is a configuration bit to control 27668c2ecf20Sopenharmony_ci * this, which means it can be set incorrectly. And even 27678c2ecf20Sopenharmony_ci * more curiously, many boards out there are improperly 27688c2ecf20Sopenharmony_ci * configured, even though the IT8720F datasheet claims 27698c2ecf20Sopenharmony_ci * that the internal routing of VCCH5V to VIN7 is the default 27708c2ecf20Sopenharmony_ci * setting. So we force the internal routing in this case. 27718c2ecf20Sopenharmony_ci * 27728c2ecf20Sopenharmony_ci * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. 27738c2ecf20Sopenharmony_ci * If UART6 is enabled, re-route VIN7 to the internal divider 27748c2ecf20Sopenharmony_ci * if that is not already the case. 27758c2ecf20Sopenharmony_ci */ 27768c2ecf20Sopenharmony_ci if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) { 27778c2ecf20Sopenharmony_ci reg |= BIT(1); 27788c2ecf20Sopenharmony_ci superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg); 27798c2ecf20Sopenharmony_ci sio_data->need_in7_reroute = true; 27808c2ecf20Sopenharmony_ci pr_notice("Routing internal VCCH5V to in7\n"); 27818c2ecf20Sopenharmony_ci } 27828c2ecf20Sopenharmony_ci if (reg & BIT(0)) 27838c2ecf20Sopenharmony_ci sio_data->internal |= BIT(0); 27848c2ecf20Sopenharmony_ci if (reg & BIT(1)) 27858c2ecf20Sopenharmony_ci sio_data->internal |= BIT(1); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci /* 27888c2ecf20Sopenharmony_ci * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7. 27898c2ecf20Sopenharmony_ci * While VIN7 can be routed to the internal voltage divider, 27908c2ecf20Sopenharmony_ci * VIN5 and VIN6 are not available if UART6 is enabled. 27918c2ecf20Sopenharmony_ci * 27928c2ecf20Sopenharmony_ci * Also, temp3 is not available if UART6 is enabled and TEMPIN3 27938c2ecf20Sopenharmony_ci * is the temperature source. Since we can not read the 27948c2ecf20Sopenharmony_ci * temperature source here, skip_temp is preliminary. 27958c2ecf20Sopenharmony_ci */ 27968c2ecf20Sopenharmony_ci if (uart6) { 27978c2ecf20Sopenharmony_ci sio_data->skip_in |= BIT(5) | BIT(6); 27988c2ecf20Sopenharmony_ci sio_data->skip_temp |= BIT(2); 27998c2ecf20Sopenharmony_ci } 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci sio_data->beep_pin = superio_inb(sioaddr, 28028c2ecf20Sopenharmony_ci IT87_SIO_BEEP_PIN_REG) & 0x3f; 28038c2ecf20Sopenharmony_ci } 28048c2ecf20Sopenharmony_ci if (sio_data->beep_pin) 28058c2ecf20Sopenharmony_ci pr_info("Beeping is supported\n"); 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci /* Disable specific features based on DMI strings */ 28088c2ecf20Sopenharmony_ci board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 28098c2ecf20Sopenharmony_ci board_name = dmi_get_system_info(DMI_BOARD_NAME); 28108c2ecf20Sopenharmony_ci if (board_vendor && board_name) { 28118c2ecf20Sopenharmony_ci if (strcmp(board_vendor, "nVIDIA") == 0 && 28128c2ecf20Sopenharmony_ci strcmp(board_name, "FN68PT") == 0) { 28138c2ecf20Sopenharmony_ci /* 28148c2ecf20Sopenharmony_ci * On the Shuttle SN68PT, FAN_CTL2 is apparently not 28158c2ecf20Sopenharmony_ci * connected to a fan, but to something else. One user 28168c2ecf20Sopenharmony_ci * has reported instant system power-off when changing 28178c2ecf20Sopenharmony_ci * the PWM2 duty cycle, so we disable it. 28188c2ecf20Sopenharmony_ci * I use the board name string as the trigger in case 28198c2ecf20Sopenharmony_ci * the same board is ever used in other systems. 28208c2ecf20Sopenharmony_ci */ 28218c2ecf20Sopenharmony_ci pr_info("Disabling pwm2 due to hardware constraints\n"); 28228c2ecf20Sopenharmony_ci sio_data->skip_pwm = BIT(1); 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci } 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ciexit: 28278c2ecf20Sopenharmony_ci superio_exit(sioaddr); 28288c2ecf20Sopenharmony_ci return err; 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci/* 28328c2ecf20Sopenharmony_ci * Some chips seem to have default value 0xff for all limit 28338c2ecf20Sopenharmony_ci * registers. For low voltage limits it makes no sense and triggers 28348c2ecf20Sopenharmony_ci * alarms, so change to 0 instead. For high temperature limits, it 28358c2ecf20Sopenharmony_ci * means -1 degree C, which surprisingly doesn't trigger an alarm, 28368c2ecf20Sopenharmony_ci * but is still confusing, so change to 127 degrees C. 28378c2ecf20Sopenharmony_ci */ 28388c2ecf20Sopenharmony_cistatic void it87_check_limit_regs(struct it87_data *data) 28398c2ecf20Sopenharmony_ci{ 28408c2ecf20Sopenharmony_ci int i, reg; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci for (i = 0; i < NUM_VIN_LIMIT; i++) { 28438c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_VIN_MIN(i)); 28448c2ecf20Sopenharmony_ci if (reg == 0xff) 28458c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_VIN_MIN(i), 0); 28468c2ecf20Sopenharmony_ci } 28478c2ecf20Sopenharmony_ci for (i = 0; i < NUM_TEMP_LIMIT; i++) { 28488c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_TEMP_HIGH(i)); 28498c2ecf20Sopenharmony_ci if (reg == 0xff) 28508c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127); 28518c2ecf20Sopenharmony_ci } 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_ci/* Check if voltage monitors are reset manually or by some reason */ 28558c2ecf20Sopenharmony_cistatic void it87_check_voltage_monitors_reset(struct it87_data *data) 28568c2ecf20Sopenharmony_ci{ 28578c2ecf20Sopenharmony_ci int reg; 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_VIN_ENABLE); 28608c2ecf20Sopenharmony_ci if ((reg & 0xff) == 0) { 28618c2ecf20Sopenharmony_ci /* Enable all voltage monitors */ 28628c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff); 28638c2ecf20Sopenharmony_ci } 28648c2ecf20Sopenharmony_ci} 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci/* Check if tachometers are reset manually or by some reason */ 28678c2ecf20Sopenharmony_cistatic void it87_check_tachometers_reset(struct platform_device *pdev) 28688c2ecf20Sopenharmony_ci{ 28698c2ecf20Sopenharmony_ci struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev); 28708c2ecf20Sopenharmony_ci struct it87_data *data = platform_get_drvdata(pdev); 28718c2ecf20Sopenharmony_ci u8 mask, fan_main_ctrl; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci mask = 0x70 & ~(sio_data->skip_fan << 4); 28748c2ecf20Sopenharmony_ci fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL); 28758c2ecf20Sopenharmony_ci if ((fan_main_ctrl & mask) == 0) { 28768c2ecf20Sopenharmony_ci /* Enable all fan tachometers */ 28778c2ecf20Sopenharmony_ci fan_main_ctrl |= mask; 28788c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, 28798c2ecf20Sopenharmony_ci fan_main_ctrl); 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci} 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci/* Set tachometers to 16-bit mode if needed */ 28848c2ecf20Sopenharmony_cistatic void it87_check_tachometers_16bit_mode(struct platform_device *pdev) 28858c2ecf20Sopenharmony_ci{ 28868c2ecf20Sopenharmony_ci struct it87_data *data = platform_get_drvdata(pdev); 28878c2ecf20Sopenharmony_ci int reg; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci if (!has_fan16_config(data)) 28908c2ecf20Sopenharmony_ci return; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci reg = it87_read_value(data, IT87_REG_FAN_16BIT); 28938c2ecf20Sopenharmony_ci if (~reg & 0x07 & data->has_fan) { 28948c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 28958c2ecf20Sopenharmony_ci "Setting fan1-3 to 16-bit mode\n"); 28968c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_16BIT, 28978c2ecf20Sopenharmony_ci reg | 0x07); 28988c2ecf20Sopenharmony_ci } 28998c2ecf20Sopenharmony_ci} 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_cistatic void it87_start_monitoring(struct it87_data *data) 29028c2ecf20Sopenharmony_ci{ 29038c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_CONFIG, 29048c2ecf20Sopenharmony_ci (it87_read_value(data, IT87_REG_CONFIG) & 0x3e) 29058c2ecf20Sopenharmony_ci | (update_vbat ? 0x41 : 0x01)); 29068c2ecf20Sopenharmony_ci} 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci/* Called when we have found a new IT87. */ 29098c2ecf20Sopenharmony_cistatic void it87_init_device(struct platform_device *pdev) 29108c2ecf20Sopenharmony_ci{ 29118c2ecf20Sopenharmony_ci struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev); 29128c2ecf20Sopenharmony_ci struct it87_data *data = platform_get_drvdata(pdev); 29138c2ecf20Sopenharmony_ci int tmp, i; 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci /* 29168c2ecf20Sopenharmony_ci * For each PWM channel: 29178c2ecf20Sopenharmony_ci * - If it is in automatic mode, setting to manual mode should set 29188c2ecf20Sopenharmony_ci * the fan to full speed by default. 29198c2ecf20Sopenharmony_ci * - If it is in manual mode, we need a mapping to temperature 29208c2ecf20Sopenharmony_ci * channels to use when later setting to automatic mode later. 29218c2ecf20Sopenharmony_ci * Use a 1:1 mapping by default (we are clueless.) 29228c2ecf20Sopenharmony_ci * In both cases, the value can (and should) be changed by the user 29238c2ecf20Sopenharmony_ci * prior to switching to a different mode. 29248c2ecf20Sopenharmony_ci * Note that this is no longer needed for the IT8721F and later, as 29258c2ecf20Sopenharmony_ci * these have separate registers for the temperature mapping and the 29268c2ecf20Sopenharmony_ci * manual duty cycle. 29278c2ecf20Sopenharmony_ci */ 29288c2ecf20Sopenharmony_ci for (i = 0; i < NUM_AUTO_PWM; i++) { 29298c2ecf20Sopenharmony_ci data->pwm_temp_map[i] = i; 29308c2ecf20Sopenharmony_ci data->pwm_duty[i] = 0x7f; /* Full speed */ 29318c2ecf20Sopenharmony_ci data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */ 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci it87_check_limit_regs(data); 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci /* 29378c2ecf20Sopenharmony_ci * Temperature channels are not forcibly enabled, as they can be 29388c2ecf20Sopenharmony_ci * set to two different sensor types and we can't guess which one 29398c2ecf20Sopenharmony_ci * is correct for a given system. These channels can be enabled at 29408c2ecf20Sopenharmony_ci * run-time through the temp{1-3}_type sysfs accessors if needed. 29418c2ecf20Sopenharmony_ci */ 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci it87_check_voltage_monitors_reset(data); 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci it87_check_tachometers_reset(pdev); 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL); 29488c2ecf20Sopenharmony_ci data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; 29498c2ecf20Sopenharmony_ci 29508c2ecf20Sopenharmony_ci it87_check_tachometers_16bit_mode(pdev); 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci /* Check for additional fans */ 29538c2ecf20Sopenharmony_ci if (has_five_fans(data)) { 29548c2ecf20Sopenharmony_ci tmp = it87_read_value(data, IT87_REG_FAN_16BIT); 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci if (tmp & BIT(4)) 29578c2ecf20Sopenharmony_ci data->has_fan |= BIT(3); /* fan4 enabled */ 29588c2ecf20Sopenharmony_ci if (tmp & BIT(5)) 29598c2ecf20Sopenharmony_ci data->has_fan |= BIT(4); /* fan5 enabled */ 29608c2ecf20Sopenharmony_ci if (has_six_fans(data) && (tmp & BIT(2))) 29618c2ecf20Sopenharmony_ci data->has_fan |= BIT(5); /* fan6 enabled */ 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci /* Fan input pins may be used for alternative functions */ 29658c2ecf20Sopenharmony_ci data->has_fan &= ~sio_data->skip_fan; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci /* Check if pwm5, pwm6 are enabled */ 29688c2ecf20Sopenharmony_ci if (has_six_pwm(data)) { 29698c2ecf20Sopenharmony_ci /* The following code may be IT8620E specific */ 29708c2ecf20Sopenharmony_ci tmp = it87_read_value(data, IT87_REG_FAN_DIV); 29718c2ecf20Sopenharmony_ci if ((tmp & 0xc0) == 0xc0) 29728c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(4); 29738c2ecf20Sopenharmony_ci if (!(tmp & BIT(3))) 29748c2ecf20Sopenharmony_ci sio_data->skip_pwm |= BIT(5); 29758c2ecf20Sopenharmony_ci } 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci it87_start_monitoring(data); 29788c2ecf20Sopenharmony_ci} 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci/* Return 1 if and only if the PWM interface is safe to use */ 29818c2ecf20Sopenharmony_cistatic int it87_check_pwm(struct device *dev) 29828c2ecf20Sopenharmony_ci{ 29838c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 29848c2ecf20Sopenharmony_ci /* 29858c2ecf20Sopenharmony_ci * Some BIOSes fail to correctly configure the IT87 fans. All fans off 29868c2ecf20Sopenharmony_ci * and polarity set to active low is sign that this is the case so we 29878c2ecf20Sopenharmony_ci * disable pwm control to protect the user. 29888c2ecf20Sopenharmony_ci */ 29898c2ecf20Sopenharmony_ci int tmp = it87_read_value(data, IT87_REG_FAN_CTL); 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_ci if ((tmp & 0x87) == 0) { 29928c2ecf20Sopenharmony_ci if (fix_pwm_polarity) { 29938c2ecf20Sopenharmony_ci /* 29948c2ecf20Sopenharmony_ci * The user asks us to attempt a chip reconfiguration. 29958c2ecf20Sopenharmony_ci * This means switching to active high polarity and 29968c2ecf20Sopenharmony_ci * inverting all fan speed values. 29978c2ecf20Sopenharmony_ci */ 29988c2ecf20Sopenharmony_ci int i; 29998c2ecf20Sopenharmony_ci u8 pwm[3]; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pwm); i++) 30028c2ecf20Sopenharmony_ci pwm[i] = it87_read_value(data, 30038c2ecf20Sopenharmony_ci IT87_REG_PWM[i]); 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci /* 30068c2ecf20Sopenharmony_ci * If any fan is in automatic pwm mode, the polarity 30078c2ecf20Sopenharmony_ci * might be correct, as suspicious as it seems, so we 30088c2ecf20Sopenharmony_ci * better don't change anything (but still disable the 30098c2ecf20Sopenharmony_ci * PWM interface). 30108c2ecf20Sopenharmony_ci */ 30118c2ecf20Sopenharmony_ci if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { 30128c2ecf20Sopenharmony_ci dev_info(dev, 30138c2ecf20Sopenharmony_ci "Reconfiguring PWM to active high polarity\n"); 30148c2ecf20Sopenharmony_ci it87_write_value(data, IT87_REG_FAN_CTL, 30158c2ecf20Sopenharmony_ci tmp | 0x87); 30168c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 30178c2ecf20Sopenharmony_ci it87_write_value(data, 30188c2ecf20Sopenharmony_ci IT87_REG_PWM[i], 30198c2ecf20Sopenharmony_ci 0x7f & ~pwm[i]); 30208c2ecf20Sopenharmony_ci return 1; 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci dev_info(dev, 30248c2ecf20Sopenharmony_ci "PWM configuration is too broken to be fixed\n"); 30258c2ecf20Sopenharmony_ci } 30268c2ecf20Sopenharmony_ci 30278c2ecf20Sopenharmony_ci return 0; 30288c2ecf20Sopenharmony_ci } else if (fix_pwm_polarity) { 30298c2ecf20Sopenharmony_ci dev_info(dev, 30308c2ecf20Sopenharmony_ci "PWM configuration looks sane, won't touch\n"); 30318c2ecf20Sopenharmony_ci } 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci return 1; 30348c2ecf20Sopenharmony_ci} 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_cistatic int it87_probe(struct platform_device *pdev) 30378c2ecf20Sopenharmony_ci{ 30388c2ecf20Sopenharmony_ci struct it87_data *data; 30398c2ecf20Sopenharmony_ci struct resource *res; 30408c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 30418c2ecf20Sopenharmony_ci struct it87_sio_data *sio_data = dev_get_platdata(dev); 30428c2ecf20Sopenharmony_ci int enable_pwm_interface; 30438c2ecf20Sopenharmony_ci struct device *hwmon_dev; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_IO, 0); 30468c2ecf20Sopenharmony_ci if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, 30478c2ecf20Sopenharmony_ci DRVNAME)) { 30488c2ecf20Sopenharmony_ci dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", 30498c2ecf20Sopenharmony_ci (unsigned long)res->start, 30508c2ecf20Sopenharmony_ci (unsigned long)(res->start + IT87_EC_EXTENT - 1)); 30518c2ecf20Sopenharmony_ci return -EBUSY; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL); 30558c2ecf20Sopenharmony_ci if (!data) 30568c2ecf20Sopenharmony_ci return -ENOMEM; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci data->addr = res->start; 30598c2ecf20Sopenharmony_ci data->sioaddr = sio_data->sioaddr; 30608c2ecf20Sopenharmony_ci data->type = sio_data->type; 30618c2ecf20Sopenharmony_ci data->features = it87_devices[sio_data->type].features; 30628c2ecf20Sopenharmony_ci data->peci_mask = it87_devices[sio_data->type].peci_mask; 30638c2ecf20Sopenharmony_ci data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask; 30648c2ecf20Sopenharmony_ci /* 30658c2ecf20Sopenharmony_ci * IT8705F Datasheet 0.4.1, 3h == Version G. 30668c2ecf20Sopenharmony_ci * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. 30678c2ecf20Sopenharmony_ci * These are the first revisions with 16-bit tachometer support. 30688c2ecf20Sopenharmony_ci */ 30698c2ecf20Sopenharmony_ci switch (data->type) { 30708c2ecf20Sopenharmony_ci case it87: 30718c2ecf20Sopenharmony_ci if (sio_data->revision >= 0x03) { 30728c2ecf20Sopenharmony_ci data->features &= ~FEAT_OLD_AUTOPWM; 30738c2ecf20Sopenharmony_ci data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS; 30748c2ecf20Sopenharmony_ci } 30758c2ecf20Sopenharmony_ci break; 30768c2ecf20Sopenharmony_ci case it8712: 30778c2ecf20Sopenharmony_ci if (sio_data->revision >= 0x08) { 30788c2ecf20Sopenharmony_ci data->features &= ~FEAT_OLD_AUTOPWM; 30798c2ecf20Sopenharmony_ci data->features |= FEAT_FAN16_CONFIG | FEAT_16BIT_FANS | 30808c2ecf20Sopenharmony_ci FEAT_FIVE_FANS; 30818c2ecf20Sopenharmony_ci } 30828c2ecf20Sopenharmony_ci break; 30838c2ecf20Sopenharmony_ci default: 30848c2ecf20Sopenharmony_ci break; 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci /* Now, we do the remaining detection. */ 30888c2ecf20Sopenharmony_ci if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) || 30898c2ecf20Sopenharmony_ci it87_read_value(data, IT87_REG_CHIPID) != 0x90) 30908c2ecf20Sopenharmony_ci return -ENODEV; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci /* Check PWM configuration */ 30978c2ecf20Sopenharmony_ci enable_pwm_interface = it87_check_pwm(dev); 30988c2ecf20Sopenharmony_ci if (!enable_pwm_interface) 30998c2ecf20Sopenharmony_ci dev_info(dev, 31008c2ecf20Sopenharmony_ci "Detected broken BIOS defaults, disabling PWM interface\n"); 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_ci /* Starting with IT8721F, we handle scaling of internal voltages */ 31038c2ecf20Sopenharmony_ci if (has_scaling(data)) { 31048c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(0)) 31058c2ecf20Sopenharmony_ci data->in_scaled |= BIT(3); /* in3 is AVCC */ 31068c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(1)) 31078c2ecf20Sopenharmony_ci data->in_scaled |= BIT(7); /* in7 is VSB */ 31088c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(2)) 31098c2ecf20Sopenharmony_ci data->in_scaled |= BIT(8); /* in8 is Vbat */ 31108c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(3)) 31118c2ecf20Sopenharmony_ci data->in_scaled |= BIT(9); /* in9 is AVCC */ 31128c2ecf20Sopenharmony_ci } else if (sio_data->type == it8781 || sio_data->type == it8782 || 31138c2ecf20Sopenharmony_ci sio_data->type == it8783) { 31148c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(0)) 31158c2ecf20Sopenharmony_ci data->in_scaled |= BIT(3); /* in3 is VCC5V */ 31168c2ecf20Sopenharmony_ci if (sio_data->internal & BIT(1)) 31178c2ecf20Sopenharmony_ci data->in_scaled |= BIT(7); /* in7 is VCCH5V */ 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci data->has_temp = 0x07; 31218c2ecf20Sopenharmony_ci if (sio_data->skip_temp & BIT(2)) { 31228c2ecf20Sopenharmony_ci if (sio_data->type == it8782 && 31238c2ecf20Sopenharmony_ci !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80)) 31248c2ecf20Sopenharmony_ci data->has_temp &= ~BIT(2); 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci data->in_internal = sio_data->internal; 31288c2ecf20Sopenharmony_ci data->need_in7_reroute = sio_data->need_in7_reroute; 31298c2ecf20Sopenharmony_ci data->has_in = 0x3ff & ~sio_data->skip_in; 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci if (has_six_temp(data)) { 31328c2ecf20Sopenharmony_ci u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci /* Check for additional temperature sensors */ 31358c2ecf20Sopenharmony_ci if ((reg & 0x03) >= 0x02) 31368c2ecf20Sopenharmony_ci data->has_temp |= BIT(3); 31378c2ecf20Sopenharmony_ci if (((reg >> 2) & 0x03) >= 0x02) 31388c2ecf20Sopenharmony_ci data->has_temp |= BIT(4); 31398c2ecf20Sopenharmony_ci if (((reg >> 4) & 0x03) >= 0x02) 31408c2ecf20Sopenharmony_ci data->has_temp |= BIT(5); 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci /* Check for additional voltage sensors */ 31438c2ecf20Sopenharmony_ci if ((reg & 0x03) == 0x01) 31448c2ecf20Sopenharmony_ci data->has_in |= BIT(10); 31458c2ecf20Sopenharmony_ci if (((reg >> 2) & 0x03) == 0x01) 31468c2ecf20Sopenharmony_ci data->has_in |= BIT(11); 31478c2ecf20Sopenharmony_ci if (((reg >> 4) & 0x03) == 0x01) 31488c2ecf20Sopenharmony_ci data->has_in |= BIT(12); 31498c2ecf20Sopenharmony_ci } 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci data->has_beep = !!sio_data->beep_pin; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci /* Initialize the IT87 chip */ 31548c2ecf20Sopenharmony_ci it87_init_device(pdev); 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci if (!sio_data->skip_vid) { 31578c2ecf20Sopenharmony_ci data->has_vid = true; 31588c2ecf20Sopenharmony_ci data->vrm = vid_which_vrm(); 31598c2ecf20Sopenharmony_ci /* VID reading from Super-I/O config space if available */ 31608c2ecf20Sopenharmony_ci data->vid = sio_data->vid_value; 31618c2ecf20Sopenharmony_ci } 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci /* Prepare for sysfs hooks */ 31648c2ecf20Sopenharmony_ci data->groups[0] = &it87_group; 31658c2ecf20Sopenharmony_ci data->groups[1] = &it87_group_in; 31668c2ecf20Sopenharmony_ci data->groups[2] = &it87_group_temp; 31678c2ecf20Sopenharmony_ci data->groups[3] = &it87_group_fan; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci if (enable_pwm_interface) { 31708c2ecf20Sopenharmony_ci data->has_pwm = BIT(ARRAY_SIZE(IT87_REG_PWM)) - 1; 31718c2ecf20Sopenharmony_ci data->has_pwm &= ~sio_data->skip_pwm; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci data->groups[4] = &it87_group_pwm; 31748c2ecf20Sopenharmony_ci if (has_old_autopwm(data) || has_newer_autopwm(data)) 31758c2ecf20Sopenharmony_ci data->groups[5] = &it87_group_auto_pwm; 31768c2ecf20Sopenharmony_ci } 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(dev, 31798c2ecf20Sopenharmony_ci it87_devices[sio_data->type].name, 31808c2ecf20Sopenharmony_ci data, data->groups); 31818c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 31828c2ecf20Sopenharmony_ci} 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_cistatic void __maybe_unused it87_resume_sio(struct platform_device *pdev) 31858c2ecf20Sopenharmony_ci{ 31868c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(&pdev->dev); 31878c2ecf20Sopenharmony_ci int err; 31888c2ecf20Sopenharmony_ci int reg2c; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci if (!data->need_in7_reroute) 31918c2ecf20Sopenharmony_ci return; 31928c2ecf20Sopenharmony_ci 31938c2ecf20Sopenharmony_ci err = superio_enter(data->sioaddr); 31948c2ecf20Sopenharmony_ci if (err) { 31958c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 31968c2ecf20Sopenharmony_ci "Unable to enter Super I/O to reroute in7 (%d)", 31978c2ecf20Sopenharmony_ci err); 31988c2ecf20Sopenharmony_ci return; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci superio_select(data->sioaddr, GPIO); 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci reg2c = superio_inb(data->sioaddr, IT87_SIO_PINX2_REG); 32048c2ecf20Sopenharmony_ci if (!(reg2c & BIT(1))) { 32058c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 32068c2ecf20Sopenharmony_ci "Routing internal VCCH5V to in7 again"); 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci reg2c |= BIT(1); 32098c2ecf20Sopenharmony_ci superio_outb(data->sioaddr, IT87_SIO_PINX2_REG, 32108c2ecf20Sopenharmony_ci reg2c); 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci superio_exit(data->sioaddr); 32148c2ecf20Sopenharmony_ci} 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_cistatic int __maybe_unused it87_resume(struct device *dev) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 32198c2ecf20Sopenharmony_ci struct it87_data *data = dev_get_drvdata(dev); 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci it87_resume_sio(pdev); 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci it87_check_pwm(dev); 32268c2ecf20Sopenharmony_ci it87_check_limit_regs(data); 32278c2ecf20Sopenharmony_ci it87_check_voltage_monitors_reset(data); 32288c2ecf20Sopenharmony_ci it87_check_tachometers_reset(pdev); 32298c2ecf20Sopenharmony_ci it87_check_tachometers_16bit_mode(pdev); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci it87_start_monitoring(data); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci /* force update */ 32348c2ecf20Sopenharmony_ci data->valid = 0; 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci it87_update_device(dev); 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci return 0; 32418c2ecf20Sopenharmony_ci} 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_cistatic struct platform_driver it87_driver = { 32468c2ecf20Sopenharmony_ci .driver = { 32478c2ecf20Sopenharmony_ci .name = DRVNAME, 32488c2ecf20Sopenharmony_ci .pm = &it87_dev_pm_ops, 32498c2ecf20Sopenharmony_ci }, 32508c2ecf20Sopenharmony_ci .probe = it87_probe, 32518c2ecf20Sopenharmony_ci}; 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_cistatic int __init it87_device_add(int index, unsigned short address, 32548c2ecf20Sopenharmony_ci const struct it87_sio_data *sio_data) 32558c2ecf20Sopenharmony_ci{ 32568c2ecf20Sopenharmony_ci struct platform_device *pdev; 32578c2ecf20Sopenharmony_ci struct resource res = { 32588c2ecf20Sopenharmony_ci .start = address + IT87_EC_OFFSET, 32598c2ecf20Sopenharmony_ci .end = address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1, 32608c2ecf20Sopenharmony_ci .name = DRVNAME, 32618c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 32628c2ecf20Sopenharmony_ci }; 32638c2ecf20Sopenharmony_ci int err; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci err = acpi_check_resource_conflict(&res); 32668c2ecf20Sopenharmony_ci if (err) 32678c2ecf20Sopenharmony_ci return err; 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci pdev = platform_device_alloc(DRVNAME, address); 32708c2ecf20Sopenharmony_ci if (!pdev) 32718c2ecf20Sopenharmony_ci return -ENOMEM; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci err = platform_device_add_resources(pdev, &res, 1); 32748c2ecf20Sopenharmony_ci if (err) { 32758c2ecf20Sopenharmony_ci pr_err("Device resource addition failed (%d)\n", err); 32768c2ecf20Sopenharmony_ci goto exit_device_put; 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci err = platform_device_add_data(pdev, sio_data, 32808c2ecf20Sopenharmony_ci sizeof(struct it87_sio_data)); 32818c2ecf20Sopenharmony_ci if (err) { 32828c2ecf20Sopenharmony_ci pr_err("Platform data allocation failed\n"); 32838c2ecf20Sopenharmony_ci goto exit_device_put; 32848c2ecf20Sopenharmony_ci } 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci err = platform_device_add(pdev); 32878c2ecf20Sopenharmony_ci if (err) { 32888c2ecf20Sopenharmony_ci pr_err("Device addition failed (%d)\n", err); 32898c2ecf20Sopenharmony_ci goto exit_device_put; 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci it87_pdev[index] = pdev; 32938c2ecf20Sopenharmony_ci return 0; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ciexit_device_put: 32968c2ecf20Sopenharmony_ci platform_device_put(pdev); 32978c2ecf20Sopenharmony_ci return err; 32988c2ecf20Sopenharmony_ci} 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_cistatic int __init sm_it87_init(void) 33018c2ecf20Sopenharmony_ci{ 33028c2ecf20Sopenharmony_ci int sioaddr[2] = { REG_2E, REG_4E }; 33038c2ecf20Sopenharmony_ci struct it87_sio_data sio_data; 33048c2ecf20Sopenharmony_ci unsigned short isa_address[2]; 33058c2ecf20Sopenharmony_ci bool found = false; 33068c2ecf20Sopenharmony_ci int i, err; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci err = platform_driver_register(&it87_driver); 33098c2ecf20Sopenharmony_ci if (err) 33108c2ecf20Sopenharmony_ci return err; 33118c2ecf20Sopenharmony_ci 33128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sioaddr); i++) { 33138c2ecf20Sopenharmony_ci memset(&sio_data, 0, sizeof(struct it87_sio_data)); 33148c2ecf20Sopenharmony_ci isa_address[i] = 0; 33158c2ecf20Sopenharmony_ci err = it87_find(sioaddr[i], &isa_address[i], &sio_data); 33168c2ecf20Sopenharmony_ci if (err || isa_address[i] == 0) 33178c2ecf20Sopenharmony_ci continue; 33188c2ecf20Sopenharmony_ci /* 33198c2ecf20Sopenharmony_ci * Don't register second chip if its ISA address matches 33208c2ecf20Sopenharmony_ci * the first chip's ISA address. 33218c2ecf20Sopenharmony_ci */ 33228c2ecf20Sopenharmony_ci if (i && isa_address[i] == isa_address[0]) 33238c2ecf20Sopenharmony_ci break; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci err = it87_device_add(i, isa_address[i], &sio_data); 33268c2ecf20Sopenharmony_ci if (err) 33278c2ecf20Sopenharmony_ci goto exit_dev_unregister; 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci found = true; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci /* 33328c2ecf20Sopenharmony_ci * IT8705F may respond on both SIO addresses. 33338c2ecf20Sopenharmony_ci * Stop probing after finding one. 33348c2ecf20Sopenharmony_ci */ 33358c2ecf20Sopenharmony_ci if (sio_data.type == it87) 33368c2ecf20Sopenharmony_ci break; 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci if (!found) { 33408c2ecf20Sopenharmony_ci err = -ENODEV; 33418c2ecf20Sopenharmony_ci goto exit_unregister; 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci return 0; 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ciexit_dev_unregister: 33468c2ecf20Sopenharmony_ci /* NULL check handled by platform_device_unregister */ 33478c2ecf20Sopenharmony_ci platform_device_unregister(it87_pdev[0]); 33488c2ecf20Sopenharmony_ciexit_unregister: 33498c2ecf20Sopenharmony_ci platform_driver_unregister(&it87_driver); 33508c2ecf20Sopenharmony_ci return err; 33518c2ecf20Sopenharmony_ci} 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_cistatic void __exit sm_it87_exit(void) 33548c2ecf20Sopenharmony_ci{ 33558c2ecf20Sopenharmony_ci /* NULL check handled by platform_device_unregister */ 33568c2ecf20Sopenharmony_ci platform_device_unregister(it87_pdev[1]); 33578c2ecf20Sopenharmony_ci platform_device_unregister(it87_pdev[0]); 33588c2ecf20Sopenharmony_ci platform_driver_unregister(&it87_driver); 33598c2ecf20Sopenharmony_ci} 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>"); 33628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); 33638c2ecf20Sopenharmony_cimodule_param(update_vbat, bool, 0); 33648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); 33658c2ecf20Sopenharmony_cimodule_param(fix_pwm_polarity, bool, 0); 33668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fix_pwm_polarity, 33678c2ecf20Sopenharmony_ci "Force PWM polarity to active high (DANGEROUS)"); 33688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_cimodule_init(sm_it87_init); 33718c2ecf20Sopenharmony_cimodule_exit(sm_it87_exit); 3372