18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * w83795.c - Linux kernel driver for hardware monitoring 48c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nuvoton Technology Corp. 58c2ecf20Sopenharmony_ci * Wei Song 68c2ecf20Sopenharmony_ci * Copyright (C) 2010 Jean Delvare <jdelvare@suse.de> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Supports following chips: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Chip #vin #fanin #pwm #temp #dts wchipid vendid i2c ISA 118c2ecf20Sopenharmony_ci * w83795g 21 14 8 6 8 0x79 0x5ca3 yes no 128c2ecf20Sopenharmony_ci * w83795adg 18 14 2 6 8 0x79 0x5ca3 yes no 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/i2c.h> 208c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 218c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 228c2ecf20Sopenharmony_ci#include <linux/err.h> 238c2ecf20Sopenharmony_ci#include <linux/mutex.h> 248c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 258c2ecf20Sopenharmony_ci#include <linux/util_macros.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Addresses to scan */ 288c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 298c2ecf20Sopenharmony_ci 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic bool reset; 348c2ecf20Sopenharmony_cimodule_param(reset, bool, 0); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define W83795_REG_BANKSEL 0x00 398c2ecf20Sopenharmony_ci#define W83795_REG_VENDORID 0xfd 408c2ecf20Sopenharmony_ci#define W83795_REG_CHIPID 0xfe 418c2ecf20Sopenharmony_ci#define W83795_REG_DEVICEID 0xfb 428c2ecf20Sopenharmony_ci#define W83795_REG_DEVICEID_A 0xff 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define W83795_REG_I2C_ADDR 0xfc 458c2ecf20Sopenharmony_ci#define W83795_REG_CONFIG 0x01 468c2ecf20Sopenharmony_ci#define W83795_REG_CONFIG_CONFIG48 0x04 478c2ecf20Sopenharmony_ci#define W83795_REG_CONFIG_START 0x01 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Multi-Function Pin Ctrl Registers */ 508c2ecf20Sopenharmony_ci#define W83795_REG_VOLT_CTRL1 0x02 518c2ecf20Sopenharmony_ci#define W83795_REG_VOLT_CTRL2 0x03 528c2ecf20Sopenharmony_ci#define W83795_REG_TEMP_CTRL1 0x04 538c2ecf20Sopenharmony_ci#define W83795_REG_TEMP_CTRL2 0x05 548c2ecf20Sopenharmony_ci#define W83795_REG_FANIN_CTRL1 0x06 558c2ecf20Sopenharmony_ci#define W83795_REG_FANIN_CTRL2 0x07 568c2ecf20Sopenharmony_ci#define W83795_REG_VMIGB_CTRL 0x08 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define TEMP_READ 0 598c2ecf20Sopenharmony_ci#define TEMP_CRIT 1 608c2ecf20Sopenharmony_ci#define TEMP_CRIT_HYST 2 618c2ecf20Sopenharmony_ci#define TEMP_WARN 3 628c2ecf20Sopenharmony_ci#define TEMP_WARN_HYST 4 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * only crit and crit_hyst affect real-time alarm status 658c2ecf20Sopenharmony_ci * current crit crit_hyst warn warn_hyst 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic const u16 W83795_REG_TEMP[][5] = { 688c2ecf20Sopenharmony_ci {0x21, 0x96, 0x97, 0x98, 0x99}, /* TD1/TR1 */ 698c2ecf20Sopenharmony_ci {0x22, 0x9a, 0x9b, 0x9c, 0x9d}, /* TD2/TR2 */ 708c2ecf20Sopenharmony_ci {0x23, 0x9e, 0x9f, 0xa0, 0xa1}, /* TD3/TR3 */ 718c2ecf20Sopenharmony_ci {0x24, 0xa2, 0xa3, 0xa4, 0xa5}, /* TD4/TR4 */ 728c2ecf20Sopenharmony_ci {0x1f, 0xa6, 0xa7, 0xa8, 0xa9}, /* TR5 */ 738c2ecf20Sopenharmony_ci {0x20, 0xaa, 0xab, 0xac, 0xad}, /* TR6 */ 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define IN_READ 0 778c2ecf20Sopenharmony_ci#define IN_MAX 1 788c2ecf20Sopenharmony_ci#define IN_LOW 2 798c2ecf20Sopenharmony_cistatic const u16 W83795_REG_IN[][3] = { 808c2ecf20Sopenharmony_ci /* Current, HL, LL */ 818c2ecf20Sopenharmony_ci {0x10, 0x70, 0x71}, /* VSEN1 */ 828c2ecf20Sopenharmony_ci {0x11, 0x72, 0x73}, /* VSEN2 */ 838c2ecf20Sopenharmony_ci {0x12, 0x74, 0x75}, /* VSEN3 */ 848c2ecf20Sopenharmony_ci {0x13, 0x76, 0x77}, /* VSEN4 */ 858c2ecf20Sopenharmony_ci {0x14, 0x78, 0x79}, /* VSEN5 */ 868c2ecf20Sopenharmony_ci {0x15, 0x7a, 0x7b}, /* VSEN6 */ 878c2ecf20Sopenharmony_ci {0x16, 0x7c, 0x7d}, /* VSEN7 */ 888c2ecf20Sopenharmony_ci {0x17, 0x7e, 0x7f}, /* VSEN8 */ 898c2ecf20Sopenharmony_ci {0x18, 0x80, 0x81}, /* VSEN9 */ 908c2ecf20Sopenharmony_ci {0x19, 0x82, 0x83}, /* VSEN10 */ 918c2ecf20Sopenharmony_ci {0x1A, 0x84, 0x85}, /* VSEN11 */ 928c2ecf20Sopenharmony_ci {0x1B, 0x86, 0x87}, /* VTT */ 938c2ecf20Sopenharmony_ci {0x1C, 0x88, 0x89}, /* 3VDD */ 948c2ecf20Sopenharmony_ci {0x1D, 0x8a, 0x8b}, /* 3VSB */ 958c2ecf20Sopenharmony_ci {0x1E, 0x8c, 0x8d}, /* VBAT */ 968c2ecf20Sopenharmony_ci {0x1F, 0xa6, 0xa7}, /* VSEN12 */ 978c2ecf20Sopenharmony_ci {0x20, 0xaa, 0xab}, /* VSEN13 */ 988c2ecf20Sopenharmony_ci {0x21, 0x96, 0x97}, /* VSEN14 */ 998c2ecf20Sopenharmony_ci {0x22, 0x9a, 0x9b}, /* VSEN15 */ 1008c2ecf20Sopenharmony_ci {0x23, 0x9e, 0x9f}, /* VSEN16 */ 1018c2ecf20Sopenharmony_ci {0x24, 0xa2, 0xa3}, /* VSEN17 */ 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci#define W83795_REG_VRLSB 0x3C 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const u8 W83795_REG_IN_HL_LSB[] = { 1068c2ecf20Sopenharmony_ci 0x8e, /* VSEN1-4 */ 1078c2ecf20Sopenharmony_ci 0x90, /* VSEN5-8 */ 1088c2ecf20Sopenharmony_ci 0x92, /* VSEN9-11 */ 1098c2ecf20Sopenharmony_ci 0x94, /* VTT, 3VDD, 3VSB, 3VBAT */ 1108c2ecf20Sopenharmony_ci 0xa8, /* VSEN12 */ 1118c2ecf20Sopenharmony_ci 0xac, /* VSEN13 */ 1128c2ecf20Sopenharmony_ci 0x98, /* VSEN14 */ 1138c2ecf20Sopenharmony_ci 0x9c, /* VSEN15 */ 1148c2ecf20Sopenharmony_ci 0xa0, /* VSEN16 */ 1158c2ecf20Sopenharmony_ci 0xa4, /* VSEN17 */ 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define IN_LSB_REG(index, type) \ 1198c2ecf20Sopenharmony_ci (((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \ 1208c2ecf20Sopenharmony_ci : (W83795_REG_IN_HL_LSB[(index)] + 1)) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define IN_LSB_SHIFT 0 1238c2ecf20Sopenharmony_ci#define IN_LSB_IDX 1 1248c2ecf20Sopenharmony_cistatic const u8 IN_LSB_SHIFT_IDX[][2] = { 1258c2ecf20Sopenharmony_ci /* High/Low LSB shift, LSB No. */ 1268c2ecf20Sopenharmony_ci {0x00, 0x00}, /* VSEN1 */ 1278c2ecf20Sopenharmony_ci {0x02, 0x00}, /* VSEN2 */ 1288c2ecf20Sopenharmony_ci {0x04, 0x00}, /* VSEN3 */ 1298c2ecf20Sopenharmony_ci {0x06, 0x00}, /* VSEN4 */ 1308c2ecf20Sopenharmony_ci {0x00, 0x01}, /* VSEN5 */ 1318c2ecf20Sopenharmony_ci {0x02, 0x01}, /* VSEN6 */ 1328c2ecf20Sopenharmony_ci {0x04, 0x01}, /* VSEN7 */ 1338c2ecf20Sopenharmony_ci {0x06, 0x01}, /* VSEN8 */ 1348c2ecf20Sopenharmony_ci {0x00, 0x02}, /* VSEN9 */ 1358c2ecf20Sopenharmony_ci {0x02, 0x02}, /* VSEN10 */ 1368c2ecf20Sopenharmony_ci {0x04, 0x02}, /* VSEN11 */ 1378c2ecf20Sopenharmony_ci {0x00, 0x03}, /* VTT */ 1388c2ecf20Sopenharmony_ci {0x02, 0x03}, /* 3VDD */ 1398c2ecf20Sopenharmony_ci {0x04, 0x03}, /* 3VSB */ 1408c2ecf20Sopenharmony_ci {0x06, 0x03}, /* VBAT */ 1418c2ecf20Sopenharmony_ci {0x06, 0x04}, /* VSEN12 */ 1428c2ecf20Sopenharmony_ci {0x06, 0x05}, /* VSEN13 */ 1438c2ecf20Sopenharmony_ci {0x06, 0x06}, /* VSEN14 */ 1448c2ecf20Sopenharmony_ci {0x06, 0x07}, /* VSEN15 */ 1458c2ecf20Sopenharmony_ci {0x06, 0x08}, /* VSEN16 */ 1468c2ecf20Sopenharmony_ci {0x06, 0x09}, /* VSEN17 */ 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define W83795_REG_FAN(index) (0x2E + (index)) 1518c2ecf20Sopenharmony_ci#define W83795_REG_FAN_MIN_HL(index) (0xB6 + (index)) 1528c2ecf20Sopenharmony_ci#define W83795_REG_FAN_MIN_LSB(index) (0xC4 + (index) / 2) 1538c2ecf20Sopenharmony_ci#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \ 1548c2ecf20Sopenharmony_ci (((index) & 1) ? 4 : 0) 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#define W83795_REG_VID_CTRL 0x6A 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define W83795_REG_ALARM_CTRL 0x40 1598c2ecf20Sopenharmony_ci#define ALARM_CTRL_RTSACS (1 << 7) 1608c2ecf20Sopenharmony_ci#define W83795_REG_ALARM(index) (0x41 + (index)) 1618c2ecf20Sopenharmony_ci#define W83795_REG_CLR_CHASSIS 0x4D 1628c2ecf20Sopenharmony_ci#define W83795_REG_BEEP(index) (0x50 + (index)) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define W83795_REG_OVT_CFG 0x58 1658c2ecf20Sopenharmony_ci#define OVT_CFG_SEL (1 << 7) 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define W83795_REG_FCMS1 0x201 1698c2ecf20Sopenharmony_ci#define W83795_REG_FCMS2 0x208 1708c2ecf20Sopenharmony_ci#define W83795_REG_TFMR(index) (0x202 + (index)) 1718c2ecf20Sopenharmony_ci#define W83795_REG_FOMC 0x20F 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define W83795_REG_TSS(index) (0x209 + (index)) 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define TSS_MAP_RESERVED 0xff 1768c2ecf20Sopenharmony_cistatic const u8 tss_map[4][6] = { 1778c2ecf20Sopenharmony_ci { 0, 1, 2, 3, 4, 5}, 1788c2ecf20Sopenharmony_ci { 6, 7, 8, 9, 0, 1}, 1798c2ecf20Sopenharmony_ci {10, 11, 12, 13, 2, 3}, 1808c2ecf20Sopenharmony_ci { 4, 5, 4, 5, TSS_MAP_RESERVED, TSS_MAP_RESERVED}, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define PWM_OUTPUT 0 1848c2ecf20Sopenharmony_ci#define PWM_FREQ 1 1858c2ecf20Sopenharmony_ci#define PWM_START 2 1868c2ecf20Sopenharmony_ci#define PWM_NONSTOP 3 1878c2ecf20Sopenharmony_ci#define PWM_STOP_TIME 4 1888c2ecf20Sopenharmony_ci#define W83795_REG_PWM(index, nr) (0x210 + (nr) * 8 + (index)) 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define W83795_REG_FTSH(index) (0x240 + (index) * 2) 1918c2ecf20Sopenharmony_ci#define W83795_REG_FTSL(index) (0x241 + (index) * 2) 1928c2ecf20Sopenharmony_ci#define W83795_REG_TFTS 0x250 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define TEMP_PWM_TTTI 0 1958c2ecf20Sopenharmony_ci#define TEMP_PWM_CTFS 1 1968c2ecf20Sopenharmony_ci#define TEMP_PWM_HCT 2 1978c2ecf20Sopenharmony_ci#define TEMP_PWM_HOT 3 1988c2ecf20Sopenharmony_ci#define W83795_REG_TTTI(index) (0x260 + (index)) 1998c2ecf20Sopenharmony_ci#define W83795_REG_CTFS(index) (0x268 + (index)) 2008c2ecf20Sopenharmony_ci#define W83795_REG_HT(index) (0x270 + (index)) 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci#define SF4_TEMP 0 2038c2ecf20Sopenharmony_ci#define SF4_PWM 1 2048c2ecf20Sopenharmony_ci#define W83795_REG_SF4_TEMP(temp_num, index) \ 2058c2ecf20Sopenharmony_ci (0x280 + 0x10 * (temp_num) + (index)) 2068c2ecf20Sopenharmony_ci#define W83795_REG_SF4_PWM(temp_num, index) \ 2078c2ecf20Sopenharmony_ci (0x288 + 0x10 * (temp_num) + (index)) 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci#define W83795_REG_DTSC 0x301 2108c2ecf20Sopenharmony_ci#define W83795_REG_DTSE 0x302 2118c2ecf20Sopenharmony_ci#define W83795_REG_DTS(index) (0x26 + (index)) 2128c2ecf20Sopenharmony_ci#define W83795_REG_PECI_TBASE(index) (0x320 + (index)) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci#define DTS_CRIT 0 2158c2ecf20Sopenharmony_ci#define DTS_CRIT_HYST 1 2168c2ecf20Sopenharmony_ci#define DTS_WARN 2 2178c2ecf20Sopenharmony_ci#define DTS_WARN_HYST 3 2188c2ecf20Sopenharmony_ci#define W83795_REG_DTS_EXT(index) (0xB2 + (index)) 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#define SETUP_PWM_DEFAULT 0 2218c2ecf20Sopenharmony_ci#define SETUP_PWM_UPTIME 1 2228c2ecf20Sopenharmony_ci#define SETUP_PWM_DOWNTIME 2 2238c2ecf20Sopenharmony_ci#define W83795_REG_SETUP_PWM(index) (0x20C + (index)) 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline u16 in_from_reg(u8 index, u16 val) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci /* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */ 2288c2ecf20Sopenharmony_ci if (index >= 12 && index <= 14) 2298c2ecf20Sopenharmony_ci return val * 6; 2308c2ecf20Sopenharmony_ci else 2318c2ecf20Sopenharmony_ci return val * 2; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic inline u16 in_to_reg(u8 index, u16 val) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci if (index >= 12 && index <= 14) 2378c2ecf20Sopenharmony_ci return val / 6; 2388c2ecf20Sopenharmony_ci else 2398c2ecf20Sopenharmony_ci return val / 2; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline unsigned long fan_from_reg(u16 val) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci if ((val == 0xfff) || (val == 0)) 2458c2ecf20Sopenharmony_ci return 0; 2468c2ecf20Sopenharmony_ci return 1350000UL / val; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline u16 fan_to_reg(long rpm) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci if (rpm <= 0) 2528c2ecf20Sopenharmony_ci return 0x0fff; 2538c2ecf20Sopenharmony_ci return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic inline unsigned long time_from_reg(u8 reg) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci return reg * 100; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic inline u8 time_to_reg(unsigned long val) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci return clamp_val((val + 50) / 100, 0, 0xff); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic inline long temp_from_reg(s8 reg) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci return reg * 1000; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic inline s8 temp_to_reg(long val, s8 min, s8 max) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci return clamp_val(val / 1000, min, max); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic const u16 pwm_freq_cksel0[16] = { 2778c2ecf20Sopenharmony_ci 1024, 512, 341, 256, 205, 171, 146, 128, 2788c2ecf20Sopenharmony_ci 85, 64, 32, 16, 8, 4, 2, 1 2798c2ecf20Sopenharmony_ci}; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic unsigned int pwm_freq_from_reg(u8 reg, u16 clkin) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci unsigned long base_clock; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (reg & 0x80) { 2868c2ecf20Sopenharmony_ci base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 2878c2ecf20Sopenharmony_ci return base_clock / ((reg & 0x7f) + 1); 2888c2ecf20Sopenharmony_ci } else 2898c2ecf20Sopenharmony_ci return pwm_freq_cksel0[reg & 0x0f]; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic u8 pwm_freq_to_reg(unsigned long val, u16 clkin) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned long base_clock; 2958c2ecf20Sopenharmony_ci u8 reg0, reg1; 2968c2ecf20Sopenharmony_ci unsigned long best0, best1; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* Best fit for cksel = 0 */ 2998c2ecf20Sopenharmony_ci reg0 = find_closest_descending(val, pwm_freq_cksel0, 3008c2ecf20Sopenharmony_ci ARRAY_SIZE(pwm_freq_cksel0)); 3018c2ecf20Sopenharmony_ci if (val < 375) /* cksel = 1 can't beat this */ 3028c2ecf20Sopenharmony_ci return reg0; 3038c2ecf20Sopenharmony_ci best0 = pwm_freq_cksel0[reg0]; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Best fit for cksel = 1 */ 3068c2ecf20Sopenharmony_ci base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256); 3078c2ecf20Sopenharmony_ci reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128); 3088c2ecf20Sopenharmony_ci best1 = base_clock / reg1; 3098c2ecf20Sopenharmony_ci reg1 = 0x80 | (reg1 - 1); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Choose the closest one */ 3128c2ecf20Sopenharmony_ci if (abs(val - best0) > abs(val - best1)) 3138c2ecf20Sopenharmony_ci return reg1; 3148c2ecf20Sopenharmony_ci else 3158c2ecf20Sopenharmony_ci return reg0; 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cienum chip_types {w83795g, w83795adg}; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistruct w83795_data { 3218c2ecf20Sopenharmony_ci struct device *hwmon_dev; 3228c2ecf20Sopenharmony_ci struct mutex update_lock; 3238c2ecf20Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 3248c2ecf20Sopenharmony_ci enum chip_types chip_type; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci u8 bank; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci u32 has_in; /* Enable monitor VIN or not */ 3298c2ecf20Sopenharmony_ci u8 has_dyn_in; /* Only in2-0 can have this */ 3308c2ecf20Sopenharmony_ci u16 in[21][3]; /* Register value, read/high/low */ 3318c2ecf20Sopenharmony_ci u8 in_lsb[10][3]; /* LSB Register value, high/low */ 3328c2ecf20Sopenharmony_ci u8 has_gain; /* has gain: in17-20 * 8 */ 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci u16 has_fan; /* Enable fan14-1 or not */ 3358c2ecf20Sopenharmony_ci u16 fan[14]; /* Register value combine */ 3368c2ecf20Sopenharmony_ci u16 fan_min[14]; /* Register value combine */ 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci u8 has_temp; /* Enable monitor temp6-1 or not */ 3398c2ecf20Sopenharmony_ci s8 temp[6][5]; /* current, crit, crit_hyst, warn, warn_hyst */ 3408c2ecf20Sopenharmony_ci u8 temp_read_vrlsb[6]; 3418c2ecf20Sopenharmony_ci u8 temp_mode; /* Bit vector, 0 = TR, 1 = TD */ 3428c2ecf20Sopenharmony_ci u8 temp_src[3]; /* Register value */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci u8 enable_dts; /* 3458c2ecf20Sopenharmony_ci * Enable PECI and SB-TSI, 3468c2ecf20Sopenharmony_ci * bit 0: =1 enable, =0 disable, 3478c2ecf20Sopenharmony_ci * bit 1: =1 AMD SB-TSI, =0 Intel PECI 3488c2ecf20Sopenharmony_ci */ 3498c2ecf20Sopenharmony_ci u8 has_dts; /* Enable monitor DTS temp */ 3508c2ecf20Sopenharmony_ci s8 dts[8]; /* Register value */ 3518c2ecf20Sopenharmony_ci u8 dts_read_vrlsb[8]; /* Register value */ 3528c2ecf20Sopenharmony_ci s8 dts_ext[4]; /* Register value */ 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci u8 has_pwm; /* 3558c2ecf20Sopenharmony_ci * 795g supports 8 pwm, 795adg only supports 2, 3568c2ecf20Sopenharmony_ci * no config register, only affected by chip 3578c2ecf20Sopenharmony_ci * type 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci u8 pwm[8][5]; /* 3608c2ecf20Sopenharmony_ci * Register value, output, freq, start, 3618c2ecf20Sopenharmony_ci * non stop, stop time 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci u16 clkin; /* CLKIN frequency in kHz */ 3648c2ecf20Sopenharmony_ci u8 pwm_fcms[2]; /* Register value */ 3658c2ecf20Sopenharmony_ci u8 pwm_tfmr[6]; /* Register value */ 3668c2ecf20Sopenharmony_ci u8 pwm_fomc; /* Register value */ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci u16 target_speed[8]; /* 3698c2ecf20Sopenharmony_ci * Register value, target speed for speed 3708c2ecf20Sopenharmony_ci * cruise 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci u8 tol_speed; /* tolerance of target speed */ 3738c2ecf20Sopenharmony_ci u8 pwm_temp[6][4]; /* TTTI, CTFS, HCT, HOT */ 3748c2ecf20Sopenharmony_ci u8 sf4_reg[6][2][7]; /* 6 temp, temp/dcpwm, 7 registers */ 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci u8 setup_pwm[3]; /* Register value */ 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci u8 alarms[6]; /* Register value */ 3798c2ecf20Sopenharmony_ci u8 enable_beep; 3808c2ecf20Sopenharmony_ci u8 beeps[6]; /* Register value */ 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci char valid; 3838c2ecf20Sopenharmony_ci char valid_limits; 3848c2ecf20Sopenharmony_ci char valid_pwm_config; 3858c2ecf20Sopenharmony_ci}; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/* 3888c2ecf20Sopenharmony_ci * Hardware access 3898c2ecf20Sopenharmony_ci * We assume that nobdody can change the bank outside the driver. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */ 3938c2ecf20Sopenharmony_cistatic int w83795_set_bank(struct i2c_client *client, u8 bank) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 3968c2ecf20Sopenharmony_ci int err; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* If the same bank is already set, nothing to do */ 3998c2ecf20Sopenharmony_ci if ((data->bank & 0x07) == bank) 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Change to new bank, preserve all other bits */ 4038c2ecf20Sopenharmony_ci bank |= data->bank & ~0x07; 4048c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank); 4058c2ecf20Sopenharmony_ci if (err < 0) { 4068c2ecf20Sopenharmony_ci dev_err(&client->dev, 4078c2ecf20Sopenharmony_ci "Failed to set bank to %d, err %d\n", 4088c2ecf20Sopenharmony_ci (int)bank, err); 4098c2ecf20Sopenharmony_ci return err; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci data->bank = bank; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */ 4178c2ecf20Sopenharmony_cistatic u8 w83795_read(struct i2c_client *client, u16 reg) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int err; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci err = w83795_set_bank(client, reg >> 8); 4228c2ecf20Sopenharmony_ci if (err < 0) 4238c2ecf20Sopenharmony_ci return 0x00; /* Arbitrary */ 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci err = i2c_smbus_read_byte_data(client, reg & 0xff); 4268c2ecf20Sopenharmony_ci if (err < 0) { 4278c2ecf20Sopenharmony_ci dev_err(&client->dev, 4288c2ecf20Sopenharmony_ci "Failed to read from register 0x%03x, err %d\n", 4298c2ecf20Sopenharmony_ci (int)reg, err); 4308c2ecf20Sopenharmony_ci return 0x00; /* Arbitrary */ 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci return err; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */ 4368c2ecf20Sopenharmony_cistatic int w83795_write(struct i2c_client *client, u16 reg, u8 value) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci int err; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci err = w83795_set_bank(client, reg >> 8); 4418c2ecf20Sopenharmony_ci if (err < 0) 4428c2ecf20Sopenharmony_ci return err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci err = i2c_smbus_write_byte_data(client, reg & 0xff, value); 4458c2ecf20Sopenharmony_ci if (err < 0) 4468c2ecf20Sopenharmony_ci dev_err(&client->dev, 4478c2ecf20Sopenharmony_ci "Failed to write to register 0x%03x, err %d\n", 4488c2ecf20Sopenharmony_ci (int)reg, err); 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void w83795_update_limits(struct i2c_client *client) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 4558c2ecf20Sopenharmony_ci int i, limit; 4568c2ecf20Sopenharmony_ci u8 lsb; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Read the voltage limits */ 4598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->in); i++) { 4608c2ecf20Sopenharmony_ci if (!(data->has_in & (1 << i))) 4618c2ecf20Sopenharmony_ci continue; 4628c2ecf20Sopenharmony_ci data->in[i][IN_MAX] = 4638c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_IN[i][IN_MAX]); 4648c2ecf20Sopenharmony_ci data->in[i][IN_LOW] = 4658c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_IN[i][IN_LOW]); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) { 4688c2ecf20Sopenharmony_ci if ((i == 2 && data->chip_type == w83795adg) || 4698c2ecf20Sopenharmony_ci (i >= 4 && !(data->has_in & (1 << (i + 11))))) 4708c2ecf20Sopenharmony_ci continue; 4718c2ecf20Sopenharmony_ci data->in_lsb[i][IN_MAX] = 4728c2ecf20Sopenharmony_ci w83795_read(client, IN_LSB_REG(i, IN_MAX)); 4738c2ecf20Sopenharmony_ci data->in_lsb[i][IN_LOW] = 4748c2ecf20Sopenharmony_ci w83795_read(client, IN_LSB_REG(i, IN_LOW)); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Read the fan limits */ 4788c2ecf20Sopenharmony_ci lsb = 0; /* Silent false gcc warning */ 4798c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 4808c2ecf20Sopenharmony_ci /* 4818c2ecf20Sopenharmony_ci * Each register contains LSB for 2 fans, but we want to 4828c2ecf20Sopenharmony_ci * read it only once to save time 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci if ((i & 1) == 0 && (data->has_fan & (3 << i))) 4858c2ecf20Sopenharmony_ci lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i)); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (!(data->has_fan & (1 << i))) 4888c2ecf20Sopenharmony_ci continue; 4898c2ecf20Sopenharmony_ci data->fan_min[i] = 4908c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4; 4918c2ecf20Sopenharmony_ci data->fan_min[i] |= 4928c2ecf20Sopenharmony_ci (lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Read the temperature limits */ 4968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 4978c2ecf20Sopenharmony_ci if (!(data->has_temp & (1 << i))) 4988c2ecf20Sopenharmony_ci continue; 4998c2ecf20Sopenharmony_ci for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++) 5008c2ecf20Sopenharmony_ci data->temp[i][limit] = 5018c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_TEMP[i][limit]); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Read the DTS limits */ 5058c2ecf20Sopenharmony_ci if (data->enable_dts) { 5068c2ecf20Sopenharmony_ci for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++) 5078c2ecf20Sopenharmony_ci data->dts_ext[limit] = 5088c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_DTS_EXT(limit)); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Read beep settings */ 5128c2ecf20Sopenharmony_ci if (data->enable_beep) { 5138c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->beeps); i++) 5148c2ecf20Sopenharmony_ci data->beeps[i] = 5158c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_BEEP(i)); 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci data->valid_limits = 1; 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic struct w83795_data *w83795_update_pwm_config(struct device *dev) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5248c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 5258c2ecf20Sopenharmony_ci int i, tmp; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (data->valid_pwm_config) 5308c2ecf20Sopenharmony_ci goto END; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Read temperature source selection */ 5338c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->temp_src); i++) 5348c2ecf20Sopenharmony_ci data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i)); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci /* Read automatic fan speed control settings */ 5378c2ecf20Sopenharmony_ci data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1); 5388c2ecf20Sopenharmony_ci data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2); 5398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++) 5408c2ecf20Sopenharmony_ci data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i)); 5418c2ecf20Sopenharmony_ci data->pwm_fomc = w83795_read(client, W83795_REG_FOMC); 5428c2ecf20Sopenharmony_ci for (i = 0; i < data->has_pwm; i++) { 5438c2ecf20Sopenharmony_ci for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++) 5448c2ecf20Sopenharmony_ci data->pwm[i][tmp] = 5458c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_PWM(i, tmp)); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) { 5488c2ecf20Sopenharmony_ci data->target_speed[i] = 5498c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_FTSH(i)) << 4; 5508c2ecf20Sopenharmony_ci data->target_speed[i] |= 5518c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_FTSL(i)) >> 4; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) { 5568c2ecf20Sopenharmony_ci data->pwm_temp[i][TEMP_PWM_TTTI] = 5578c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_TTTI(i)) & 0x7f; 5588c2ecf20Sopenharmony_ci data->pwm_temp[i][TEMP_PWM_CTFS] = 5598c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_CTFS(i)); 5608c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_HT(i)); 5618c2ecf20Sopenharmony_ci data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4; 5628c2ecf20Sopenharmony_ci data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* Read SmartFanIV trip points */ 5668c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) { 5678c2ecf20Sopenharmony_ci for (tmp = 0; tmp < 7; tmp++) { 5688c2ecf20Sopenharmony_ci data->sf4_reg[i][SF4_TEMP][tmp] = 5698c2ecf20Sopenharmony_ci w83795_read(client, 5708c2ecf20Sopenharmony_ci W83795_REG_SF4_TEMP(i, tmp)); 5718c2ecf20Sopenharmony_ci data->sf4_reg[i][SF4_PWM][tmp] = 5728c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_SF4_PWM(i, tmp)); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* Read setup PWM */ 5778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++) 5788c2ecf20Sopenharmony_ci data->setup_pwm[i] = 5798c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_SETUP_PWM(i)); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci data->valid_pwm_config = 1; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ciEND: 5848c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 5858c2ecf20Sopenharmony_ci return data; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic struct w83795_data *w83795_update_device(struct device *dev) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 5918c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 5928c2ecf20Sopenharmony_ci u16 tmp; 5938c2ecf20Sopenharmony_ci u8 intrusion; 5948c2ecf20Sopenharmony_ci int i; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (!data->valid_limits) 5998c2ecf20Sopenharmony_ci w83795_update_limits(client); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (!(time_after(jiffies, data->last_updated + HZ * 2) 6028c2ecf20Sopenharmony_ci || !data->valid)) 6038c2ecf20Sopenharmony_ci goto END; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* Update the voltages value */ 6068c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->in); i++) { 6078c2ecf20Sopenharmony_ci if (!(data->has_in & (1 << i))) 6088c2ecf20Sopenharmony_ci continue; 6098c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2; 6108c2ecf20Sopenharmony_ci tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6; 6118c2ecf20Sopenharmony_ci data->in[i][IN_READ] = tmp; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci /* in0-2 can have dynamic limits (W83795G only) */ 6158c2ecf20Sopenharmony_ci if (data->has_dyn_in) { 6168c2ecf20Sopenharmony_ci u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX)); 6178c2ecf20Sopenharmony_ci u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW)); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 6208c2ecf20Sopenharmony_ci if (!(data->has_dyn_in & (1 << i))) 6218c2ecf20Sopenharmony_ci continue; 6228c2ecf20Sopenharmony_ci data->in[i][IN_MAX] = 6238c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_IN[i][IN_MAX]); 6248c2ecf20Sopenharmony_ci data->in[i][IN_LOW] = 6258c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_IN[i][IN_LOW]); 6268c2ecf20Sopenharmony_ci data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03; 6278c2ecf20Sopenharmony_ci data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* Update fan */ 6328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->fan); i++) { 6338c2ecf20Sopenharmony_ci if (!(data->has_fan & (1 << i))) 6348c2ecf20Sopenharmony_ci continue; 6358c2ecf20Sopenharmony_ci data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4; 6368c2ecf20Sopenharmony_ci data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* Update temperature */ 6408c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->temp); i++) { 6418c2ecf20Sopenharmony_ci data->temp[i][TEMP_READ] = 6428c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]); 6438c2ecf20Sopenharmony_ci data->temp_read_vrlsb[i] = 6448c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_VRLSB); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* Update dts temperature */ 6488c2ecf20Sopenharmony_ci if (data->enable_dts) { 6498c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->dts); i++) { 6508c2ecf20Sopenharmony_ci if (!(data->has_dts & (1 << i))) 6518c2ecf20Sopenharmony_ci continue; 6528c2ecf20Sopenharmony_ci data->dts[i] = 6538c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_DTS(i)); 6548c2ecf20Sopenharmony_ci data->dts_read_vrlsb[i] = 6558c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_VRLSB); 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Update pwm output */ 6608c2ecf20Sopenharmony_ci for (i = 0; i < data->has_pwm; i++) { 6618c2ecf20Sopenharmony_ci data->pwm[i][PWM_OUTPUT] = 6628c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT)); 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* 6668c2ecf20Sopenharmony_ci * Update intrusion and alarms 6678c2ecf20Sopenharmony_ci * It is important to read intrusion first, because reading from 6688c2ecf20Sopenharmony_ci * register SMI STS6 clears the interrupt status temporarily. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_ALARM_CTRL); 6718c2ecf20Sopenharmony_ci /* Switch to interrupt status for intrusion if needed */ 6728c2ecf20Sopenharmony_ci if (tmp & ALARM_CTRL_RTSACS) 6738c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_ALARM_CTRL, 6748c2ecf20Sopenharmony_ci tmp & ~ALARM_CTRL_RTSACS); 6758c2ecf20Sopenharmony_ci intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6); 6768c2ecf20Sopenharmony_ci /* Switch to real-time alarms */ 6778c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS); 6788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(data->alarms); i++) 6798c2ecf20Sopenharmony_ci data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i)); 6808c2ecf20Sopenharmony_ci data->alarms[5] |= intrusion; 6818c2ecf20Sopenharmony_ci /* Restore original configuration if needed */ 6828c2ecf20Sopenharmony_ci if (!(tmp & ALARM_CTRL_RTSACS)) 6838c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_ALARM_CTRL, 6848c2ecf20Sopenharmony_ci tmp & ~ALARM_CTRL_RTSACS); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci data->last_updated = jiffies; 6878c2ecf20Sopenharmony_ci data->valid = 1; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ciEND: 6908c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 6918c2ecf20Sopenharmony_ci return data; 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci/* 6958c2ecf20Sopenharmony_ci * Sysfs attributes 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci#define ALARM_STATUS 0 6998c2ecf20Sopenharmony_ci#define BEEP_ENABLE 1 7008c2ecf20Sopenharmony_cistatic ssize_t 7018c2ecf20Sopenharmony_cishow_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_device(dev); 7048c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 7058c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 7068c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 7078c2ecf20Sopenharmony_ci int index = sensor_attr->index >> 3; 7088c2ecf20Sopenharmony_ci int bit = sensor_attr->index & 0x07; 7098c2ecf20Sopenharmony_ci u8 val; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (nr == ALARM_STATUS) 7128c2ecf20Sopenharmony_ci val = (data->alarms[index] >> bit) & 1; 7138c2ecf20Sopenharmony_ci else /* BEEP_ENABLE */ 7148c2ecf20Sopenharmony_ci val = (data->beeps[index] >> bit) & 1; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", val); 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic ssize_t 7208c2ecf20Sopenharmony_cistore_beep(struct device *dev, struct device_attribute *attr, 7218c2ecf20Sopenharmony_ci const char *buf, size_t count) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 7248c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 7258c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 7268c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 7278c2ecf20Sopenharmony_ci int index = sensor_attr->index >> 3; 7288c2ecf20Sopenharmony_ci int shift = sensor_attr->index & 0x07; 7298c2ecf20Sopenharmony_ci u8 beep_bit = 1 << shift; 7308c2ecf20Sopenharmony_ci unsigned long val; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 7338c2ecf20Sopenharmony_ci return -EINVAL; 7348c2ecf20Sopenharmony_ci if (val != 0 && val != 1) 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 7388c2ecf20Sopenharmony_ci data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index)); 7398c2ecf20Sopenharmony_ci data->beeps[index] &= ~beep_bit; 7408c2ecf20Sopenharmony_ci data->beeps[index] |= val << shift; 7418c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]); 7428c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci return count; 7458c2ecf20Sopenharmony_ci} 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci/* Write 0 to clear chassis alarm */ 7488c2ecf20Sopenharmony_cistatic ssize_t 7498c2ecf20Sopenharmony_cistore_chassis_clear(struct device *dev, 7508c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 7518c2ecf20Sopenharmony_ci size_t count) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 7548c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 7558c2ecf20Sopenharmony_ci unsigned long val; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0 || val != 0) 7588c2ecf20Sopenharmony_ci return -EINVAL; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 7618c2ecf20Sopenharmony_ci val = w83795_read(client, W83795_REG_CLR_CHASSIS); 7628c2ecf20Sopenharmony_ci val |= 0x80; 7638c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_CLR_CHASSIS, val); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Clear status and force cache refresh */ 7668c2ecf20Sopenharmony_ci w83795_read(client, W83795_REG_ALARM(5)); 7678c2ecf20Sopenharmony_ci data->valid = 0; 7688c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 7698c2ecf20Sopenharmony_ci return count; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci#define FAN_INPUT 0 7738c2ecf20Sopenharmony_ci#define FAN_MIN 1 7748c2ecf20Sopenharmony_cistatic ssize_t 7758c2ecf20Sopenharmony_cishow_fan(struct device *dev, struct device_attribute *attr, char *buf) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 7788c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 7798c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 7808c2ecf20Sopenharmony_ci int index = sensor_attr->index; 7818c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_device(dev); 7828c2ecf20Sopenharmony_ci u16 val; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (nr == FAN_INPUT) 7858c2ecf20Sopenharmony_ci val = data->fan[index] & 0x0fff; 7868c2ecf20Sopenharmony_ci else 7878c2ecf20Sopenharmony_ci val = data->fan_min[index] & 0x0fff; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return sprintf(buf, "%lu\n", fan_from_reg(val)); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic ssize_t 7938c2ecf20Sopenharmony_cistore_fan_min(struct device *dev, struct device_attribute *attr, 7948c2ecf20Sopenharmony_ci const char *buf, size_t count) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 7978c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 7988c2ecf20Sopenharmony_ci int index = sensor_attr->index; 7998c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8008c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 8018c2ecf20Sopenharmony_ci unsigned long val; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val)) 8048c2ecf20Sopenharmony_ci return -EINVAL; 8058c2ecf20Sopenharmony_ci val = fan_to_reg(val); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 8088c2ecf20Sopenharmony_ci data->fan_min[index] = val; 8098c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff); 8108c2ecf20Sopenharmony_ci val &= 0x0f; 8118c2ecf20Sopenharmony_ci if (index & 1) { 8128c2ecf20Sopenharmony_ci val <<= 4; 8138c2ecf20Sopenharmony_ci val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 8148c2ecf20Sopenharmony_ci & 0x0f; 8158c2ecf20Sopenharmony_ci } else { 8168c2ecf20Sopenharmony_ci val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index)) 8178c2ecf20Sopenharmony_ci & 0xf0; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff); 8208c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci return count; 8238c2ecf20Sopenharmony_ci} 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_cistatic ssize_t 8268c2ecf20Sopenharmony_cishow_pwm(struct device *dev, struct device_attribute *attr, char *buf) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct w83795_data *data; 8298c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 8308c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 8318c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 8328c2ecf20Sopenharmony_ci int index = sensor_attr->index; 8338c2ecf20Sopenharmony_ci unsigned int val; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci data = nr == PWM_OUTPUT ? w83795_update_device(dev) 8368c2ecf20Sopenharmony_ci : w83795_update_pwm_config(dev); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci switch (nr) { 8398c2ecf20Sopenharmony_ci case PWM_STOP_TIME: 8408c2ecf20Sopenharmony_ci val = time_from_reg(data->pwm[index][nr]); 8418c2ecf20Sopenharmony_ci break; 8428c2ecf20Sopenharmony_ci case PWM_FREQ: 8438c2ecf20Sopenharmony_ci val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin); 8448c2ecf20Sopenharmony_ci break; 8458c2ecf20Sopenharmony_ci default: 8468c2ecf20Sopenharmony_ci val = data->pwm[index][nr]; 8478c2ecf20Sopenharmony_ci break; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", val); 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic ssize_t 8548c2ecf20Sopenharmony_cistore_pwm(struct device *dev, struct device_attribute *attr, 8558c2ecf20Sopenharmony_ci const char *buf, size_t count) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8588c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 8598c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 8608c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 8618c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 8628c2ecf20Sopenharmony_ci int index = sensor_attr->index; 8638c2ecf20Sopenharmony_ci unsigned long val; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 8668c2ecf20Sopenharmony_ci return -EINVAL; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 8698c2ecf20Sopenharmony_ci switch (nr) { 8708c2ecf20Sopenharmony_ci case PWM_STOP_TIME: 8718c2ecf20Sopenharmony_ci val = time_to_reg(val); 8728c2ecf20Sopenharmony_ci break; 8738c2ecf20Sopenharmony_ci case PWM_FREQ: 8748c2ecf20Sopenharmony_ci val = pwm_freq_to_reg(val, data->clkin); 8758c2ecf20Sopenharmony_ci break; 8768c2ecf20Sopenharmony_ci default: 8778c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0xff); 8788c2ecf20Sopenharmony_ci break; 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_PWM(index, nr), val); 8818c2ecf20Sopenharmony_ci data->pwm[index][nr] = val; 8828c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8838c2ecf20Sopenharmony_ci return count; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic ssize_t 8878c2ecf20Sopenharmony_cishow_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 8908c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 8918c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 8928c2ecf20Sopenharmony_ci int index = sensor_attr->index; 8938c2ecf20Sopenharmony_ci u8 tmp; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* Speed cruise mode */ 8968c2ecf20Sopenharmony_ci if (data->pwm_fcms[0] & (1 << index)) { 8978c2ecf20Sopenharmony_ci tmp = 2; 8988c2ecf20Sopenharmony_ci goto out; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci /* Thermal cruise or SmartFan IV mode */ 9018c2ecf20Sopenharmony_ci for (tmp = 0; tmp < 6; tmp++) { 9028c2ecf20Sopenharmony_ci if (data->pwm_tfmr[tmp] & (1 << index)) { 9038c2ecf20Sopenharmony_ci tmp = 3; 9048c2ecf20Sopenharmony_ci goto out; 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci } 9078c2ecf20Sopenharmony_ci /* Manual mode */ 9088c2ecf20Sopenharmony_ci tmp = 1; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciout: 9118c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", tmp); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic ssize_t 9158c2ecf20Sopenharmony_cistore_pwm_enable(struct device *dev, struct device_attribute *attr, 9168c2ecf20Sopenharmony_ci const char *buf, size_t count) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 9198c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 9208c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 9218c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 9228c2ecf20Sopenharmony_ci int index = sensor_attr->index; 9238c2ecf20Sopenharmony_ci unsigned long val; 9248c2ecf20Sopenharmony_ci int i; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 9278c2ecf20Sopenharmony_ci return -EINVAL; 9288c2ecf20Sopenharmony_ci if (val < 1 || val > 2) 9298c2ecf20Sopenharmony_ci return -EINVAL; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci#ifndef CONFIG_SENSORS_W83795_FANCTRL 9328c2ecf20Sopenharmony_ci if (val > 1) { 9338c2ecf20Sopenharmony_ci dev_warn(dev, "Automatic fan speed control support disabled\n"); 9348c2ecf20Sopenharmony_ci dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n"); 9358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci#endif 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 9408c2ecf20Sopenharmony_ci switch (val) { 9418c2ecf20Sopenharmony_ci case 1: 9428c2ecf20Sopenharmony_ci /* Clear speed cruise mode bits */ 9438c2ecf20Sopenharmony_ci data->pwm_fcms[0] &= ~(1 << index); 9448c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 9458c2ecf20Sopenharmony_ci /* Clear thermal cruise mode bits */ 9468c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 9478c2ecf20Sopenharmony_ci data->pwm_tfmr[i] &= ~(1 << index); 9488c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TFMR(i), 9498c2ecf20Sopenharmony_ci data->pwm_tfmr[i]); 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci break; 9528c2ecf20Sopenharmony_ci case 2: 9538c2ecf20Sopenharmony_ci data->pwm_fcms[0] |= (1 << index); 9548c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]); 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 9588c2ecf20Sopenharmony_ci return count; 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cistatic ssize_t 9628c2ecf20Sopenharmony_cishow_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 9658c2ecf20Sopenharmony_ci int index = to_sensor_dev_attr_2(attr)->index; 9668c2ecf20Sopenharmony_ci unsigned int mode; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (data->pwm_fomc & (1 << index)) 9698c2ecf20Sopenharmony_ci mode = 0; /* DC */ 9708c2ecf20Sopenharmony_ci else 9718c2ecf20Sopenharmony_ci mode = 1; /* PWM */ 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", mode); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci/* 9778c2ecf20Sopenharmony_ci * Check whether a given temperature source can ever be useful. 9788c2ecf20Sopenharmony_ci * Returns the number of selectable temperature channels which are 9798c2ecf20Sopenharmony_ci * enabled. 9808c2ecf20Sopenharmony_ci */ 9818c2ecf20Sopenharmony_cistatic int w83795_tss_useful(const struct w83795_data *data, int tsrc) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci int useful = 0, i; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 9868c2ecf20Sopenharmony_ci if (tss_map[i][tsrc] == TSS_MAP_RESERVED) 9878c2ecf20Sopenharmony_ci continue; 9888c2ecf20Sopenharmony_ci if (tss_map[i][tsrc] < 6) /* Analog */ 9898c2ecf20Sopenharmony_ci useful += (data->has_temp >> tss_map[i][tsrc]) & 1; 9908c2ecf20Sopenharmony_ci else /* Digital */ 9918c2ecf20Sopenharmony_ci useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return useful; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic ssize_t 9988c2ecf20Sopenharmony_cishow_temp_src(struct device *dev, struct device_attribute *attr, char *buf) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 10018c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 10028c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 10038c2ecf20Sopenharmony_ci int index = sensor_attr->index; 10048c2ecf20Sopenharmony_ci u8 tmp = data->temp_src[index / 2]; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (index & 1) 10078c2ecf20Sopenharmony_ci tmp >>= 4; /* Pick high nibble */ 10088c2ecf20Sopenharmony_ci else 10098c2ecf20Sopenharmony_ci tmp &= 0x0f; /* Pick low nibble */ 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* Look-up the actual temperature channel number */ 10128c2ecf20Sopenharmony_ci if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED) 10138c2ecf20Sopenharmony_ci return -EINVAL; /* Shouldn't happen */ 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic ssize_t 10198c2ecf20Sopenharmony_cistore_temp_src(struct device *dev, struct device_attribute *attr, 10208c2ecf20Sopenharmony_ci const char *buf, size_t count) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 10238c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 10248c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 10258c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 10268c2ecf20Sopenharmony_ci int index = sensor_attr->index; 10278c2ecf20Sopenharmony_ci int tmp; 10288c2ecf20Sopenharmony_ci unsigned long channel; 10298c2ecf20Sopenharmony_ci u8 val = index / 2; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &channel) < 0 || 10328c2ecf20Sopenharmony_ci channel < 1 || channel > 14) 10338c2ecf20Sopenharmony_ci return -EINVAL; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci /* Check if request can be fulfilled */ 10368c2ecf20Sopenharmony_ci for (tmp = 0; tmp < 4; tmp++) { 10378c2ecf20Sopenharmony_ci if (tss_map[tmp][index] == channel - 1) 10388c2ecf20Sopenharmony_ci break; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci if (tmp == 4) /* No match */ 10418c2ecf20Sopenharmony_ci return -EINVAL; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 10448c2ecf20Sopenharmony_ci if (index & 1) { 10458c2ecf20Sopenharmony_ci tmp <<= 4; 10468c2ecf20Sopenharmony_ci data->temp_src[val] &= 0x0f; 10478c2ecf20Sopenharmony_ci } else { 10488c2ecf20Sopenharmony_ci data->temp_src[val] &= 0xf0; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci data->temp_src[val] |= tmp; 10518c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]); 10528c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return count; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci#define TEMP_PWM_ENABLE 0 10588c2ecf20Sopenharmony_ci#define TEMP_PWM_FAN_MAP 1 10598c2ecf20Sopenharmony_cistatic ssize_t 10608c2ecf20Sopenharmony_cishow_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 10618c2ecf20Sopenharmony_ci char *buf) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 10648c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 10658c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 10668c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 10678c2ecf20Sopenharmony_ci int index = sensor_attr->index; 10688c2ecf20Sopenharmony_ci u8 tmp = 0xff; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci switch (nr) { 10718c2ecf20Sopenharmony_ci case TEMP_PWM_ENABLE: 10728c2ecf20Sopenharmony_ci tmp = (data->pwm_fcms[1] >> index) & 1; 10738c2ecf20Sopenharmony_ci if (tmp) 10748c2ecf20Sopenharmony_ci tmp = 4; 10758c2ecf20Sopenharmony_ci else 10768c2ecf20Sopenharmony_ci tmp = 3; 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci case TEMP_PWM_FAN_MAP: 10798c2ecf20Sopenharmony_ci tmp = data->pwm_tfmr[index]; 10808c2ecf20Sopenharmony_ci break; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", tmp); 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_cistatic ssize_t 10878c2ecf20Sopenharmony_cistore_temp_pwm_enable(struct device *dev, struct device_attribute *attr, 10888c2ecf20Sopenharmony_ci const char *buf, size_t count) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 10918c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 10928c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 10938c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 10948c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 10958c2ecf20Sopenharmony_ci int index = sensor_attr->index; 10968c2ecf20Sopenharmony_ci unsigned long tmp; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &tmp) < 0) 10998c2ecf20Sopenharmony_ci return -EINVAL; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci switch (nr) { 11028c2ecf20Sopenharmony_ci case TEMP_PWM_ENABLE: 11038c2ecf20Sopenharmony_ci if (tmp != 3 && tmp != 4) 11048c2ecf20Sopenharmony_ci return -EINVAL; 11058c2ecf20Sopenharmony_ci tmp -= 3; 11068c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11078c2ecf20Sopenharmony_ci data->pwm_fcms[1] &= ~(1 << index); 11088c2ecf20Sopenharmony_ci data->pwm_fcms[1] |= tmp << index; 11098c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]); 11108c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci case TEMP_PWM_FAN_MAP: 11138c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11148c2ecf20Sopenharmony_ci tmp = clamp_val(tmp, 0, 0xff); 11158c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TFMR(index), tmp); 11168c2ecf20Sopenharmony_ci data->pwm_tfmr[index] = tmp; 11178c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11188c2ecf20Sopenharmony_ci break; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci return count; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci#define FANIN_TARGET 0 11248c2ecf20Sopenharmony_ci#define FANIN_TOL 1 11258c2ecf20Sopenharmony_cistatic ssize_t 11268c2ecf20Sopenharmony_cishow_fanin(struct device *dev, struct device_attribute *attr, char *buf) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 11298c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 11308c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 11318c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 11328c2ecf20Sopenharmony_ci int index = sensor_attr->index; 11338c2ecf20Sopenharmony_ci u16 tmp = 0; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci switch (nr) { 11368c2ecf20Sopenharmony_ci case FANIN_TARGET: 11378c2ecf20Sopenharmony_ci tmp = fan_from_reg(data->target_speed[index]); 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci case FANIN_TOL: 11408c2ecf20Sopenharmony_ci tmp = data->tol_speed; 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci } 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", tmp); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic ssize_t 11488c2ecf20Sopenharmony_cistore_fanin(struct device *dev, struct device_attribute *attr, 11498c2ecf20Sopenharmony_ci const char *buf, size_t count) 11508c2ecf20Sopenharmony_ci{ 11518c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 11528c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 11538c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 11548c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 11558c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 11568c2ecf20Sopenharmony_ci int index = sensor_attr->index; 11578c2ecf20Sopenharmony_ci unsigned long val; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 11608c2ecf20Sopenharmony_ci return -EINVAL; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11638c2ecf20Sopenharmony_ci switch (nr) { 11648c2ecf20Sopenharmony_ci case FANIN_TARGET: 11658c2ecf20Sopenharmony_ci val = fan_to_reg(clamp_val(val, 0, 0xfff)); 11668c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FTSH(index), val >> 4); 11678c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0); 11688c2ecf20Sopenharmony_ci data->target_speed[index] = val; 11698c2ecf20Sopenharmony_ci break; 11708c2ecf20Sopenharmony_ci case FANIN_TOL: 11718c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x3f); 11728c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TFTS, val); 11738c2ecf20Sopenharmony_ci data->tol_speed = val; 11748c2ecf20Sopenharmony_ci break; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci return count; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_cistatic ssize_t 11838c2ecf20Sopenharmony_cishow_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf) 11848c2ecf20Sopenharmony_ci{ 11858c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 11868c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 11878c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 11888c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 11898c2ecf20Sopenharmony_ci int index = sensor_attr->index; 11908c2ecf20Sopenharmony_ci long tmp = temp_from_reg(data->pwm_temp[index][nr]); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", tmp); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic ssize_t 11968c2ecf20Sopenharmony_cistore_temp_pwm(struct device *dev, struct device_attribute *attr, 11978c2ecf20Sopenharmony_ci const char *buf, size_t count) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 12008c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 12018c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 12028c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 12038c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 12048c2ecf20Sopenharmony_ci int index = sensor_attr->index; 12058c2ecf20Sopenharmony_ci unsigned long val; 12068c2ecf20Sopenharmony_ci u8 tmp; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 12098c2ecf20Sopenharmony_ci return -EINVAL; 12108c2ecf20Sopenharmony_ci val /= 1000; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12138c2ecf20Sopenharmony_ci switch (nr) { 12148c2ecf20Sopenharmony_ci case TEMP_PWM_TTTI: 12158c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x7f); 12168c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TTTI(index), val); 12178c2ecf20Sopenharmony_ci break; 12188c2ecf20Sopenharmony_ci case TEMP_PWM_CTFS: 12198c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x7f); 12208c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_CTFS(index), val); 12218c2ecf20Sopenharmony_ci break; 12228c2ecf20Sopenharmony_ci case TEMP_PWM_HCT: 12238c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x0f); 12248c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_HT(index)); 12258c2ecf20Sopenharmony_ci tmp &= 0x0f; 12268c2ecf20Sopenharmony_ci tmp |= (val << 4) & 0xf0; 12278c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_HT(index), tmp); 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci case TEMP_PWM_HOT: 12308c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x0f); 12318c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_HT(index)); 12328c2ecf20Sopenharmony_ci tmp &= 0xf0; 12338c2ecf20Sopenharmony_ci tmp |= val & 0x0f; 12348c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_HT(index), tmp); 12358c2ecf20Sopenharmony_ci break; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci data->pwm_temp[index][nr] = val; 12388c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci return count; 12418c2ecf20Sopenharmony_ci} 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_cistatic ssize_t 12448c2ecf20Sopenharmony_cishow_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf) 12458c2ecf20Sopenharmony_ci{ 12468c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 12478c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 12488c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 12498c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 12508c2ecf20Sopenharmony_ci int index = sensor_attr->index; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]); 12538c2ecf20Sopenharmony_ci} 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cistatic ssize_t 12568c2ecf20Sopenharmony_cistore_sf4_pwm(struct device *dev, struct device_attribute *attr, 12578c2ecf20Sopenharmony_ci const char *buf, size_t count) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 12608c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 12618c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 12628c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 12638c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 12648c2ecf20Sopenharmony_ci int index = sensor_attr->index; 12658c2ecf20Sopenharmony_ci unsigned long val; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 12688c2ecf20Sopenharmony_ci return -EINVAL; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12718c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_SF4_PWM(index, nr), val); 12728c2ecf20Sopenharmony_ci data->sf4_reg[index][SF4_PWM][nr] = val; 12738c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return count; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic ssize_t 12798c2ecf20Sopenharmony_cishow_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 12828c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 12838c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 12848c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 12858c2ecf20Sopenharmony_ci int index = sensor_attr->index; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci return sprintf(buf, "%u\n", 12888c2ecf20Sopenharmony_ci (data->sf4_reg[index][SF4_TEMP][nr]) * 1000); 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistatic ssize_t 12928c2ecf20Sopenharmony_cistore_sf4_temp(struct device *dev, struct device_attribute *attr, 12938c2ecf20Sopenharmony_ci const char *buf, size_t count) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 12968c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 12978c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 12988c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 12998c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 13008c2ecf20Sopenharmony_ci int index = sensor_attr->index; 13018c2ecf20Sopenharmony_ci unsigned long val; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 13048c2ecf20Sopenharmony_ci return -EINVAL; 13058c2ecf20Sopenharmony_ci val /= 1000; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13088c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val); 13098c2ecf20Sopenharmony_ci data->sf4_reg[index][SF4_TEMP][nr] = val; 13108c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci return count; 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_cistatic ssize_t 13178c2ecf20Sopenharmony_cishow_temp(struct device *dev, struct device_attribute *attr, char *buf) 13188c2ecf20Sopenharmony_ci{ 13198c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 13208c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 13218c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 13228c2ecf20Sopenharmony_ci int index = sensor_attr->index; 13238c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_device(dev); 13248c2ecf20Sopenharmony_ci long temp = temp_from_reg(data->temp[index][nr]); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci if (nr == TEMP_READ) 13278c2ecf20Sopenharmony_ci temp += (data->temp_read_vrlsb[index] >> 6) * 250; 13288c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", temp); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic ssize_t 13328c2ecf20Sopenharmony_cistore_temp(struct device *dev, struct device_attribute *attr, 13338c2ecf20Sopenharmony_ci const char *buf, size_t count) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 13368c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 13378c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 13388c2ecf20Sopenharmony_ci int index = sensor_attr->index; 13398c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 13408c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 13418c2ecf20Sopenharmony_ci long tmp; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &tmp) < 0) 13448c2ecf20Sopenharmony_ci return -EINVAL; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13478c2ecf20Sopenharmony_ci data->temp[index][nr] = temp_to_reg(tmp, -128, 127); 13488c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]); 13498c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13508c2ecf20Sopenharmony_ci return count; 13518c2ecf20Sopenharmony_ci} 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_cistatic ssize_t 13558c2ecf20Sopenharmony_cishow_dts_mode(struct device *dev, struct device_attribute *attr, char *buf) 13568c2ecf20Sopenharmony_ci{ 13578c2ecf20Sopenharmony_ci struct w83795_data *data = dev_get_drvdata(dev); 13588c2ecf20Sopenharmony_ci int tmp; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci if (data->enable_dts & 2) 13618c2ecf20Sopenharmony_ci tmp = 5; 13628c2ecf20Sopenharmony_ci else 13638c2ecf20Sopenharmony_ci tmp = 6; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", tmp); 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic ssize_t 13698c2ecf20Sopenharmony_cishow_dts(struct device *dev, struct device_attribute *attr, char *buf) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 13728c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 13738c2ecf20Sopenharmony_ci int index = sensor_attr->index; 13748c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_device(dev); 13758c2ecf20Sopenharmony_ci long temp = temp_from_reg(data->dts[index]); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci temp += (data->dts_read_vrlsb[index] >> 6) * 250; 13788c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", temp); 13798c2ecf20Sopenharmony_ci} 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_cistatic ssize_t 13828c2ecf20Sopenharmony_cishow_dts_ext(struct device *dev, struct device_attribute *attr, char *buf) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 13858c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 13868c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 13878c2ecf20Sopenharmony_ci struct w83795_data *data = dev_get_drvdata(dev); 13888c2ecf20Sopenharmony_ci long temp = temp_from_reg(data->dts_ext[nr]); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", temp); 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_cistatic ssize_t 13948c2ecf20Sopenharmony_cistore_dts_ext(struct device *dev, struct device_attribute *attr, 13958c2ecf20Sopenharmony_ci const char *buf, size_t count) 13968c2ecf20Sopenharmony_ci{ 13978c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 13988c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 13998c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 14008c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 14018c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 14028c2ecf20Sopenharmony_ci long tmp; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci if (kstrtol(buf, 10, &tmp) < 0) 14058c2ecf20Sopenharmony_ci return -EINVAL; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14088c2ecf20Sopenharmony_ci data->dts_ext[nr] = temp_to_reg(tmp, -128, 127); 14098c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]); 14108c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14118c2ecf20Sopenharmony_ci return count; 14128c2ecf20Sopenharmony_ci} 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic ssize_t 14168c2ecf20Sopenharmony_cishow_temp_mode(struct device *dev, struct device_attribute *attr, char *buf) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct w83795_data *data = dev_get_drvdata(dev); 14198c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 14208c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 14218c2ecf20Sopenharmony_ci int index = sensor_attr->index; 14228c2ecf20Sopenharmony_ci int tmp; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci if (data->temp_mode & (1 << index)) 14258c2ecf20Sopenharmony_ci tmp = 3; /* Thermal diode */ 14268c2ecf20Sopenharmony_ci else 14278c2ecf20Sopenharmony_ci tmp = 4; /* Thermistor */ 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", tmp); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci/* Only for temp1-4 (temp5-6 can only be thermistor) */ 14338c2ecf20Sopenharmony_cistatic ssize_t 14348c2ecf20Sopenharmony_cistore_temp_mode(struct device *dev, struct device_attribute *attr, 14358c2ecf20Sopenharmony_ci const char *buf, size_t count) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 14388c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 14398c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 14408c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 14418c2ecf20Sopenharmony_ci int index = sensor_attr->index; 14428c2ecf20Sopenharmony_ci int reg_shift; 14438c2ecf20Sopenharmony_ci unsigned long val; 14448c2ecf20Sopenharmony_ci u8 tmp; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 14478c2ecf20Sopenharmony_ci return -EINVAL; 14488c2ecf20Sopenharmony_ci if ((val != 4) && (val != 3)) 14498c2ecf20Sopenharmony_ci return -EINVAL; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14528c2ecf20Sopenharmony_ci if (val == 3) { 14538c2ecf20Sopenharmony_ci /* Thermal diode */ 14548c2ecf20Sopenharmony_ci val = 0x01; 14558c2ecf20Sopenharmony_ci data->temp_mode |= 1 << index; 14568c2ecf20Sopenharmony_ci } else if (val == 4) { 14578c2ecf20Sopenharmony_ci /* Thermistor */ 14588c2ecf20Sopenharmony_ci val = 0x03; 14598c2ecf20Sopenharmony_ci data->temp_mode &= ~(1 << index); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci reg_shift = 2 * index; 14638c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 14648c2ecf20Sopenharmony_ci tmp &= ~(0x03 << reg_shift); 14658c2ecf20Sopenharmony_ci tmp |= val << reg_shift; 14668c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_TEMP_CTRL2, tmp); 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14698c2ecf20Sopenharmony_ci return count; 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci/* show/store VIN */ 14748c2ecf20Sopenharmony_cistatic ssize_t 14758c2ecf20Sopenharmony_cishow_in(struct device *dev, struct device_attribute *attr, char *buf) 14768c2ecf20Sopenharmony_ci{ 14778c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 14788c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 14798c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 14808c2ecf20Sopenharmony_ci int index = sensor_attr->index; 14818c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_device(dev); 14828c2ecf20Sopenharmony_ci u16 val = data->in[index][nr]; 14838c2ecf20Sopenharmony_ci u8 lsb_idx; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci switch (nr) { 14868c2ecf20Sopenharmony_ci case IN_READ: 14878c2ecf20Sopenharmony_ci /* calculate this value again by sensors as sensors3.conf */ 14888c2ecf20Sopenharmony_ci if ((index >= 17) && 14898c2ecf20Sopenharmony_ci !((data->has_gain >> (index - 17)) & 1)) 14908c2ecf20Sopenharmony_ci val *= 8; 14918c2ecf20Sopenharmony_ci break; 14928c2ecf20Sopenharmony_ci case IN_MAX: 14938c2ecf20Sopenharmony_ci case IN_LOW: 14948c2ecf20Sopenharmony_ci lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 14958c2ecf20Sopenharmony_ci val <<= 2; 14968c2ecf20Sopenharmony_ci val |= (data->in_lsb[lsb_idx][nr] >> 14978c2ecf20Sopenharmony_ci IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03; 14988c2ecf20Sopenharmony_ci if ((index >= 17) && 14998c2ecf20Sopenharmony_ci !((data->has_gain >> (index - 17)) & 1)) 15008c2ecf20Sopenharmony_ci val *= 8; 15018c2ecf20Sopenharmony_ci break; 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci val = in_from_reg(index, val); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", val); 15068c2ecf20Sopenharmony_ci} 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_cistatic ssize_t 15098c2ecf20Sopenharmony_cistore_in(struct device *dev, struct device_attribute *attr, 15108c2ecf20Sopenharmony_ci const char *buf, size_t count) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15138c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15148c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15158c2ecf20Sopenharmony_ci int index = sensor_attr->index; 15168c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 15178c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 15188c2ecf20Sopenharmony_ci unsigned long val; 15198c2ecf20Sopenharmony_ci u8 tmp; 15208c2ecf20Sopenharmony_ci u8 lsb_idx; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 15238c2ecf20Sopenharmony_ci return -EINVAL; 15248c2ecf20Sopenharmony_ci val = in_to_reg(index, val); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if ((index >= 17) && 15278c2ecf20Sopenharmony_ci !((data->has_gain >> (index - 17)) & 1)) 15288c2ecf20Sopenharmony_ci val /= 8; 15298c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0x3FF); 15308c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX]; 15338c2ecf20Sopenharmony_ci tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr)); 15348c2ecf20Sopenharmony_ci tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]); 15358c2ecf20Sopenharmony_ci tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]; 15368c2ecf20Sopenharmony_ci w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp); 15378c2ecf20Sopenharmony_ci data->in_lsb[lsb_idx][nr] = tmp; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci tmp = (val >> 2) & 0xff; 15408c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_IN[index][nr], tmp); 15418c2ecf20Sopenharmony_ci data->in[index][nr] = tmp; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15448c2ecf20Sopenharmony_ci return count; 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL 15498c2ecf20Sopenharmony_cistatic ssize_t 15508c2ecf20Sopenharmony_cishow_sf_setup(struct device *dev, struct device_attribute *attr, char *buf) 15518c2ecf20Sopenharmony_ci{ 15528c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15538c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15548c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15558c2ecf20Sopenharmony_ci struct w83795_data *data = w83795_update_pwm_config(dev); 15568c2ecf20Sopenharmony_ci u16 val = data->setup_pwm[nr]; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci switch (nr) { 15598c2ecf20Sopenharmony_ci case SETUP_PWM_UPTIME: 15608c2ecf20Sopenharmony_ci case SETUP_PWM_DOWNTIME: 15618c2ecf20Sopenharmony_ci val = time_from_reg(val); 15628c2ecf20Sopenharmony_ci break; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", val); 15668c2ecf20Sopenharmony_ci} 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_cistatic ssize_t 15698c2ecf20Sopenharmony_cistore_sf_setup(struct device *dev, struct device_attribute *attr, 15708c2ecf20Sopenharmony_ci const char *buf, size_t count) 15718c2ecf20Sopenharmony_ci{ 15728c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *sensor_attr = 15738c2ecf20Sopenharmony_ci to_sensor_dev_attr_2(attr); 15748c2ecf20Sopenharmony_ci int nr = sensor_attr->nr; 15758c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 15768c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 15778c2ecf20Sopenharmony_ci unsigned long val; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (kstrtoul(buf, 10, &val) < 0) 15808c2ecf20Sopenharmony_ci return -EINVAL; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci switch (nr) { 15838c2ecf20Sopenharmony_ci case SETUP_PWM_DEFAULT: 15848c2ecf20Sopenharmony_ci val = clamp_val(val, 0, 0xff); 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci case SETUP_PWM_UPTIME: 15878c2ecf20Sopenharmony_ci case SETUP_PWM_DOWNTIME: 15888c2ecf20Sopenharmony_ci val = time_to_reg(val); 15898c2ecf20Sopenharmony_ci if (val == 0) 15908c2ecf20Sopenharmony_ci return -EINVAL; 15918c2ecf20Sopenharmony_ci break; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15958c2ecf20Sopenharmony_ci data->setup_pwm[nr] = val; 15968c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_SETUP_PWM(nr), val); 15978c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15988c2ecf20Sopenharmony_ci return count; 15998c2ecf20Sopenharmony_ci} 16008c2ecf20Sopenharmony_ci#endif 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci#define NOT_USED -1 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci/* 16068c2ecf20Sopenharmony_ci * Don't change the attribute order, _max, _min and _beep are accessed by index 16078c2ecf20Sopenharmony_ci * somewhere else in the code 16088c2ecf20Sopenharmony_ci */ 16098c2ecf20Sopenharmony_ci#define SENSOR_ATTR_IN(index) { \ 16108c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL, \ 16118c2ecf20Sopenharmony_ci IN_READ, index), \ 16128c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in, \ 16138c2ecf20Sopenharmony_ci store_in, IN_MAX, index), \ 16148c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in, \ 16158c2ecf20Sopenharmony_ci store_in, IN_LOW, index), \ 16168c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep, \ 16178c2ecf20Sopenharmony_ci NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \ 16188c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO, \ 16198c2ecf20Sopenharmony_ci show_alarm_beep, store_beep, BEEP_ENABLE, \ 16208c2ecf20Sopenharmony_ci index + ((index > 14) ? 1 : 0)) } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci/* 16238c2ecf20Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index 16248c2ecf20Sopenharmony_ci * somewhere else in the code 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ci#define SENSOR_ATTR_FAN(index) { \ 16278c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan, \ 16288c2ecf20Sopenharmony_ci NULL, FAN_INPUT, index - 1), \ 16298c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO, \ 16308c2ecf20Sopenharmony_ci show_fan, store_fan_min, FAN_MIN, index - 1), \ 16318c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep, \ 16328c2ecf20Sopenharmony_ci NULL, ALARM_STATUS, index + 31), \ 16338c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO, \ 16348c2ecf20Sopenharmony_ci show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) } 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci#define SENSOR_ATTR_PWM(index) { \ 16378c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm, \ 16388c2ecf20Sopenharmony_ci store_pwm, PWM_OUTPUT, index - 1), \ 16398c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO, \ 16408c2ecf20Sopenharmony_ci show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \ 16418c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO, \ 16428c2ecf20Sopenharmony_ci show_pwm_mode, NULL, NOT_USED, index - 1), \ 16438c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO, \ 16448c2ecf20Sopenharmony_ci show_pwm, store_pwm, PWM_FREQ, index - 1), \ 16458c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO, \ 16468c2ecf20Sopenharmony_ci show_pwm, store_pwm, PWM_NONSTOP, index - 1), \ 16478c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO, \ 16488c2ecf20Sopenharmony_ci show_pwm, store_pwm, PWM_START, index - 1), \ 16498c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO, \ 16508c2ecf20Sopenharmony_ci show_pwm, store_pwm, PWM_STOP_TIME, index - 1), \ 16518c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \ 16528c2ecf20Sopenharmony_ci show_fanin, store_fanin, FANIN_TARGET, index - 1) } 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci/* 16558c2ecf20Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index 16568c2ecf20Sopenharmony_ci * somewhere else in the code 16578c2ecf20Sopenharmony_ci */ 16588c2ecf20Sopenharmony_ci#define SENSOR_ATTR_DTS(index) { \ 16598c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_type, S_IRUGO , \ 16608c2ecf20Sopenharmony_ci show_dts_mode, NULL, NOT_USED, index - 7), \ 16618c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts, \ 16628c2ecf20Sopenharmony_ci NULL, NOT_USED, index - 7), \ 16638c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \ 16648c2ecf20Sopenharmony_ci store_dts_ext, DTS_CRIT, NOT_USED), \ 16658c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 16668c2ecf20Sopenharmony_ci show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED), \ 16678c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \ 16688c2ecf20Sopenharmony_ci store_dts_ext, DTS_WARN, NOT_USED), \ 16698c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 16708c2ecf20Sopenharmony_ci show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED), \ 16718c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 16728c2ecf20Sopenharmony_ci show_alarm_beep, NULL, ALARM_STATUS, index + 17), \ 16738c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 16748c2ecf20Sopenharmony_ci show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) } 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci/* 16778c2ecf20Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index 16788c2ecf20Sopenharmony_ci * somewhere else in the code 16798c2ecf20Sopenharmony_ci */ 16808c2ecf20Sopenharmony_ci#define SENSOR_ATTR_TEMP(index) { \ 16818c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 5 ? S_IWUSR : 0), \ 16828c2ecf20Sopenharmony_ci show_temp_mode, store_temp_mode, NOT_USED, index - 1), \ 16838c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp, \ 16848c2ecf20Sopenharmony_ci NULL, TEMP_READ, index - 1), \ 16858c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp, \ 16868c2ecf20Sopenharmony_ci store_temp, TEMP_CRIT, index - 1), \ 16878c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR, \ 16888c2ecf20Sopenharmony_ci show_temp, store_temp, TEMP_CRIT_HYST, index - 1), \ 16898c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp, \ 16908c2ecf20Sopenharmony_ci store_temp, TEMP_WARN, index - 1), \ 16918c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR, \ 16928c2ecf20Sopenharmony_ci show_temp, store_temp, TEMP_WARN_HYST, index - 1), \ 16938c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO, \ 16948c2ecf20Sopenharmony_ci show_alarm_beep, NULL, ALARM_STATUS, \ 16958c2ecf20Sopenharmony_ci index + (index > 4 ? 11 : 17)), \ 16968c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO, \ 16978c2ecf20Sopenharmony_ci show_alarm_beep, store_beep, BEEP_ENABLE, \ 16988c2ecf20Sopenharmony_ci index + (index > 4 ? 11 : 17)), \ 16998c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO, \ 17008c2ecf20Sopenharmony_ci show_temp_pwm_enable, store_temp_pwm_enable, \ 17018c2ecf20Sopenharmony_ci TEMP_PWM_ENABLE, index - 1), \ 17028c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \ 17038c2ecf20Sopenharmony_ci show_temp_pwm_enable, store_temp_pwm_enable, \ 17048c2ecf20Sopenharmony_ci TEMP_PWM_FAN_MAP, index - 1), \ 17058c2ecf20Sopenharmony_ci SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO, \ 17068c2ecf20Sopenharmony_ci show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \ 17078c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO, \ 17088c2ecf20Sopenharmony_ci show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \ 17098c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO, \ 17108c2ecf20Sopenharmony_ci show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \ 17118c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO, \ 17128c2ecf20Sopenharmony_ci show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \ 17138c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \ 17148c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 0, index - 1), \ 17158c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \ 17168c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 1, index - 1), \ 17178c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \ 17188c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 2, index - 1), \ 17198c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \ 17208c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 3, index - 1), \ 17218c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \ 17228c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 4, index - 1), \ 17238c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \ 17248c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 5, index - 1), \ 17258c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \ 17268c2ecf20Sopenharmony_ci show_sf4_pwm, store_sf4_pwm, 6, index - 1), \ 17278c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\ 17288c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 0, index - 1), \ 17298c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\ 17308c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 1, index - 1), \ 17318c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\ 17328c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 2, index - 1), \ 17338c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\ 17348c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 3, index - 1), \ 17358c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\ 17368c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 4, index - 1), \ 17378c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\ 17388c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 5, index - 1), \ 17398c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\ 17408c2ecf20Sopenharmony_ci show_sf4_temp, store_sf4_temp, 6, index - 1) } 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic struct sensor_device_attribute_2 w83795_in[][5] = { 17448c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(0), 17458c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(1), 17468c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(2), 17478c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(3), 17488c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(4), 17498c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(5), 17508c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(6), 17518c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(7), 17528c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(8), 17538c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(9), 17548c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(10), 17558c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(11), 17568c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(12), 17578c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(13), 17588c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(14), 17598c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(15), 17608c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(16), 17618c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(17), 17628c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(18), 17638c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(19), 17648c2ecf20Sopenharmony_ci SENSOR_ATTR_IN(20), 17658c2ecf20Sopenharmony_ci}; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_fan[][4] = { 17688c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(1), 17698c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(2), 17708c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(3), 17718c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(4), 17728c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(5), 17738c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(6), 17748c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(7), 17758c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(8), 17768c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(9), 17778c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(10), 17788c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(11), 17798c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(12), 17808c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(13), 17818c2ecf20Sopenharmony_ci SENSOR_ATTR_FAN(14), 17828c2ecf20Sopenharmony_ci}; 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_temp[][28] = { 17858c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(1), 17868c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(2), 17878c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(3), 17888c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(4), 17898c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(5), 17908c2ecf20Sopenharmony_ci SENSOR_ATTR_TEMP(6), 17918c2ecf20Sopenharmony_ci}; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_dts[][8] = { 17948c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(7), 17958c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(8), 17968c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(9), 17978c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(10), 17988c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(11), 17998c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(12), 18008c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(13), 18018c2ecf20Sopenharmony_ci SENSOR_ATTR_DTS(14), 18028c2ecf20Sopenharmony_ci}; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_pwm[][8] = { 18058c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(1), 18068c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(2), 18078c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(3), 18088c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(4), 18098c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(5), 18108c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(6), 18118c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(7), 18128c2ecf20Sopenharmony_ci SENSOR_ATTR_PWM(8), 18138c2ecf20Sopenharmony_ci}; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_tss[6] = { 18168c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO, 18178c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 0), 18188c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO, 18198c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 1), 18208c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO, 18218c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 2), 18228c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO, 18238c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 3), 18248c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO, 18258c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 4), 18268c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO, 18278c2ecf20Sopenharmony_ci show_temp_src, store_temp_src, NOT_USED, 5), 18288c2ecf20Sopenharmony_ci}; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 sda_single_files[] = { 18318c2ecf20Sopenharmony_ci SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, 18328c2ecf20Sopenharmony_ci store_chassis_clear, ALARM_STATUS, 46), 18338c2ecf20Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL 18348c2ecf20Sopenharmony_ci SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin, 18358c2ecf20Sopenharmony_ci store_fanin, FANIN_TOL, NOT_USED), 18368c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup, 18378c2ecf20Sopenharmony_ci store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED), 18388c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup, 18398c2ecf20Sopenharmony_ci store_sf_setup, SETUP_PWM_UPTIME, NOT_USED), 18408c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup, 18418c2ecf20Sopenharmony_ci store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED), 18428c2ecf20Sopenharmony_ci#endif 18438c2ecf20Sopenharmony_ci}; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 sda_beep_files[] = { 18468c2ecf20Sopenharmony_ci SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep, 18478c2ecf20Sopenharmony_ci store_beep, BEEP_ENABLE, 46), 18488c2ecf20Sopenharmony_ci SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep, 18498c2ecf20Sopenharmony_ci store_beep, BEEP_ENABLE, 47), 18508c2ecf20Sopenharmony_ci}; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci/* 18538c2ecf20Sopenharmony_ci * Driver interface 18548c2ecf20Sopenharmony_ci */ 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_cistatic void w83795_init_client(struct i2c_client *client) 18578c2ecf20Sopenharmony_ci{ 18588c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 18598c2ecf20Sopenharmony_ci static const u16 clkin[4] = { /* in kHz */ 18608c2ecf20Sopenharmony_ci 14318, 24000, 33333, 48000 18618c2ecf20Sopenharmony_ci }; 18628c2ecf20Sopenharmony_ci u8 config; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci if (reset) 18658c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_CONFIG, 0x80); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci /* Start monitoring if needed */ 18688c2ecf20Sopenharmony_ci config = w83795_read(client, W83795_REG_CONFIG); 18698c2ecf20Sopenharmony_ci if (!(config & W83795_REG_CONFIG_START)) { 18708c2ecf20Sopenharmony_ci dev_info(&client->dev, "Enabling monitoring operations\n"); 18718c2ecf20Sopenharmony_ci w83795_write(client, W83795_REG_CONFIG, 18728c2ecf20Sopenharmony_ci config | W83795_REG_CONFIG_START); 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci data->clkin = clkin[(config >> 3) & 0x3]; 18768c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin); 18778c2ecf20Sopenharmony_ci} 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_cistatic int w83795_get_device_id(struct i2c_client *client) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci int device_id; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci /* 18868c2ecf20Sopenharmony_ci * Special case for rev. A chips; can't be checked first because later 18878c2ecf20Sopenharmony_ci * revisions emulate this for compatibility 18888c2ecf20Sopenharmony_ci */ 18898c2ecf20Sopenharmony_ci if (device_id < 0 || (device_id & 0xf0) != 0x50) { 18908c2ecf20Sopenharmony_ci int alt_id; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci alt_id = i2c_smbus_read_byte_data(client, 18938c2ecf20Sopenharmony_ci W83795_REG_DEVICEID_A); 18948c2ecf20Sopenharmony_ci if (alt_id == 0x50) 18958c2ecf20Sopenharmony_ci device_id = alt_id; 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci return device_id; 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 19028c2ecf20Sopenharmony_cistatic int w83795_detect(struct i2c_client *client, 19038c2ecf20Sopenharmony_ci struct i2c_board_info *info) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci int bank, vendor_id, device_id, expected, i2c_addr, config; 19068c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 19078c2ecf20Sopenharmony_ci unsigned short address = client->addr; 19088c2ecf20Sopenharmony_ci const char *chip_name; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 19118c2ecf20Sopenharmony_ci return -ENODEV; 19128c2ecf20Sopenharmony_ci bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 19138c2ecf20Sopenharmony_ci if (bank < 0 || (bank & 0x7c)) { 19148c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 19158c2ecf20Sopenharmony_ci "w83795: Detection failed at addr 0x%02hx, check %s\n", 19168c2ecf20Sopenharmony_ci address, "bank"); 19178c2ecf20Sopenharmony_ci return -ENODEV; 19188c2ecf20Sopenharmony_ci } 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci /* Check Nuvoton vendor ID */ 19218c2ecf20Sopenharmony_ci vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID); 19228c2ecf20Sopenharmony_ci expected = bank & 0x80 ? 0x5c : 0xa3; 19238c2ecf20Sopenharmony_ci if (vendor_id != expected) { 19248c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 19258c2ecf20Sopenharmony_ci "w83795: Detection failed at addr 0x%02hx, check %s\n", 19268c2ecf20Sopenharmony_ci address, "vendor id"); 19278c2ecf20Sopenharmony_ci return -ENODEV; 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci /* Check device ID */ 19318c2ecf20Sopenharmony_ci device_id = w83795_get_device_id(client) | 19328c2ecf20Sopenharmony_ci (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8); 19338c2ecf20Sopenharmony_ci if ((device_id >> 4) != 0x795) { 19348c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 19358c2ecf20Sopenharmony_ci "w83795: Detection failed at addr 0x%02hx, check %s\n", 19368c2ecf20Sopenharmony_ci address, "device id\n"); 19378c2ecf20Sopenharmony_ci return -ENODEV; 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* 19418c2ecf20Sopenharmony_ci * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR 19428c2ecf20Sopenharmony_ci * should match 19438c2ecf20Sopenharmony_ci */ 19448c2ecf20Sopenharmony_ci if ((bank & 0x07) == 0) { 19458c2ecf20Sopenharmony_ci i2c_addr = i2c_smbus_read_byte_data(client, 19468c2ecf20Sopenharmony_ci W83795_REG_I2C_ADDR); 19478c2ecf20Sopenharmony_ci if ((i2c_addr & 0x7f) != address) { 19488c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 19498c2ecf20Sopenharmony_ci "w83795: Detection failed at addr 0x%02hx, " 19508c2ecf20Sopenharmony_ci "check %s\n", address, "i2c addr"); 19518c2ecf20Sopenharmony_ci return -ENODEV; 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci } 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci /* 19568c2ecf20Sopenharmony_ci * Check 795 chip type: 795G or 795ADG 19578c2ecf20Sopenharmony_ci * Usually we don't write to chips during detection, but here we don't 19588c2ecf20Sopenharmony_ci * quite have the choice; hopefully it's OK, we are about to return 19598c2ecf20Sopenharmony_ci * success anyway 19608c2ecf20Sopenharmony_ci */ 19618c2ecf20Sopenharmony_ci if ((bank & 0x07) != 0) 19628c2ecf20Sopenharmony_ci i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, 19638c2ecf20Sopenharmony_ci bank & ~0x07); 19648c2ecf20Sopenharmony_ci config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG); 19658c2ecf20Sopenharmony_ci if (config & W83795_REG_CONFIG_CONFIG48) 19668c2ecf20Sopenharmony_ci chip_name = "w83795adg"; 19678c2ecf20Sopenharmony_ci else 19688c2ecf20Sopenharmony_ci chip_name = "w83795g"; 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci strlcpy(info->type, chip_name, I2C_NAME_SIZE); 19718c2ecf20Sopenharmony_ci dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name, 19728c2ecf20Sopenharmony_ci 'A' + (device_id & 0xf), address); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci return 0; 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL 19788c2ecf20Sopenharmony_ci#define NUM_PWM_ATTRIBUTES ARRAY_SIZE(w83795_pwm[0]) 19798c2ecf20Sopenharmony_ci#define NUM_TEMP_ATTRIBUTES ARRAY_SIZE(w83795_temp[0]) 19808c2ecf20Sopenharmony_ci#else 19818c2ecf20Sopenharmony_ci#define NUM_PWM_ATTRIBUTES 4 19828c2ecf20Sopenharmony_ci#define NUM_TEMP_ATTRIBUTES 8 19838c2ecf20Sopenharmony_ci#endif 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_cistatic int w83795_handle_files(struct device *dev, int (*fn)(struct device *, 19868c2ecf20Sopenharmony_ci const struct device_attribute *)) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci struct w83795_data *data = dev_get_drvdata(dev); 19898c2ecf20Sopenharmony_ci int err, i, j; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(w83795_in); i++) { 19928c2ecf20Sopenharmony_ci if (!(data->has_in & (1 << i))) 19938c2ecf20Sopenharmony_ci continue; 19948c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) { 19958c2ecf20Sopenharmony_ci if (j == 4 && !data->enable_beep) 19968c2ecf20Sopenharmony_ci continue; 19978c2ecf20Sopenharmony_ci err = fn(dev, &w83795_in[i][j].dev_attr); 19988c2ecf20Sopenharmony_ci if (err) 19998c2ecf20Sopenharmony_ci return err; 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci } 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) { 20048c2ecf20Sopenharmony_ci if (!(data->has_fan & (1 << i))) 20058c2ecf20Sopenharmony_ci continue; 20068c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) { 20078c2ecf20Sopenharmony_ci if (j == 3 && !data->enable_beep) 20088c2ecf20Sopenharmony_ci continue; 20098c2ecf20Sopenharmony_ci err = fn(dev, &w83795_fan[i][j].dev_attr); 20108c2ecf20Sopenharmony_ci if (err) 20118c2ecf20Sopenharmony_ci return err; 20128c2ecf20Sopenharmony_ci } 20138c2ecf20Sopenharmony_ci } 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) { 20168c2ecf20Sopenharmony_ci j = w83795_tss_useful(data, i); 20178c2ecf20Sopenharmony_ci if (!j) 20188c2ecf20Sopenharmony_ci continue; 20198c2ecf20Sopenharmony_ci err = fn(dev, &w83795_tss[i].dev_attr); 20208c2ecf20Sopenharmony_ci if (err) 20218c2ecf20Sopenharmony_ci return err; 20228c2ecf20Sopenharmony_ci } 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) { 20258c2ecf20Sopenharmony_ci err = fn(dev, &sda_single_files[i].dev_attr); 20268c2ecf20Sopenharmony_ci if (err) 20278c2ecf20Sopenharmony_ci return err; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (data->enable_beep) { 20318c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) { 20328c2ecf20Sopenharmony_ci err = fn(dev, &sda_beep_files[i].dev_attr); 20338c2ecf20Sopenharmony_ci if (err) 20348c2ecf20Sopenharmony_ci return err; 20358c2ecf20Sopenharmony_ci } 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci for (i = 0; i < data->has_pwm; i++) { 20398c2ecf20Sopenharmony_ci for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) { 20408c2ecf20Sopenharmony_ci err = fn(dev, &w83795_pwm[i][j].dev_attr); 20418c2ecf20Sopenharmony_ci if (err) 20428c2ecf20Sopenharmony_ci return err; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) { 20478c2ecf20Sopenharmony_ci if (!(data->has_temp & (1 << i))) 20488c2ecf20Sopenharmony_ci continue; 20498c2ecf20Sopenharmony_ci for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) { 20508c2ecf20Sopenharmony_ci if (j == 7 && !data->enable_beep) 20518c2ecf20Sopenharmony_ci continue; 20528c2ecf20Sopenharmony_ci err = fn(dev, &w83795_temp[i][j].dev_attr); 20538c2ecf20Sopenharmony_ci if (err) 20548c2ecf20Sopenharmony_ci return err; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci } 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci if (data->enable_dts) { 20598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) { 20608c2ecf20Sopenharmony_ci if (!(data->has_dts & (1 << i))) 20618c2ecf20Sopenharmony_ci continue; 20628c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) { 20638c2ecf20Sopenharmony_ci if (j == 7 && !data->enable_beep) 20648c2ecf20Sopenharmony_ci continue; 20658c2ecf20Sopenharmony_ci err = fn(dev, &w83795_dts[i][j].dev_attr); 20668c2ecf20Sopenharmony_ci if (err) 20678c2ecf20Sopenharmony_ci return err; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci } 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci return 0; 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci/* We need a wrapper that fits in w83795_handle_files */ 20768c2ecf20Sopenharmony_cistatic int device_remove_file_wrapper(struct device *dev, 20778c2ecf20Sopenharmony_ci const struct device_attribute *attr) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci device_remove_file(dev, attr); 20808c2ecf20Sopenharmony_ci return 0; 20818c2ecf20Sopenharmony_ci} 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_cistatic void w83795_check_dynamic_in_limits(struct i2c_client *client) 20848c2ecf20Sopenharmony_ci{ 20858c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 20868c2ecf20Sopenharmony_ci u8 vid_ctl; 20878c2ecf20Sopenharmony_ci int i, err_max, err_min; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci vid_ctl = w83795_read(client, W83795_REG_VID_CTRL); 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci /* Return immediately if VRM isn't configured */ 20928c2ecf20Sopenharmony_ci if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07) 20938c2ecf20Sopenharmony_ci return; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci data->has_dyn_in = (vid_ctl >> 3) & 0x07; 20968c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 20978c2ecf20Sopenharmony_ci if (!(data->has_dyn_in & (1 << i))) 20988c2ecf20Sopenharmony_ci continue; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci /* Voltage limits in dynamic mode, switch to read-only */ 21018c2ecf20Sopenharmony_ci err_max = sysfs_chmod_file(&client->dev.kobj, 21028c2ecf20Sopenharmony_ci &w83795_in[i][2].dev_attr.attr, 21038c2ecf20Sopenharmony_ci S_IRUGO); 21048c2ecf20Sopenharmony_ci err_min = sysfs_chmod_file(&client->dev.kobj, 21058c2ecf20Sopenharmony_ci &w83795_in[i][3].dev_attr.attr, 21068c2ecf20Sopenharmony_ci S_IRUGO); 21078c2ecf20Sopenharmony_ci if (err_max || err_min) 21088c2ecf20Sopenharmony_ci dev_warn(&client->dev, 21098c2ecf20Sopenharmony_ci "Failed to set in%d limits read-only (%d, %d)\n", 21108c2ecf20Sopenharmony_ci i, err_max, err_min); 21118c2ecf20Sopenharmony_ci else 21128c2ecf20Sopenharmony_ci dev_info(&client->dev, 21138c2ecf20Sopenharmony_ci "in%d limits set dynamically from VID\n", i); 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci/* Check pins that can be used for either temperature or voltage monitoring */ 21188c2ecf20Sopenharmony_cistatic void w83795_apply_temp_config(struct w83795_data *data, u8 config, 21198c2ecf20Sopenharmony_ci int temp_chan, int in_chan) 21208c2ecf20Sopenharmony_ci{ 21218c2ecf20Sopenharmony_ci /* config is a 2-bit value */ 21228c2ecf20Sopenharmony_ci switch (config) { 21238c2ecf20Sopenharmony_ci case 0x2: /* Voltage monitoring */ 21248c2ecf20Sopenharmony_ci data->has_in |= 1 << in_chan; 21258c2ecf20Sopenharmony_ci break; 21268c2ecf20Sopenharmony_ci case 0x1: /* Thermal diode */ 21278c2ecf20Sopenharmony_ci if (temp_chan >= 4) 21288c2ecf20Sopenharmony_ci break; 21298c2ecf20Sopenharmony_ci data->temp_mode |= 1 << temp_chan; 21308c2ecf20Sopenharmony_ci fallthrough; 21318c2ecf20Sopenharmony_ci case 0x3: /* Thermistor */ 21328c2ecf20Sopenharmony_ci data->has_temp |= 1 << temp_chan; 21338c2ecf20Sopenharmony_ci break; 21348c2ecf20Sopenharmony_ci } 21358c2ecf20Sopenharmony_ci} 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_cistatic const struct i2c_device_id w83795_id[]; 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_cistatic int w83795_probe(struct i2c_client *client) 21408c2ecf20Sopenharmony_ci{ 21418c2ecf20Sopenharmony_ci int i; 21428c2ecf20Sopenharmony_ci u8 tmp; 21438c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 21448c2ecf20Sopenharmony_ci struct w83795_data *data; 21458c2ecf20Sopenharmony_ci int err; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL); 21488c2ecf20Sopenharmony_ci if (!data) 21498c2ecf20Sopenharmony_ci return -ENOMEM; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci i2c_set_clientdata(client, data); 21528c2ecf20Sopenharmony_ci data->chip_type = i2c_match_id(w83795_id, client)->driver_data; 21538c2ecf20Sopenharmony_ci data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL); 21548c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci /* Initialize the chip */ 21578c2ecf20Sopenharmony_ci w83795_init_client(client); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* Check which voltages and fans are present */ 21608c2ecf20Sopenharmony_ci data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1) 21618c2ecf20Sopenharmony_ci | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8); 21628c2ecf20Sopenharmony_ci data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1) 21638c2ecf20Sopenharmony_ci | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8); 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci /* Check which analog temperatures and extra voltages are present */ 21668c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_TEMP_CTRL1); 21678c2ecf20Sopenharmony_ci if (tmp & 0x20) 21688c2ecf20Sopenharmony_ci data->enable_dts = 1; 21698c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16); 21708c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, tmp & 0x3, 4, 15); 21718c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_TEMP_CTRL2); 21728c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, tmp >> 6, 3, 20); 21738c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19); 21748c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18); 21758c2ecf20Sopenharmony_ci w83795_apply_temp_config(data, tmp & 0x3, 0, 17); 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci /* Check DTS enable status */ 21788c2ecf20Sopenharmony_ci if (data->enable_dts) { 21798c2ecf20Sopenharmony_ci if (1 & w83795_read(client, W83795_REG_DTSC)) 21808c2ecf20Sopenharmony_ci data->enable_dts |= 2; 21818c2ecf20Sopenharmony_ci data->has_dts = w83795_read(client, W83795_REG_DTSE); 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci /* Report PECI Tbase values */ 21858c2ecf20Sopenharmony_ci if (data->enable_dts == 1) { 21868c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 21878c2ecf20Sopenharmony_ci if (!(data->has_dts & (1 << i))) 21888c2ecf20Sopenharmony_ci continue; 21898c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_PECI_TBASE(i)); 21908c2ecf20Sopenharmony_ci dev_info(&client->dev, 21918c2ecf20Sopenharmony_ci "PECI agent %d Tbase temperature: %u\n", 21928c2ecf20Sopenharmony_ci i + 1, (unsigned int)tmp & 0x7f); 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci /* pwm and smart fan */ 21998c2ecf20Sopenharmony_ci if (data->chip_type == w83795g) 22008c2ecf20Sopenharmony_ci data->has_pwm = 8; 22018c2ecf20Sopenharmony_ci else 22028c2ecf20Sopenharmony_ci data->has_pwm = 2; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci /* Check if BEEP pin is available */ 22058c2ecf20Sopenharmony_ci if (data->chip_type == w83795g) { 22068c2ecf20Sopenharmony_ci /* The W83795G has a dedicated BEEP pin */ 22078c2ecf20Sopenharmony_ci data->enable_beep = 1; 22088c2ecf20Sopenharmony_ci } else { 22098c2ecf20Sopenharmony_ci /* 22108c2ecf20Sopenharmony_ci * The W83795ADG has a shared pin for OVT# and BEEP, so you 22118c2ecf20Sopenharmony_ci * can't have both 22128c2ecf20Sopenharmony_ci */ 22138c2ecf20Sopenharmony_ci tmp = w83795_read(client, W83795_REG_OVT_CFG); 22148c2ecf20Sopenharmony_ci if ((tmp & OVT_CFG_SEL) == 0) 22158c2ecf20Sopenharmony_ci data->enable_beep = 1; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci err = w83795_handle_files(dev, device_create_file); 22198c2ecf20Sopenharmony_ci if (err) 22208c2ecf20Sopenharmony_ci goto exit_remove; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (data->chip_type == w83795g) 22238c2ecf20Sopenharmony_ci w83795_check_dynamic_in_limits(client); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci data->hwmon_dev = hwmon_device_register(dev); 22268c2ecf20Sopenharmony_ci if (IS_ERR(data->hwmon_dev)) { 22278c2ecf20Sopenharmony_ci err = PTR_ERR(data->hwmon_dev); 22288c2ecf20Sopenharmony_ci goto exit_remove; 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return 0; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ciexit_remove: 22348c2ecf20Sopenharmony_ci w83795_handle_files(dev, device_remove_file_wrapper); 22358c2ecf20Sopenharmony_ci return err; 22368c2ecf20Sopenharmony_ci} 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_cistatic int w83795_remove(struct i2c_client *client) 22398c2ecf20Sopenharmony_ci{ 22408c2ecf20Sopenharmony_ci struct w83795_data *data = i2c_get_clientdata(client); 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 22438c2ecf20Sopenharmony_ci w83795_handle_files(&client->dev, device_remove_file_wrapper); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci return 0; 22468c2ecf20Sopenharmony_ci} 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_cistatic const struct i2c_device_id w83795_id[] = { 22508c2ecf20Sopenharmony_ci { "w83795g", w83795g }, 22518c2ecf20Sopenharmony_ci { "w83795adg", w83795adg }, 22528c2ecf20Sopenharmony_ci { } 22538c2ecf20Sopenharmony_ci}; 22548c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, w83795_id); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_cistatic struct i2c_driver w83795_driver = { 22578c2ecf20Sopenharmony_ci .driver = { 22588c2ecf20Sopenharmony_ci .name = "w83795", 22598c2ecf20Sopenharmony_ci }, 22608c2ecf20Sopenharmony_ci .probe_new = w83795_probe, 22618c2ecf20Sopenharmony_ci .remove = w83795_remove, 22628c2ecf20Sopenharmony_ci .id_table = w83795_id, 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci .class = I2C_CLASS_HWMON, 22658c2ecf20Sopenharmony_ci .detect = w83795_detect, 22668c2ecf20Sopenharmony_ci .address_list = normal_i2c, 22678c2ecf20Sopenharmony_ci}; 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_cimodule_i2c_driver(w83795_driver); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wei Song, Jean Delvare <jdelvare@suse.de>"); 22728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver"); 22738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2274