18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com> 68c2ecf20Sopenharmony_ci * Copyright (c) 2004 Utilitek Systems, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * derived in part from lm78.c: 98c2ecf20Sopenharmony_ci * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * derived in part from lm85.c: 128c2ecf20Sopenharmony_ci * Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> 138c2ecf20Sopenharmony_ci * Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * derived in part from w83l785ts.c: 168c2ecf20Sopenharmony_ci * Copyright (c) 2003-2004 Jean Delvare <jdelvare@suse.de> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com> 198c2ecf20Sopenharmony_ci * Copyright (c) 2005 Aspen Systems, Inc. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org> 228c2ecf20Sopenharmony_ci * Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Modified for mainline integration by Hans J. Koch <hjk@hansjkoch.de> 258c2ecf20Sopenharmony_ci * Copyright (c) 2007 Hans J. Koch, Linutronix GmbH 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/init.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/i2c.h> 328c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 338c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 348c2ecf20Sopenharmony_ci#include <linux/hwmon-vid.h> 358c2ecf20Sopenharmony_ci#include <linux/err.h> 368c2ecf20Sopenharmony_ci#include <linux/delay.h> 378c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* LM93 REGISTER ADDRESSES */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* miscellaneous */ 428c2ecf20Sopenharmony_ci#define LM93_REG_MFR_ID 0x3e 438c2ecf20Sopenharmony_ci#define LM93_REG_VER 0x3f 448c2ecf20Sopenharmony_ci#define LM93_REG_STATUS_CONTROL 0xe2 458c2ecf20Sopenharmony_ci#define LM93_REG_CONFIG 0xe3 468c2ecf20Sopenharmony_ci#define LM93_REG_SLEEP_CONTROL 0xe4 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* alarm values start here */ 498c2ecf20Sopenharmony_ci#define LM93_REG_HOST_ERROR_1 0x48 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* voltage inputs: in1-in16 (nr => 0-15) */ 528c2ecf20Sopenharmony_ci#define LM93_REG_IN(nr) (0x56 + (nr)) 538c2ecf20Sopenharmony_ci#define LM93_REG_IN_MIN(nr) (0x90 + (nr) * 2) 548c2ecf20Sopenharmony_ci#define LM93_REG_IN_MAX(nr) (0x91 + (nr) * 2) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* temperature inputs: temp1-temp4 (nr => 0-3) */ 578c2ecf20Sopenharmony_ci#define LM93_REG_TEMP(nr) (0x50 + (nr)) 588c2ecf20Sopenharmony_ci#define LM93_REG_TEMP_MIN(nr) (0x78 + (nr) * 2) 598c2ecf20Sopenharmony_ci#define LM93_REG_TEMP_MAX(nr) (0x79 + (nr) * 2) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* temp[1-4]_auto_boost (nr => 0-3) */ 628c2ecf20Sopenharmony_ci#define LM93_REG_BOOST(nr) (0x80 + (nr)) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */ 658c2ecf20Sopenharmony_ci#define LM93_REG_PROCHOT_CUR(nr) (0x67 + (nr) * 2) 668c2ecf20Sopenharmony_ci#define LM93_REG_PROCHOT_AVG(nr) (0x68 + (nr) * 2) 678c2ecf20Sopenharmony_ci#define LM93_REG_PROCHOT_MAX(nr) (0xb0 + (nr)) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* fan tach inputs: fan1-fan4 (nr => 0-3) */ 708c2ecf20Sopenharmony_ci#define LM93_REG_FAN(nr) (0x6e + (nr) * 2) 718c2ecf20Sopenharmony_ci#define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */ 748c2ecf20Sopenharmony_ci#define LM93_REG_PWM_CTL(nr, reg) (0xc8 + (reg) + (nr) * 4) 758c2ecf20Sopenharmony_ci#define LM93_PWM_CTL1 0x0 768c2ecf20Sopenharmony_ci#define LM93_PWM_CTL2 0x1 778c2ecf20Sopenharmony_ci#define LM93_PWM_CTL3 0x2 788c2ecf20Sopenharmony_ci#define LM93_PWM_CTL4 0x3 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* GPIO input state */ 818c2ecf20Sopenharmony_ci#define LM93_REG_GPI 0x6b 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* vid inputs: vid1-vid2 (nr => 0-1) */ 848c2ecf20Sopenharmony_ci#define LM93_REG_VID(nr) (0x6c + (nr)) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */ 878c2ecf20Sopenharmony_ci#define LM93_REG_VCCP_LIMIT_OFF(nr) (0xb2 + (nr)) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* temp[1-4]_auto_boost_hyst */ 908c2ecf20Sopenharmony_ci#define LM93_REG_BOOST_HYST_12 0xc0 918c2ecf20Sopenharmony_ci#define LM93_REG_BOOST_HYST_34 0xc1 928c2ecf20Sopenharmony_ci#define LM93_REG_BOOST_HYST(nr) (0xc0 + (nr)/2) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* temp[1-4]_auto_pwm_[min|hyst] */ 958c2ecf20Sopenharmony_ci#define LM93_REG_PWM_MIN_HYST_12 0xc3 968c2ecf20Sopenharmony_ci#define LM93_REG_PWM_MIN_HYST_34 0xc4 978c2ecf20Sopenharmony_ci#define LM93_REG_PWM_MIN_HYST(nr) (0xc3 + (nr)/2) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* prochot_override & prochot_interval */ 1008c2ecf20Sopenharmony_ci#define LM93_REG_PROCHOT_OVERRIDE 0xc6 1018c2ecf20Sopenharmony_ci#define LM93_REG_PROCHOT_INTERVAL 0xc7 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* temp[1-4]_auto_base (nr => 0-3) */ 1048c2ecf20Sopenharmony_ci#define LM93_REG_TEMP_BASE(nr) (0xd0 + (nr)) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* temp[1-4]_auto_offsets (step => 0-11) */ 1078c2ecf20Sopenharmony_ci#define LM93_REG_TEMP_OFFSET(step) (0xd4 + (step)) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* #PROCHOT & #VRDHOT PWM ramp control */ 1108c2ecf20Sopenharmony_ci#define LM93_REG_PWM_RAMP_CTL 0xbf 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* miscellaneous */ 1138c2ecf20Sopenharmony_ci#define LM93_REG_SFC1 0xbc 1148c2ecf20Sopenharmony_ci#define LM93_REG_SFC2 0xbd 1158c2ecf20Sopenharmony_ci#define LM93_REG_GPI_VID_CTL 0xbe 1168c2ecf20Sopenharmony_ci#define LM93_REG_SF_TACH_TO_PWM 0xe0 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* error masks */ 1198c2ecf20Sopenharmony_ci#define LM93_REG_GPI_ERR_MASK 0xec 1208c2ecf20Sopenharmony_ci#define LM93_REG_MISC_ERR_MASK 0xed 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* LM93 REGISTER VALUES */ 1238c2ecf20Sopenharmony_ci#define LM93_MFR_ID 0x73 1248c2ecf20Sopenharmony_ci#define LM93_MFR_ID_PROTOTYPE 0x72 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci/* LM94 REGISTER VALUES */ 1278c2ecf20Sopenharmony_ci#define LM94_MFR_ID_2 0x7a 1288c2ecf20Sopenharmony_ci#define LM94_MFR_ID 0x79 1298c2ecf20Sopenharmony_ci#define LM94_MFR_ID_PROTOTYPE 0x78 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/* SMBus capabilities */ 1328c2ecf20Sopenharmony_ci#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \ 1338c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA) 1348c2ecf20Sopenharmony_ci#define LM93_SMBUS_FUNC_MIN (I2C_FUNC_SMBUS_BYTE_DATA | \ 1358c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_WORD_DATA) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Addresses to scan */ 1388c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* Insmod parameters */ 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic bool disable_block; 1438c2ecf20Sopenharmony_cimodule_param(disable_block, bool, 0); 1448c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_block, 1458c2ecf20Sopenharmony_ci "Set to non-zero to disable SMBus block data transactions."); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic bool init; 1488c2ecf20Sopenharmony_cimodule_param(init, bool, 0); 1498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(init, "Set to non-zero to force chip initialization."); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int vccp_limit_type[2] = {0, 0}; 1528c2ecf20Sopenharmony_cimodule_param_array(vccp_limit_type, int, NULL, 0); 1538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes."); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int vid_agtl; 1568c2ecf20Sopenharmony_cimodule_param(vid_agtl, int, 0); 1578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds."); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* Driver data */ 1608c2ecf20Sopenharmony_cistatic struct i2c_driver lm93_driver; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* LM93 BLOCK READ COMMANDS */ 1638c2ecf20Sopenharmony_cistatic const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = { 1648c2ecf20Sopenharmony_ci { 0xf2, 8 }, 1658c2ecf20Sopenharmony_ci { 0xf3, 8 }, 1668c2ecf20Sopenharmony_ci { 0xf4, 6 }, 1678c2ecf20Sopenharmony_ci { 0xf5, 16 }, 1688c2ecf20Sopenharmony_ci { 0xf6, 4 }, 1698c2ecf20Sopenharmony_ci { 0xf7, 8 }, 1708c2ecf20Sopenharmony_ci { 0xf8, 12 }, 1718c2ecf20Sopenharmony_ci { 0xf9, 32 }, 1728c2ecf20Sopenharmony_ci { 0xfa, 8 }, 1738c2ecf20Sopenharmony_ci { 0xfb, 8 }, 1748c2ecf20Sopenharmony_ci { 0xfc, 16 }, 1758c2ecf20Sopenharmony_ci { 0xfd, 9 }, 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* 1798c2ecf20Sopenharmony_ci * ALARMS: SYSCTL format described further below 1808c2ecf20Sopenharmony_ci * REG: 64 bits in 8 registers, as immediately below 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_cistruct block1_t { 1838c2ecf20Sopenharmony_ci u8 host_status_1; 1848c2ecf20Sopenharmony_ci u8 host_status_2; 1858c2ecf20Sopenharmony_ci u8 host_status_3; 1868c2ecf20Sopenharmony_ci u8 host_status_4; 1878c2ecf20Sopenharmony_ci u8 p1_prochot_status; 1888c2ecf20Sopenharmony_ci u8 p2_prochot_status; 1898c2ecf20Sopenharmony_ci u8 gpi_status; 1908c2ecf20Sopenharmony_ci u8 fan_status; 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * Client-specific data 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_cistruct lm93_data { 1978c2ecf20Sopenharmony_ci struct i2c_client *client; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci struct mutex update_lock; 2008c2ecf20Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* client update function */ 2038c2ecf20Sopenharmony_ci void (*update)(struct lm93_data *, struct i2c_client *); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci char valid; /* !=0 if following fields are valid */ 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* register values, arranged by block read groups */ 2088c2ecf20Sopenharmony_ci struct block1_t block1; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* 2118c2ecf20Sopenharmony_ci * temp1 - temp4: unfiltered readings 2128c2ecf20Sopenharmony_ci * temp1 - temp2: filtered readings 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_ci u8 block2[6]; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* vin1 - vin16: readings */ 2178c2ecf20Sopenharmony_ci u8 block3[16]; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* prochot1 - prochot2: readings */ 2208c2ecf20Sopenharmony_ci struct { 2218c2ecf20Sopenharmony_ci u8 cur; 2228c2ecf20Sopenharmony_ci u8 avg; 2238c2ecf20Sopenharmony_ci } block4[2]; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* fan counts 1-4 => 14-bits, LE, *left* justified */ 2268c2ecf20Sopenharmony_ci u16 block5[4]; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* block6 has a lot of data we don't need */ 2298c2ecf20Sopenharmony_ci struct { 2308c2ecf20Sopenharmony_ci u8 min; 2318c2ecf20Sopenharmony_ci u8 max; 2328c2ecf20Sopenharmony_ci } temp_lim[4]; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* vin1 - vin16: low and high limits */ 2358c2ecf20Sopenharmony_ci struct { 2368c2ecf20Sopenharmony_ci u8 min; 2378c2ecf20Sopenharmony_ci u8 max; 2388c2ecf20Sopenharmony_ci } block7[16]; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* fan count limits 1-4 => same format as block5 */ 2418c2ecf20Sopenharmony_ci u16 block8[4]; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* pwm control registers (2 pwms, 4 regs) */ 2448c2ecf20Sopenharmony_ci u8 block9[2][4]; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* auto/pwm base temp and offset temp registers */ 2478c2ecf20Sopenharmony_ci struct { 2488c2ecf20Sopenharmony_ci u8 base[4]; 2498c2ecf20Sopenharmony_ci u8 offset[12]; 2508c2ecf20Sopenharmony_ci } block10; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* master config register */ 2538c2ecf20Sopenharmony_ci u8 config; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci /* VID1 & VID2 => register format, 6-bits, right justified */ 2568c2ecf20Sopenharmony_ci u8 vid[2]; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* prochot1 - prochot2: limits */ 2598c2ecf20Sopenharmony_ci u8 prochot_max[2]; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */ 2628c2ecf20Sopenharmony_ci u8 vccp_limits[2]; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* GPIO input state (register format, i.e. inverted) */ 2658c2ecf20Sopenharmony_ci u8 gpi; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* #PROCHOT override (register format) */ 2688c2ecf20Sopenharmony_ci u8 prochot_override; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* #PROCHOT intervals (register format) */ 2718c2ecf20Sopenharmony_ci u8 prochot_interval; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Fan Boost Temperatures (register format) */ 2748c2ecf20Sopenharmony_ci u8 boost[4]; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* Fan Boost Hysteresis (register format) */ 2778c2ecf20Sopenharmony_ci u8 boost_hyst[2]; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Temperature Zone Min. PWM & Hysteresis (register format) */ 2808c2ecf20Sopenharmony_ci u8 auto_pwm_min_hyst[2]; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* #PROCHOT & #VRDHOT PWM Ramp Control */ 2838c2ecf20Sopenharmony_ci u8 pwm_ramp_ctl; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* miscellaneous setup regs */ 2868c2ecf20Sopenharmony_ci u8 sfc1; 2878c2ecf20Sopenharmony_ci u8 sfc2; 2888c2ecf20Sopenharmony_ci u8 sf_tach_to_pwm; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* 2918c2ecf20Sopenharmony_ci * The two PWM CTL2 registers can read something other than what was 2928c2ecf20Sopenharmony_ci * last written for the OVR_DC field (duty cycle override). So, we 2938c2ecf20Sopenharmony_ci * save the user-commanded value here. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_ci u8 pwm_override[2]; 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* 2998c2ecf20Sopenharmony_ci * VID: mV 3008c2ecf20Sopenharmony_ci * REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_cistatic int LM93_VID_FROM_REG(u8 reg) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci return vid_from_reg((reg & 0x3f), 100); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* min, max, and nominal register values, per channel (u8) */ 3088c2ecf20Sopenharmony_cistatic const u8 lm93_vin_reg_min[16] = { 3098c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 3108c2ecf20Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 3118c2ecf20Sopenharmony_ci}; 3128c2ecf20Sopenharmony_cistatic const u8 lm93_vin_reg_max[16] = { 3138c2ecf20Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 3148c2ecf20Sopenharmony_ci 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci/* 3178c2ecf20Sopenharmony_ci * Values from the datasheet. They're here for documentation only. 3188c2ecf20Sopenharmony_ci * static const u8 lm93_vin_reg_nom[16] = { 3198c2ecf20Sopenharmony_ci * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 3208c2ecf20Sopenharmony_ci * 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0, 3218c2ecf20Sopenharmony_ci * }; 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* min, max, and nominal voltage readings, per channel (mV)*/ 3258c2ecf20Sopenharmony_cistatic const unsigned long lm93_vin_val_min[16] = { 3268c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 3278c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 3000, 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const unsigned long lm93_vin_val_max[16] = { 3318c2ecf20Sopenharmony_ci 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600, 3328c2ecf20Sopenharmony_ci 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600, 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ci/* 3358c2ecf20Sopenharmony_ci * Values from the datasheet. They're here for documentation only. 3368c2ecf20Sopenharmony_ci * static const unsigned long lm93_vin_val_nom[16] = { 3378c2ecf20Sopenharmony_ci * 927, 927, 927, 1200, 1500, 1500, 1200, 1200, 3388c2ecf20Sopenharmony_ci * 3300, 5000, 2500, 1969, 984, 984, 309, 3300, 3398c2ecf20Sopenharmony_ci * }; 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic unsigned LM93_IN_FROM_REG(int nr, u8 reg) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci const long uv_max = lm93_vin_val_max[nr] * 1000; 3458c2ecf20Sopenharmony_ci const long uv_min = lm93_vin_val_min[nr] * 1000; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci const long slope = (uv_max - uv_min) / 3488c2ecf20Sopenharmony_ci (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); 3498c2ecf20Sopenharmony_ci const long intercept = uv_min - slope * lm93_vin_reg_min[nr]; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return (slope * reg + intercept + 500) / 1000; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * IN: mV, limits determined by channel nr 3568c2ecf20Sopenharmony_ci * REG: scaling determined by channel nr 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_cistatic u8 LM93_IN_TO_REG(int nr, unsigned val) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci /* range limit */ 3618c2ecf20Sopenharmony_ci const long mv = clamp_val(val, 3628c2ecf20Sopenharmony_ci lm93_vin_val_min[nr], lm93_vin_val_max[nr]); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* try not to lose too much precision here */ 3658c2ecf20Sopenharmony_ci const long uv = mv * 1000; 3668c2ecf20Sopenharmony_ci const long uv_max = lm93_vin_val_max[nr] * 1000; 3678c2ecf20Sopenharmony_ci const long uv_min = lm93_vin_val_min[nr] * 1000; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* convert */ 3708c2ecf20Sopenharmony_ci const long slope = (uv_max - uv_min) / 3718c2ecf20Sopenharmony_ci (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]); 3728c2ecf20Sopenharmony_ci const long intercept = uv_min - slope * lm93_vin_reg_min[nr]; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci u8 result = ((uv - intercept + (slope/2)) / slope); 3758c2ecf20Sopenharmony_ci result = clamp_val(result, 3768c2ecf20Sopenharmony_ci lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]); 3778c2ecf20Sopenharmony_ci return result; 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */ 3818c2ecf20Sopenharmony_cistatic unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci const long uv_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) : 3848c2ecf20Sopenharmony_ci (((reg >> 0 & 0x0f) + 1) * -25000); 3858c2ecf20Sopenharmony_ci const long uv_vid = vid * 1000; 3868c2ecf20Sopenharmony_ci return (uv_vid + uv_offset + 5000) / 10000; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci#define LM93_IN_MIN_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 0, (vid)) 3908c2ecf20Sopenharmony_ci#define LM93_IN_MAX_FROM_REG(reg, vid) LM93_IN_REL_FROM_REG((reg), 1, (vid)) 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/* 3938c2ecf20Sopenharmony_ci * vid in mV , upper == 0 indicates low limit, otherwise upper limit 3948c2ecf20Sopenharmony_ci * upper also determines which nibble of the register is returned 3958c2ecf20Sopenharmony_ci * (the other nibble will be 0x0) 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_cistatic u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci long uv_offset = vid * 1000 - val * 10000; 4008c2ecf20Sopenharmony_ci if (upper) { 4018c2ecf20Sopenharmony_ci uv_offset = clamp_val(uv_offset, 12500, 200000); 4028c2ecf20Sopenharmony_ci return (u8)((uv_offset / 12500 - 1) << 4); 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci uv_offset = clamp_val(uv_offset, -400000, -25000); 4058c2ecf20Sopenharmony_ci return (u8)((uv_offset / -25000 - 1) << 0); 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * TEMP: 1/1000 degrees C (-128C to +127C) 4118c2ecf20Sopenharmony_ci * REG: 1C/bit, two's complement 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_cistatic int LM93_TEMP_FROM_REG(u8 reg) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci return (s8)reg * 1000; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci#define LM93_TEMP_MIN (-128000) 4198c2ecf20Sopenharmony_ci#define LM93_TEMP_MAX (127000) 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/* 4228c2ecf20Sopenharmony_ci * TEMP: 1/1000 degrees C (-128C to +127C) 4238c2ecf20Sopenharmony_ci * REG: 1C/bit, two's complement 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_cistatic u8 LM93_TEMP_TO_REG(long temp) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci int ntemp = clamp_val(temp, LM93_TEMP_MIN, LM93_TEMP_MAX); 4288c2ecf20Sopenharmony_ci ntemp += (ntemp < 0 ? -500 : 500); 4298c2ecf20Sopenharmony_ci return (u8)(ntemp / 1000); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci/* Determine 4-bit temperature offset resolution */ 4338c2ecf20Sopenharmony_cistatic int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */ 4368c2ecf20Sopenharmony_ci return sfc2 & (nr < 2 ? 0x10 : 0x20); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/* 4408c2ecf20Sopenharmony_ci * This function is common to all 4-bit temperature offsets 4418c2ecf20Sopenharmony_ci * reg is 4 bits right justified 4428c2ecf20Sopenharmony_ci * mode 0 => 1C/bit, mode !0 => 0.5C/bit 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_cistatic int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci return (reg & 0x0f) * (mode ? 5 : 10); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci#define LM93_TEMP_OFFSET_MIN (0) 4508c2ecf20Sopenharmony_ci#define LM93_TEMP_OFFSET_MAX0 (150) 4518c2ecf20Sopenharmony_ci#define LM93_TEMP_OFFSET_MAX1 (75) 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci/* 4548c2ecf20Sopenharmony_ci * This function is common to all 4-bit temperature offsets 4558c2ecf20Sopenharmony_ci * returns 4 bits right justified 4568c2ecf20Sopenharmony_ci * mode 0 => 1C/bit, mode !0 => 0.5C/bit 4578c2ecf20Sopenharmony_ci */ 4588c2ecf20Sopenharmony_cistatic u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci int factor = mode ? 5 : 10; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci off = clamp_val(off, LM93_TEMP_OFFSET_MIN, 4638c2ecf20Sopenharmony_ci mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0); 4648c2ecf20Sopenharmony_ci return (u8)((off + factor/2) / factor); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci/* 0 <= nr <= 3 */ 4688c2ecf20Sopenharmony_cistatic int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci /* temp1-temp2 (nr=0,1) use lower nibble */ 4718c2ecf20Sopenharmony_ci if (nr < 2) 4728c2ecf20Sopenharmony_ci return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* temp3-temp4 (nr=2,3) use upper nibble */ 4758c2ecf20Sopenharmony_ci else 4768c2ecf20Sopenharmony_ci return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode); 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci/* 4808c2ecf20Sopenharmony_ci * TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero)) 4818c2ecf20Sopenharmony_ci * REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero) 4828c2ecf20Sopenharmony_ci * 0 <= nr <= 3 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_cistatic u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* temp1-temp2 (nr=0,1) use lower nibble */ 4898c2ecf20Sopenharmony_ci if (nr < 2) 4908c2ecf20Sopenharmony_ci return (old & 0xf0) | (new & 0x0f); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* temp3-temp4 (nr=2,3) use upper nibble */ 4938c2ecf20Sopenharmony_ci else 4948c2ecf20Sopenharmony_ci return (new << 4 & 0xf0) | (old & 0x0f); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr, 4988c2ecf20Sopenharmony_ci int mode) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci u8 reg; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci switch (nr) { 5038c2ecf20Sopenharmony_ci case 0: 5048c2ecf20Sopenharmony_ci reg = data->boost_hyst[0] & 0x0f; 5058c2ecf20Sopenharmony_ci break; 5068c2ecf20Sopenharmony_ci case 1: 5078c2ecf20Sopenharmony_ci reg = data->boost_hyst[0] >> 4 & 0x0f; 5088c2ecf20Sopenharmony_ci break; 5098c2ecf20Sopenharmony_ci case 2: 5108c2ecf20Sopenharmony_ci reg = data->boost_hyst[1] & 0x0f; 5118c2ecf20Sopenharmony_ci break; 5128c2ecf20Sopenharmony_ci case 3: 5138c2ecf20Sopenharmony_ci default: 5148c2ecf20Sopenharmony_ci reg = data->boost_hyst[1] >> 4 & 0x0f; 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci return LM93_TEMP_FROM_REG(data->boost[nr]) - 5198c2ecf20Sopenharmony_ci LM93_TEMP_OFFSET_FROM_REG(reg, mode); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst, 5238c2ecf20Sopenharmony_ci int nr, int mode) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci u8 reg = LM93_TEMP_OFFSET_TO_REG( 5268c2ecf20Sopenharmony_ci (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci switch (nr) { 5298c2ecf20Sopenharmony_ci case 0: 5308c2ecf20Sopenharmony_ci reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f); 5318c2ecf20Sopenharmony_ci break; 5328c2ecf20Sopenharmony_ci case 1: 5338c2ecf20Sopenharmony_ci reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f); 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci case 2: 5368c2ecf20Sopenharmony_ci reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci case 3: 5398c2ecf20Sopenharmony_ci default: 5408c2ecf20Sopenharmony_ci reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return reg; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci/* 5488c2ecf20Sopenharmony_ci * PWM: 0-255 per sensors documentation 5498c2ecf20Sopenharmony_ci * REG: 0-13 as mapped below... right justified 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_cienum pwm_freq { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ }; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic int lm93_pwm_map[2][16] = { 5548c2ecf20Sopenharmony_ci { 5558c2ecf20Sopenharmony_ci 0x00, /* 0.00% */ 0x40, /* 25.00% */ 5568c2ecf20Sopenharmony_ci 0x50, /* 31.25% */ 0x60, /* 37.50% */ 5578c2ecf20Sopenharmony_ci 0x70, /* 43.75% */ 0x80, /* 50.00% */ 5588c2ecf20Sopenharmony_ci 0x90, /* 56.25% */ 0xa0, /* 62.50% */ 5598c2ecf20Sopenharmony_ci 0xb0, /* 68.75% */ 0xc0, /* 75.00% */ 5608c2ecf20Sopenharmony_ci 0xd0, /* 81.25% */ 0xe0, /* 87.50% */ 5618c2ecf20Sopenharmony_ci 0xf0, /* 93.75% */ 0xff, /* 100.00% */ 5628c2ecf20Sopenharmony_ci 0xff, 0xff, /* 14, 15 are reserved and should never occur */ 5638c2ecf20Sopenharmony_ci }, 5648c2ecf20Sopenharmony_ci { 5658c2ecf20Sopenharmony_ci 0x00, /* 0.00% */ 0x40, /* 25.00% */ 5668c2ecf20Sopenharmony_ci 0x49, /* 28.57% */ 0x52, /* 32.14% */ 5678c2ecf20Sopenharmony_ci 0x5b, /* 35.71% */ 0x64, /* 39.29% */ 5688c2ecf20Sopenharmony_ci 0x6d, /* 42.86% */ 0x76, /* 46.43% */ 5698c2ecf20Sopenharmony_ci 0x80, /* 50.00% */ 0x89, /* 53.57% */ 5708c2ecf20Sopenharmony_ci 0x92, /* 57.14% */ 0xb6, /* 71.43% */ 5718c2ecf20Sopenharmony_ci 0xdb, /* 85.71% */ 0xff, /* 100.00% */ 5728c2ecf20Sopenharmony_ci 0xff, 0xff, /* 14, 15 are reserved and should never occur */ 5738c2ecf20Sopenharmony_ci }, 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int LM93_PWM_FROM_REG(u8 reg, enum pwm_freq freq) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci return lm93_pwm_map[freq][reg & 0x0f]; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/* round up to nearest match */ 5828c2ecf20Sopenharmony_cistatic u8 LM93_PWM_TO_REG(int pwm, enum pwm_freq freq) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci int i; 5858c2ecf20Sopenharmony_ci for (i = 0; i < 13; i++) 5868c2ecf20Sopenharmony_ci if (pwm <= lm93_pwm_map[freq][i]) 5878c2ecf20Sopenharmony_ci break; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* can fall through with i==13 */ 5908c2ecf20Sopenharmony_ci return (u8)i; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int LM93_FAN_FROM_REG(u16 regs) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci const u16 count = le16_to_cpu(regs) >> 2; 5968c2ecf20Sopenharmony_ci return count == 0 ? -1 : count == 0x3fff ? 0 : 1350000 / count; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci/* 6008c2ecf20Sopenharmony_ci * RPM: (82.5 to 1350000) 6018c2ecf20Sopenharmony_ci * REG: 14-bits, LE, *left* justified 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_cistatic u16 LM93_FAN_TO_REG(long rpm) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci u16 count, regs; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (rpm == 0) { 6088c2ecf20Sopenharmony_ci count = 0x3fff; 6098c2ecf20Sopenharmony_ci } else { 6108c2ecf20Sopenharmony_ci rpm = clamp_val(rpm, 1, 1000000); 6118c2ecf20Sopenharmony_ci count = clamp_val((1350000 + rpm) / rpm, 1, 0x3ffe); 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci regs = count << 2; 6158c2ecf20Sopenharmony_ci return cpu_to_le16(regs); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* 6198c2ecf20Sopenharmony_ci * PWM FREQ: HZ 6208c2ecf20Sopenharmony_ci * REG: 0-7 as mapped below 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistatic int lm93_pwm_freq_map[8] = { 6238c2ecf20Sopenharmony_ci 22500, 96, 84, 72, 60, 48, 36, 12 6248c2ecf20Sopenharmony_ci}; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int LM93_PWM_FREQ_FROM_REG(u8 reg) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci return lm93_pwm_freq_map[reg & 0x07]; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci/* round up to nearest match */ 6328c2ecf20Sopenharmony_cistatic u8 LM93_PWM_FREQ_TO_REG(int freq) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci int i; 6358c2ecf20Sopenharmony_ci for (i = 7; i > 0; i--) 6368c2ecf20Sopenharmony_ci if (freq <= lm93_pwm_freq_map[i]) 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* can fall through with i==0 */ 6408c2ecf20Sopenharmony_ci return (u8)i; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/* 6448c2ecf20Sopenharmony_ci * TIME: 1/100 seconds 6458c2ecf20Sopenharmony_ci * REG: 0-7 as mapped below 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic int lm93_spinup_time_map[8] = { 6488c2ecf20Sopenharmony_ci 0, 10, 25, 40, 70, 100, 200, 400, 6498c2ecf20Sopenharmony_ci}; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic int LM93_SPINUP_TIME_FROM_REG(u8 reg) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci return lm93_spinup_time_map[reg >> 5 & 0x07]; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/* round up to nearest match */ 6578c2ecf20Sopenharmony_cistatic u8 LM93_SPINUP_TIME_TO_REG(int time) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci int i; 6608c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) 6618c2ecf20Sopenharmony_ci if (time <= lm93_spinup_time_map[i]) 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* can fall through with i==8 */ 6658c2ecf20Sopenharmony_ci return (u8)i; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci#define LM93_RAMP_MIN 0 6698c2ecf20Sopenharmony_ci#define LM93_RAMP_MAX 75 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int LM93_RAMP_FROM_REG(u8 reg) 6728c2ecf20Sopenharmony_ci{ 6738c2ecf20Sopenharmony_ci return (reg & 0x0f) * 5; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/* 6778c2ecf20Sopenharmony_ci * RAMP: 1/100 seconds 6788c2ecf20Sopenharmony_ci * REG: 50mS/bit 4-bits right justified 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_cistatic u8 LM93_RAMP_TO_REG(int ramp) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci ramp = clamp_val(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX); 6838c2ecf20Sopenharmony_ci return (u8)((ramp + 2) / 5); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/* 6878c2ecf20Sopenharmony_ci * PROCHOT: 0-255, 0 => 0%, 255 => > 96.6% 6888c2ecf20Sopenharmony_ci * REG: (same) 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_cistatic u8 LM93_PROCHOT_TO_REG(long prochot) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci prochot = clamp_val(prochot, 0, 255); 6938c2ecf20Sopenharmony_ci return (u8)prochot; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* 6978c2ecf20Sopenharmony_ci * PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds) 6988c2ecf20Sopenharmony_ci * REG: 0-9 as mapped below 6998c2ecf20Sopenharmony_ci */ 7008c2ecf20Sopenharmony_cistatic int lm93_interval_map[10] = { 7018c2ecf20Sopenharmony_ci 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200, 7028c2ecf20Sopenharmony_ci}; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int LM93_INTERVAL_FROM_REG(u8 reg) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci return lm93_interval_map[reg & 0x0f]; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci/* round up to nearest match */ 7108c2ecf20Sopenharmony_cistatic u8 LM93_INTERVAL_TO_REG(long interval) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci int i; 7138c2ecf20Sopenharmony_ci for (i = 0; i < 9; i++) 7148c2ecf20Sopenharmony_ci if (interval <= lm93_interval_map[i]) 7158c2ecf20Sopenharmony_ci break; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* can fall through with i==9 */ 7188c2ecf20Sopenharmony_ci return (u8)i; 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci/* 7228c2ecf20Sopenharmony_ci * GPIO: 0-255, GPIO0 is LSB 7238c2ecf20Sopenharmony_ci * REG: inverted 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_cistatic unsigned LM93_GPI_FROM_REG(u8 reg) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci return ~reg & 0xff; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci/* 7318c2ecf20Sopenharmony_ci * alarm bitmask definitions 7328c2ecf20Sopenharmony_ci * The LM93 has nearly 64 bits of error status... I've pared that down to 7338c2ecf20Sopenharmony_ci * what I think is a useful subset in order to fit it into 32 bits. 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * Especially note that the #VRD_HOT alarms are missing because we provide 7368c2ecf20Sopenharmony_ci * that information as values in another sysfs file. 7378c2ecf20Sopenharmony_ci * 7388c2ecf20Sopenharmony_ci * If libsensors is extended to support 64 bit values, this could be revisited. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci#define LM93_ALARM_IN1 0x00000001 7418c2ecf20Sopenharmony_ci#define LM93_ALARM_IN2 0x00000002 7428c2ecf20Sopenharmony_ci#define LM93_ALARM_IN3 0x00000004 7438c2ecf20Sopenharmony_ci#define LM93_ALARM_IN4 0x00000008 7448c2ecf20Sopenharmony_ci#define LM93_ALARM_IN5 0x00000010 7458c2ecf20Sopenharmony_ci#define LM93_ALARM_IN6 0x00000020 7468c2ecf20Sopenharmony_ci#define LM93_ALARM_IN7 0x00000040 7478c2ecf20Sopenharmony_ci#define LM93_ALARM_IN8 0x00000080 7488c2ecf20Sopenharmony_ci#define LM93_ALARM_IN9 0x00000100 7498c2ecf20Sopenharmony_ci#define LM93_ALARM_IN10 0x00000200 7508c2ecf20Sopenharmony_ci#define LM93_ALARM_IN11 0x00000400 7518c2ecf20Sopenharmony_ci#define LM93_ALARM_IN12 0x00000800 7528c2ecf20Sopenharmony_ci#define LM93_ALARM_IN13 0x00001000 7538c2ecf20Sopenharmony_ci#define LM93_ALARM_IN14 0x00002000 7548c2ecf20Sopenharmony_ci#define LM93_ALARM_IN15 0x00004000 7558c2ecf20Sopenharmony_ci#define LM93_ALARM_IN16 0x00008000 7568c2ecf20Sopenharmony_ci#define LM93_ALARM_FAN1 0x00010000 7578c2ecf20Sopenharmony_ci#define LM93_ALARM_FAN2 0x00020000 7588c2ecf20Sopenharmony_ci#define LM93_ALARM_FAN3 0x00040000 7598c2ecf20Sopenharmony_ci#define LM93_ALARM_FAN4 0x00080000 7608c2ecf20Sopenharmony_ci#define LM93_ALARM_PH1_ERR 0x00100000 7618c2ecf20Sopenharmony_ci#define LM93_ALARM_PH2_ERR 0x00200000 7628c2ecf20Sopenharmony_ci#define LM93_ALARM_SCSI1_ERR 0x00400000 7638c2ecf20Sopenharmony_ci#define LM93_ALARM_SCSI2_ERR 0x00800000 7648c2ecf20Sopenharmony_ci#define LM93_ALARM_DVDDP1_ERR 0x01000000 7658c2ecf20Sopenharmony_ci#define LM93_ALARM_DVDDP2_ERR 0x02000000 7668c2ecf20Sopenharmony_ci#define LM93_ALARM_D1_ERR 0x04000000 7678c2ecf20Sopenharmony_ci#define LM93_ALARM_D2_ERR 0x08000000 7688c2ecf20Sopenharmony_ci#define LM93_ALARM_TEMP1 0x10000000 7698c2ecf20Sopenharmony_ci#define LM93_ALARM_TEMP2 0x20000000 7708c2ecf20Sopenharmony_ci#define LM93_ALARM_TEMP3 0x40000000 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_cistatic unsigned LM93_ALARMS_FROM_REG(struct block1_t b1) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci unsigned result; 7758c2ecf20Sopenharmony_ci result = b1.host_status_2 & 0x3f; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (vccp_limit_type[0]) 7788c2ecf20Sopenharmony_ci result |= (b1.host_status_4 & 0x10) << 2; 7798c2ecf20Sopenharmony_ci else 7808c2ecf20Sopenharmony_ci result |= b1.host_status_2 & 0x40; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (vccp_limit_type[1]) 7838c2ecf20Sopenharmony_ci result |= (b1.host_status_4 & 0x20) << 2; 7848c2ecf20Sopenharmony_ci else 7858c2ecf20Sopenharmony_ci result |= b1.host_status_2 & 0x80; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci result |= b1.host_status_3 << 8; 7888c2ecf20Sopenharmony_ci result |= (b1.fan_status & 0x0f) << 16; 7898c2ecf20Sopenharmony_ci result |= (b1.p1_prochot_status & 0x80) << 13; 7908c2ecf20Sopenharmony_ci result |= (b1.p2_prochot_status & 0x80) << 14; 7918c2ecf20Sopenharmony_ci result |= (b1.host_status_4 & 0xfc) << 20; 7928c2ecf20Sopenharmony_ci result |= (b1.host_status_1 & 0x07) << 28; 7938c2ecf20Sopenharmony_ci return result; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci#define MAX_RETRIES 5 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic u8 lm93_read_byte(struct i2c_client *client, u8 reg) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci int value, i; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci /* retry in case of read errors */ 8038c2ecf20Sopenharmony_ci for (i = 1; i <= MAX_RETRIES; i++) { 8048c2ecf20Sopenharmony_ci value = i2c_smbus_read_byte_data(client, reg); 8058c2ecf20Sopenharmony_ci if (value >= 0) { 8068c2ecf20Sopenharmony_ci return value; 8078c2ecf20Sopenharmony_ci } else { 8088c2ecf20Sopenharmony_ci dev_warn(&client->dev, 8098c2ecf20Sopenharmony_ci "lm93: read byte data failed, address 0x%02x.\n", 8108c2ecf20Sopenharmony_ci reg); 8118c2ecf20Sopenharmony_ci mdelay(i + 3); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci /* <TODO> what to return in case of error? */ 8178c2ecf20Sopenharmony_ci dev_err(&client->dev, "lm93: All read byte retries failed!!\n"); 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci int result; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* <TODO> how to handle write errors? */ 8268c2ecf20Sopenharmony_ci result = i2c_smbus_write_byte_data(client, reg, value); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (result < 0) 8298c2ecf20Sopenharmony_ci dev_warn(&client->dev, 8308c2ecf20Sopenharmony_ci "lm93: write byte data failed, 0x%02x at address 0x%02x.\n", 8318c2ecf20Sopenharmony_ci value, reg); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return result; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic u16 lm93_read_word(struct i2c_client *client, u8 reg) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci int value, i; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* retry in case of read errors */ 8418c2ecf20Sopenharmony_ci for (i = 1; i <= MAX_RETRIES; i++) { 8428c2ecf20Sopenharmony_ci value = i2c_smbus_read_word_data(client, reg); 8438c2ecf20Sopenharmony_ci if (value >= 0) { 8448c2ecf20Sopenharmony_ci return value; 8458c2ecf20Sopenharmony_ci } else { 8468c2ecf20Sopenharmony_ci dev_warn(&client->dev, 8478c2ecf20Sopenharmony_ci "lm93: read word data failed, address 0x%02x.\n", 8488c2ecf20Sopenharmony_ci reg); 8498c2ecf20Sopenharmony_ci mdelay(i + 3); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* <TODO> what to return in case of error? */ 8558c2ecf20Sopenharmony_ci dev_err(&client->dev, "lm93: All read word retries failed!!\n"); 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int lm93_write_word(struct i2c_client *client, u8 reg, u16 value) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci int result; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* <TODO> how to handle write errors? */ 8648c2ecf20Sopenharmony_ci result = i2c_smbus_write_word_data(client, reg, value); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (result < 0) 8678c2ecf20Sopenharmony_ci dev_warn(&client->dev, 8688c2ecf20Sopenharmony_ci "lm93: write word data failed, 0x%04x at address 0x%02x.\n", 8698c2ecf20Sopenharmony_ci value, reg); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return result; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX]; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/* 8778c2ecf20Sopenharmony_ci * read block data into values, retry if not expected length 8788c2ecf20Sopenharmony_ci * fbn => index to lm93_block_read_cmds table 8798c2ecf20Sopenharmony_ci * (Fixed Block Number - section 14.5.2 of LM93 datasheet) 8808c2ecf20Sopenharmony_ci */ 8818c2ecf20Sopenharmony_cistatic void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci int i, result = 0; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci for (i = 1; i <= MAX_RETRIES; i++) { 8868c2ecf20Sopenharmony_ci result = i2c_smbus_read_block_data(client, 8878c2ecf20Sopenharmony_ci lm93_block_read_cmds[fbn].cmd, lm93_block_buffer); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (result == lm93_block_read_cmds[fbn].len) { 8908c2ecf20Sopenharmony_ci break; 8918c2ecf20Sopenharmony_ci } else { 8928c2ecf20Sopenharmony_ci dev_warn(&client->dev, 8938c2ecf20Sopenharmony_ci "lm93: block read data failed, command 0x%02x.\n", 8948c2ecf20Sopenharmony_ci lm93_block_read_cmds[fbn].cmd); 8958c2ecf20Sopenharmony_ci mdelay(i + 3); 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci } 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (result == lm93_block_read_cmds[fbn].len) { 9008c2ecf20Sopenharmony_ci memcpy(values, lm93_block_buffer, 9018c2ecf20Sopenharmony_ci lm93_block_read_cmds[fbn].len); 9028c2ecf20Sopenharmony_ci } else { 9038c2ecf20Sopenharmony_ci /* <TODO> what to do in case of error? */ 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic struct lm93_data *lm93_update_device(struct device *dev) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 9108c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 9118c2ecf20Sopenharmony_ci const unsigned long interval = HZ + (HZ / 2); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_updated + interval) || 9168c2ecf20Sopenharmony_ci !data->valid) { 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci data->update(data, client); 9198c2ecf20Sopenharmony_ci data->last_updated = jiffies; 9208c2ecf20Sopenharmony_ci data->valid = 1; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 9248c2ecf20Sopenharmony_ci return data; 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci/* update routine for data that has no corresponding SMBus block command */ 9288c2ecf20Sopenharmony_cistatic void lm93_update_client_common(struct lm93_data *data, 9298c2ecf20Sopenharmony_ci struct i2c_client *client) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci int i; 9328c2ecf20Sopenharmony_ci u8 *ptr; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* temp1 - temp4: limits */ 9358c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 9368c2ecf20Sopenharmony_ci data->temp_lim[i].min = 9378c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_TEMP_MIN(i)); 9388c2ecf20Sopenharmony_ci data->temp_lim[i].max = 9398c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_TEMP_MAX(i)); 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci /* config register */ 9438c2ecf20Sopenharmony_ci data->config = lm93_read_byte(client, LM93_REG_CONFIG); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci /* vid1 - vid2: values */ 9468c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 9478c2ecf20Sopenharmony_ci data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i)); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci /* prochot1 - prochot2: limits */ 9508c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 9518c2ecf20Sopenharmony_ci data->prochot_max[i] = lm93_read_byte(client, 9528c2ecf20Sopenharmony_ci LM93_REG_PROCHOT_MAX(i)); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* vccp1 - vccp2: VID relative limits */ 9558c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) 9568c2ecf20Sopenharmony_ci data->vccp_limits[i] = lm93_read_byte(client, 9578c2ecf20Sopenharmony_ci LM93_REG_VCCP_LIMIT_OFF(i)); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci /* GPIO input state */ 9608c2ecf20Sopenharmony_ci data->gpi = lm93_read_byte(client, LM93_REG_GPI); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* #PROCHOT override state */ 9638c2ecf20Sopenharmony_ci data->prochot_override = lm93_read_byte(client, 9648c2ecf20Sopenharmony_ci LM93_REG_PROCHOT_OVERRIDE); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* #PROCHOT intervals */ 9678c2ecf20Sopenharmony_ci data->prochot_interval = lm93_read_byte(client, 9688c2ecf20Sopenharmony_ci LM93_REG_PROCHOT_INTERVAL); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* Fan Boost Temperature registers */ 9718c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 9728c2ecf20Sopenharmony_ci data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i)); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Fan Boost Temperature Hyst. registers */ 9758c2ecf20Sopenharmony_ci data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12); 9768c2ecf20Sopenharmony_ci data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* Temperature Zone Min. PWM & Hysteresis registers */ 9798c2ecf20Sopenharmony_ci data->auto_pwm_min_hyst[0] = 9808c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12); 9818c2ecf20Sopenharmony_ci data->auto_pwm_min_hyst[1] = 9828c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* #PROCHOT & #VRDHOT PWM Ramp Control register */ 9858c2ecf20Sopenharmony_ci data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* misc setup registers */ 9888c2ecf20Sopenharmony_ci data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1); 9898c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 9908c2ecf20Sopenharmony_ci data->sf_tach_to_pwm = lm93_read_byte(client, 9918c2ecf20Sopenharmony_ci LM93_REG_SF_TACH_TO_PWM); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci /* write back alarm values to clear */ 9948c2ecf20Sopenharmony_ci for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) 9958c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i)); 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci/* update routine which uses SMBus block data commands */ 9998c2ecf20Sopenharmony_cistatic void lm93_update_client_full(struct lm93_data *data, 10008c2ecf20Sopenharmony_ci struct i2c_client *client) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "starting device update (block data enabled)\n"); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* in1 - in16: values & limits */ 10058c2ecf20Sopenharmony_ci lm93_read_block(client, 3, (u8 *)(data->block3)); 10068c2ecf20Sopenharmony_ci lm93_read_block(client, 7, (u8 *)(data->block7)); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci /* temp1 - temp4: values */ 10098c2ecf20Sopenharmony_ci lm93_read_block(client, 2, (u8 *)(data->block2)); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci /* prochot1 - prochot2: values */ 10128c2ecf20Sopenharmony_ci lm93_read_block(client, 4, (u8 *)(data->block4)); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* fan1 - fan4: values & limits */ 10158c2ecf20Sopenharmony_ci lm93_read_block(client, 5, (u8 *)(data->block5)); 10168c2ecf20Sopenharmony_ci lm93_read_block(client, 8, (u8 *)(data->block8)); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* pmw control registers */ 10198c2ecf20Sopenharmony_ci lm93_read_block(client, 9, (u8 *)(data->block9)); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* alarm values */ 10228c2ecf20Sopenharmony_ci lm93_read_block(client, 1, (u8 *)(&data->block1)); 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* auto/pwm registers */ 10258c2ecf20Sopenharmony_ci lm93_read_block(client, 10, (u8 *)(&data->block10)); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci lm93_update_client_common(data, client); 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci/* update routine which uses SMBus byte/word data commands only */ 10318c2ecf20Sopenharmony_cistatic void lm93_update_client_min(struct lm93_data *data, 10328c2ecf20Sopenharmony_ci struct i2c_client *client) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci int i, j; 10358c2ecf20Sopenharmony_ci u8 *ptr; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "starting device update (block data disabled)\n"); 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci /* in1 - in16: values & limits */ 10408c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 10418c2ecf20Sopenharmony_ci data->block3[i] = 10428c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_IN(i)); 10438c2ecf20Sopenharmony_ci data->block7[i].min = 10448c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_IN_MIN(i)); 10458c2ecf20Sopenharmony_ci data->block7[i].max = 10468c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_IN_MAX(i)); 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci /* temp1 - temp4: values */ 10508c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10518c2ecf20Sopenharmony_ci data->block2[i] = 10528c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_TEMP(i)); 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci /* prochot1 - prochot2: values */ 10568c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 10578c2ecf20Sopenharmony_ci data->block4[i].cur = 10588c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i)); 10598c2ecf20Sopenharmony_ci data->block4[i].avg = 10608c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i)); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* fan1 - fan4: values & limits */ 10648c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10658c2ecf20Sopenharmony_ci data->block5[i] = 10668c2ecf20Sopenharmony_ci lm93_read_word(client, LM93_REG_FAN(i)); 10678c2ecf20Sopenharmony_ci data->block8[i] = 10688c2ecf20Sopenharmony_ci lm93_read_word(client, LM93_REG_FAN_MIN(i)); 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* pwm control registers */ 10728c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 10738c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 10748c2ecf20Sopenharmony_ci data->block9[i][j] = 10758c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_PWM_CTL(i, j)); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* alarm values */ 10808c2ecf20Sopenharmony_ci for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) { 10818c2ecf20Sopenharmony_ci *(ptr + i) = 10828c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i); 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* auto/pwm (base temp) registers */ 10868c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10878c2ecf20Sopenharmony_ci data->block10.base[i] = 10888c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_TEMP_BASE(i)); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci /* auto/pwm (offset temp) registers */ 10928c2ecf20Sopenharmony_ci for (i = 0; i < 12; i++) { 10938c2ecf20Sopenharmony_ci data->block10.offset[i] = 10948c2ecf20Sopenharmony_ci lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i)); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci lm93_update_client_common(data, client); 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci/* following are the sysfs callback functions */ 11018c2ecf20Sopenharmony_cistatic ssize_t in_show(struct device *dev, struct device_attribute *attr, 11028c2ecf20Sopenharmony_ci char *buf) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 11078c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr])); 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in1_input, in, 0); 11118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in2_input, in, 1); 11128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in3_input, in, 2); 11138c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in4_input, in, 3); 11148c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in5_input, in, 4); 11158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in6_input, in, 5); 11168c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in7_input, in, 6); 11178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in8_input, in, 7); 11188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in9_input, in, 8); 11198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in10_input, in, 9); 11208c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in11_input, in, 10); 11218c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in12_input, in, 11); 11228c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in13_input, in, 12); 11238c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in14_input, in, 13); 11248c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in15_input, in, 14); 11258c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(in16_input, in, 15); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_cistatic ssize_t in_min_show(struct device *dev, struct device_attribute *attr, 11288c2ecf20Sopenharmony_ci char *buf) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 11318c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 11328c2ecf20Sopenharmony_ci int vccp = nr - 6; 11338c2ecf20Sopenharmony_ci long rc, vid; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { 11368c2ecf20Sopenharmony_ci vid = LM93_VID_FROM_REG(data->vid[vccp]); 11378c2ecf20Sopenharmony_ci rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid); 11388c2ecf20Sopenharmony_ci } else { 11398c2ecf20Sopenharmony_ci rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); 11408c2ecf20Sopenharmony_ci } 11418c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", rc); 11428c2ecf20Sopenharmony_ci} 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_cistatic ssize_t in_min_store(struct device *dev, struct device_attribute *attr, 11458c2ecf20Sopenharmony_ci const char *buf, size_t count) 11468c2ecf20Sopenharmony_ci{ 11478c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 11488c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 11498c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 11508c2ecf20Sopenharmony_ci int vccp = nr - 6; 11518c2ecf20Sopenharmony_ci long vid; 11528c2ecf20Sopenharmony_ci unsigned long val; 11538c2ecf20Sopenharmony_ci int err; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 11568c2ecf20Sopenharmony_ci if (err) 11578c2ecf20Sopenharmony_ci return err; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11608c2ecf20Sopenharmony_ci if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { 11618c2ecf20Sopenharmony_ci vid = LM93_VID_FROM_REG(data->vid[vccp]); 11628c2ecf20Sopenharmony_ci data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) | 11638c2ecf20Sopenharmony_ci LM93_IN_REL_TO_REG(val, 0, vid); 11648c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp), 11658c2ecf20Sopenharmony_ci data->vccp_limits[vccp]); 11668c2ecf20Sopenharmony_ci } else { 11678c2ecf20Sopenharmony_ci data->block7[nr].min = LM93_IN_TO_REG(nr, val); 11688c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_IN_MIN(nr), 11698c2ecf20Sopenharmony_ci data->block7[nr].min); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11728c2ecf20Sopenharmony_ci return count; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_min, in_min, 0); 11768c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_min, in_min, 1); 11778c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_min, in_min, 2); 11788c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_min, in_min, 3); 11798c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in5_min, in_min, 4); 11808c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in6_min, in_min, 5); 11818c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in7_min, in_min, 6); 11828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in8_min, in_min, 7); 11838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in9_min, in_min, 8); 11848c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in10_min, in_min, 9); 11858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in11_min, in_min, 10); 11868c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in12_min, in_min, 11); 11878c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in13_min, in_min, 12); 11888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in14_min, in_min, 13); 11898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in15_min, in_min, 14); 11908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in16_min, in_min, 15); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic ssize_t in_max_show(struct device *dev, struct device_attribute *attr, 11938c2ecf20Sopenharmony_ci char *buf) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 11968c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 11978c2ecf20Sopenharmony_ci int vccp = nr - 6; 11988c2ecf20Sopenharmony_ci long rc, vid; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { 12018c2ecf20Sopenharmony_ci vid = LM93_VID_FROM_REG(data->vid[vccp]); 12028c2ecf20Sopenharmony_ci rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp], vid); 12038c2ecf20Sopenharmony_ci } else { 12048c2ecf20Sopenharmony_ci rc = LM93_IN_FROM_REG(nr, data->block7[nr].max); 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", rc); 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic ssize_t in_max_store(struct device *dev, struct device_attribute *attr, 12108c2ecf20Sopenharmony_ci const char *buf, size_t count) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 12138c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 12148c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 12158c2ecf20Sopenharmony_ci int vccp = nr - 6; 12168c2ecf20Sopenharmony_ci long vid; 12178c2ecf20Sopenharmony_ci unsigned long val; 12188c2ecf20Sopenharmony_ci int err; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 12218c2ecf20Sopenharmony_ci if (err) 12228c2ecf20Sopenharmony_ci return err; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12258c2ecf20Sopenharmony_ci if ((nr == 6 || nr == 7) && vccp_limit_type[vccp]) { 12268c2ecf20Sopenharmony_ci vid = LM93_VID_FROM_REG(data->vid[vccp]); 12278c2ecf20Sopenharmony_ci data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) | 12288c2ecf20Sopenharmony_ci LM93_IN_REL_TO_REG(val, 1, vid); 12298c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp), 12308c2ecf20Sopenharmony_ci data->vccp_limits[vccp]); 12318c2ecf20Sopenharmony_ci } else { 12328c2ecf20Sopenharmony_ci data->block7[nr].max = LM93_IN_TO_REG(nr, val); 12338c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_IN_MAX(nr), 12348c2ecf20Sopenharmony_ci data->block7[nr].max); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12378c2ecf20Sopenharmony_ci return count; 12388c2ecf20Sopenharmony_ci} 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in1_max, in_max, 0); 12418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in2_max, in_max, 1); 12428c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in3_max, in_max, 2); 12438c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in4_max, in_max, 3); 12448c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in5_max, in_max, 4); 12458c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in6_max, in_max, 5); 12468c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in7_max, in_max, 6); 12478c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in8_max, in_max, 7); 12488c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in9_max, in_max, 8); 12498c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in10_max, in_max, 9); 12508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in11_max, in_max, 10); 12518c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in12_max, in_max, 11); 12528c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in13_max, in_max, 12); 12538c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in14_max, in_max, 13); 12548c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in15_max, in_max, 14); 12558c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(in16_max, in_max, 15); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *attr, 12588c2ecf20Sopenharmony_ci char *buf) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 12618c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 12628c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block2[nr])); 12638c2ecf20Sopenharmony_ci} 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0); 12668c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1); 12678c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic ssize_t temp_min_show(struct device *dev, 12708c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 12718c2ecf20Sopenharmony_ci{ 12728c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 12738c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 12748c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].min)); 12758c2ecf20Sopenharmony_ci} 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_cistatic ssize_t temp_min_store(struct device *dev, 12788c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 12798c2ecf20Sopenharmony_ci size_t count) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 12828c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 12838c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 12848c2ecf20Sopenharmony_ci long val; 12858c2ecf20Sopenharmony_ci int err; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 12888c2ecf20Sopenharmony_ci if (err) 12898c2ecf20Sopenharmony_ci return err; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 12928c2ecf20Sopenharmony_ci data->temp_lim[nr].min = LM93_TEMP_TO_REG(val); 12938c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min); 12948c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 12958c2ecf20Sopenharmony_ci return count; 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0); 12998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1); 13008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic ssize_t temp_max_show(struct device *dev, 13038c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13068c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 13078c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->temp_lim[nr].max)); 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic ssize_t temp_max_store(struct device *dev, 13118c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 13128c2ecf20Sopenharmony_ci size_t count) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13158c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 13168c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 13178c2ecf20Sopenharmony_ci long val; 13188c2ecf20Sopenharmony_ci int err; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 13218c2ecf20Sopenharmony_ci if (err) 13228c2ecf20Sopenharmony_ci return err; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13258c2ecf20Sopenharmony_ci data->temp_lim[nr].max = LM93_TEMP_TO_REG(val); 13268c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max); 13278c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13288c2ecf20Sopenharmony_ci return count; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0); 13328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1); 13338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic ssize_t temp_auto_base_show(struct device *dev, 13368c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13398c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 13408c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->block10.base[nr])); 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_cistatic ssize_t temp_auto_base_store(struct device *dev, 13448c2ecf20Sopenharmony_ci struct device_attribute *attr, 13458c2ecf20Sopenharmony_ci const char *buf, size_t count) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13488c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 13498c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 13508c2ecf20Sopenharmony_ci long val; 13518c2ecf20Sopenharmony_ci int err; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 13548c2ecf20Sopenharmony_ci if (err) 13558c2ecf20Sopenharmony_ci return err; 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13588c2ecf20Sopenharmony_ci data->block10.base[nr] = LM93_TEMP_TO_REG(val); 13598c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]); 13608c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13618c2ecf20Sopenharmony_ci return count; 13628c2ecf20Sopenharmony_ci} 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_auto_base, temp_auto_base, 0); 13658c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_auto_base, temp_auto_base, 1); 13668c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_auto_base, temp_auto_base, 2); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic ssize_t temp_auto_boost_show(struct device *dev, 13698c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13728c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 13738c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_FROM_REG(data->boost[nr])); 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic ssize_t temp_auto_boost_store(struct device *dev, 13778c2ecf20Sopenharmony_ci struct device_attribute *attr, 13788c2ecf20Sopenharmony_ci const char *buf, size_t count) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 13818c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 13828c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 13838c2ecf20Sopenharmony_ci long val; 13848c2ecf20Sopenharmony_ci int err; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci err = kstrtol(buf, 10, &val); 13878c2ecf20Sopenharmony_ci if (err) 13888c2ecf20Sopenharmony_ci return err; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 13918c2ecf20Sopenharmony_ci data->boost[nr] = LM93_TEMP_TO_REG(val); 13928c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]); 13938c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 13948c2ecf20Sopenharmony_ci return count; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_auto_boost, temp_auto_boost, 0); 13988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_auto_boost, temp_auto_boost, 1); 13998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_auto_boost, temp_auto_boost, 2); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_cistatic ssize_t temp_auto_boost_hyst_show(struct device *dev, 14028c2ecf20Sopenharmony_ci struct device_attribute *attr, 14038c2ecf20Sopenharmony_ci char *buf) 14048c2ecf20Sopenharmony_ci{ 14058c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 14068c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 14078c2ecf20Sopenharmony_ci int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); 14088c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 14098c2ecf20Sopenharmony_ci LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode)); 14108c2ecf20Sopenharmony_ci} 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_cistatic ssize_t temp_auto_boost_hyst_store(struct device *dev, 14138c2ecf20Sopenharmony_ci struct device_attribute *attr, 14148c2ecf20Sopenharmony_ci const char *buf, size_t count) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 14178c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 14188c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 14198c2ecf20Sopenharmony_ci unsigned long val; 14208c2ecf20Sopenharmony_ci int err; 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 14238c2ecf20Sopenharmony_ci if (err) 14248c2ecf20Sopenharmony_ci return err; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14278c2ecf20Sopenharmony_ci /* force 0.5C/bit mode */ 14288c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 14298c2ecf20Sopenharmony_ci data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); 14308c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); 14318c2ecf20Sopenharmony_ci data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1); 14328c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_BOOST_HYST(nr), 14338c2ecf20Sopenharmony_ci data->boost_hyst[nr/2]); 14348c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14358c2ecf20Sopenharmony_ci return count; 14368c2ecf20Sopenharmony_ci} 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_auto_boost_hyst, temp_auto_boost_hyst, 0); 14398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_auto_boost_hyst, temp_auto_boost_hyst, 1); 14408c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_auto_boost_hyst, temp_auto_boost_hyst, 2); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cistatic ssize_t temp_auto_offset_show(struct device *dev, 14438c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr); 14468c2ecf20Sopenharmony_ci int nr = s_attr->index; 14478c2ecf20Sopenharmony_ci int ofs = s_attr->nr; 14488c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 14498c2ecf20Sopenharmony_ci int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); 14508c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 14518c2ecf20Sopenharmony_ci LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs], 14528c2ecf20Sopenharmony_ci nr, mode)); 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic ssize_t temp_auto_offset_store(struct device *dev, 14568c2ecf20Sopenharmony_ci struct device_attribute *attr, 14578c2ecf20Sopenharmony_ci const char *buf, size_t count) 14588c2ecf20Sopenharmony_ci{ 14598c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr); 14608c2ecf20Sopenharmony_ci int nr = s_attr->index; 14618c2ecf20Sopenharmony_ci int ofs = s_attr->nr; 14628c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 14638c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 14648c2ecf20Sopenharmony_ci unsigned long val; 14658c2ecf20Sopenharmony_ci int err; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 14688c2ecf20Sopenharmony_ci if (err) 14698c2ecf20Sopenharmony_ci return err; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14728c2ecf20Sopenharmony_ci /* force 0.5C/bit mode */ 14738c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 14748c2ecf20Sopenharmony_ci data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); 14758c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); 14768c2ecf20Sopenharmony_ci data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG( 14778c2ecf20Sopenharmony_ci data->block10.offset[ofs], val, nr, 1); 14788c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs), 14798c2ecf20Sopenharmony_ci data->block10.offset[ofs]); 14808c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 14818c2ecf20Sopenharmony_ci return count; 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset1, temp_auto_offset, 0, 0); 14858c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset2, temp_auto_offset, 1, 0); 14868c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset3, temp_auto_offset, 2, 0); 14878c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset4, temp_auto_offset, 3, 0); 14888c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset5, temp_auto_offset, 4, 0); 14898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset6, temp_auto_offset, 5, 0); 14908c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset7, temp_auto_offset, 6, 0); 14918c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset8, temp_auto_offset, 7, 0); 14928c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset9, temp_auto_offset, 8, 0); 14938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset10, temp_auto_offset, 9, 0); 14948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset11, temp_auto_offset, 10, 0); 14958c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp1_auto_offset12, temp_auto_offset, 11, 0); 14968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset1, temp_auto_offset, 0, 1); 14978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset2, temp_auto_offset, 1, 1); 14988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset3, temp_auto_offset, 2, 1); 14998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset4, temp_auto_offset, 3, 1); 15008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset5, temp_auto_offset, 4, 1); 15018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset6, temp_auto_offset, 5, 1); 15028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset7, temp_auto_offset, 6, 1); 15038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset8, temp_auto_offset, 7, 1); 15048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset9, temp_auto_offset, 8, 1); 15058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset10, temp_auto_offset, 9, 1); 15068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset11, temp_auto_offset, 10, 1); 15078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp2_auto_offset12, temp_auto_offset, 11, 1); 15088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset1, temp_auto_offset, 0, 2); 15098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset2, temp_auto_offset, 1, 2); 15108c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset3, temp_auto_offset, 2, 2); 15118c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset4, temp_auto_offset, 3, 2); 15128c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset5, temp_auto_offset, 4, 2); 15138c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset6, temp_auto_offset, 5, 2); 15148c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset7, temp_auto_offset, 6, 2); 15158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset8, temp_auto_offset, 7, 2); 15168c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset9, temp_auto_offset, 8, 2); 15178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset10, temp_auto_offset, 9, 2); 15188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset11, temp_auto_offset, 10, 2); 15198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_2_RW(temp3_auto_offset12, temp_auto_offset, 11, 2); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_cistatic ssize_t temp_auto_pwm_min_show(struct device *dev, 15228c2ecf20Sopenharmony_ci struct device_attribute *attr, 15238c2ecf20Sopenharmony_ci char *buf) 15248c2ecf20Sopenharmony_ci{ 15258c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 15268c2ecf20Sopenharmony_ci u8 reg, ctl4; 15278c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 15288c2ecf20Sopenharmony_ci reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f; 15298c2ecf20Sopenharmony_ci ctl4 = data->block9[nr][LM93_PWM_CTL4]; 15308c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ? 15318c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ)); 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic ssize_t temp_auto_pwm_min_store(struct device *dev, 15358c2ecf20Sopenharmony_ci struct device_attribute *attr, 15368c2ecf20Sopenharmony_ci const char *buf, size_t count) 15378c2ecf20Sopenharmony_ci{ 15388c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 15398c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 15408c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 15418c2ecf20Sopenharmony_ci u8 reg, ctl4; 15428c2ecf20Sopenharmony_ci unsigned long val; 15438c2ecf20Sopenharmony_ci int err; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 15468c2ecf20Sopenharmony_ci if (err) 15478c2ecf20Sopenharmony_ci return err; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15508c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr)); 15518c2ecf20Sopenharmony_ci ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); 15528c2ecf20Sopenharmony_ci reg = (reg & 0x0f) | 15538c2ecf20Sopenharmony_ci LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? 15548c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : 15558c2ecf20Sopenharmony_ci LM93_PWM_MAP_HI_FREQ) << 4; 15568c2ecf20Sopenharmony_ci data->auto_pwm_min_hyst[nr/2] = reg; 15578c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); 15588c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15598c2ecf20Sopenharmony_ci return count; 15608c2ecf20Sopenharmony_ci} 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_auto_pwm_min, temp_auto_pwm_min, 0); 15638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_auto_pwm_min, temp_auto_pwm_min, 1); 15648c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_auto_pwm_min, temp_auto_pwm_min, 2); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic ssize_t temp_auto_offset_hyst_show(struct device *dev, 15678c2ecf20Sopenharmony_ci struct device_attribute *attr, 15688c2ecf20Sopenharmony_ci char *buf) 15698c2ecf20Sopenharmony_ci{ 15708c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 15718c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 15728c2ecf20Sopenharmony_ci int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr); 15738c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_TEMP_OFFSET_FROM_REG( 15748c2ecf20Sopenharmony_ci data->auto_pwm_min_hyst[nr / 2], mode)); 15758c2ecf20Sopenharmony_ci} 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic ssize_t temp_auto_offset_hyst_store(struct device *dev, 15788c2ecf20Sopenharmony_ci struct device_attribute *attr, 15798c2ecf20Sopenharmony_ci const char *buf, size_t count) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 15828c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 15838c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 15848c2ecf20Sopenharmony_ci u8 reg; 15858c2ecf20Sopenharmony_ci unsigned long val; 15868c2ecf20Sopenharmony_ci int err; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 15898c2ecf20Sopenharmony_ci if (err) 15908c2ecf20Sopenharmony_ci return err; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15938c2ecf20Sopenharmony_ci /* force 0.5C/bit mode */ 15948c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 15958c2ecf20Sopenharmony_ci data->sfc2 |= ((nr < 2) ? 0x10 : 0x20); 15968c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); 15978c2ecf20Sopenharmony_ci reg = data->auto_pwm_min_hyst[nr/2]; 15988c2ecf20Sopenharmony_ci reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f); 15998c2ecf20Sopenharmony_ci data->auto_pwm_min_hyst[nr/2] = reg; 16008c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg); 16018c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 16028c2ecf20Sopenharmony_ci return count; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_auto_offset_hyst, temp_auto_offset_hyst, 0); 16068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_auto_offset_hyst, temp_auto_offset_hyst, 1); 16078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_auto_offset_hyst, temp_auto_offset_hyst, 2); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_cistatic ssize_t fan_input_show(struct device *dev, 16108c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr); 16138c2ecf20Sopenharmony_ci int nr = s_attr->index; 16148c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block5[nr])); 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, fan_input, 0); 16208c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, fan_input, 1); 16218c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan3_input, fan_input, 2); 16228c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan4_input, fan_input, 3); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_cistatic ssize_t fan_min_show(struct device *dev, struct device_attribute *attr, 16258c2ecf20Sopenharmony_ci char *buf) 16268c2ecf20Sopenharmony_ci{ 16278c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 16288c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_FAN_FROM_REG(data->block8[nr])); 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic ssize_t fan_min_store(struct device *dev, 16348c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 16358c2ecf20Sopenharmony_ci size_t count) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 16388c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 16398c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 16408c2ecf20Sopenharmony_ci unsigned long val; 16418c2ecf20Sopenharmony_ci int err; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 16448c2ecf20Sopenharmony_ci if (err) 16458c2ecf20Sopenharmony_ci return err; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 16488c2ecf20Sopenharmony_ci data->block8[nr] = LM93_FAN_TO_REG(val); 16498c2ecf20Sopenharmony_ci lm93_write_word(client, LM93_REG_FAN_MIN(nr), data->block8[nr]); 16508c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 16518c2ecf20Sopenharmony_ci return count; 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0); 16558c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1); 16568c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan3_min, fan_min, 2); 16578c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan4_min, fan_min, 3); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci/* 16608c2ecf20Sopenharmony_ci * some tedious bit-twiddling here to deal with the register format: 16618c2ecf20Sopenharmony_ci * 16628c2ecf20Sopenharmony_ci * data->sf_tach_to_pwm: (tach to pwm mapping bits) 16638c2ecf20Sopenharmony_ci * 16648c2ecf20Sopenharmony_ci * bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 16658c2ecf20Sopenharmony_ci * T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1 16668c2ecf20Sopenharmony_ci * 16678c2ecf20Sopenharmony_ci * data->sfc2: (enable bits) 16688c2ecf20Sopenharmony_ci * 16698c2ecf20Sopenharmony_ci * bit | 3 | 2 | 1 | 0 16708c2ecf20Sopenharmony_ci * T4 T3 T2 T1 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_cistatic ssize_t fan_smart_tach_show(struct device *dev, 16748c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 16758c2ecf20Sopenharmony_ci{ 16768c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 16778c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 16788c2ecf20Sopenharmony_ci long rc = 0; 16798c2ecf20Sopenharmony_ci int mapping; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci /* extract the relevant mapping */ 16828c2ecf20Sopenharmony_ci mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci /* if there's a mapping and it's enabled */ 16858c2ecf20Sopenharmony_ci if (mapping && ((data->sfc2 >> nr) & 0x01)) 16868c2ecf20Sopenharmony_ci rc = mapping; 16878c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", rc); 16888c2ecf20Sopenharmony_ci} 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci/* 16918c2ecf20Sopenharmony_ci * helper function - must grab data->update_lock before calling 16928c2ecf20Sopenharmony_ci * fan is 0-3, indicating fan1-fan4 16938c2ecf20Sopenharmony_ci */ 16948c2ecf20Sopenharmony_cistatic void lm93_write_fan_smart_tach(struct i2c_client *client, 16958c2ecf20Sopenharmony_ci struct lm93_data *data, int fan, long value) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci /* insert the new mapping and write it out */ 16988c2ecf20Sopenharmony_ci data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); 16998c2ecf20Sopenharmony_ci data->sf_tach_to_pwm &= ~(0x3 << fan * 2); 17008c2ecf20Sopenharmony_ci data->sf_tach_to_pwm |= value << fan * 2; 17018c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci /* insert the enable bit and write it out */ 17048c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 17058c2ecf20Sopenharmony_ci if (value) 17068c2ecf20Sopenharmony_ci data->sfc2 |= 1 << fan; 17078c2ecf20Sopenharmony_ci else 17088c2ecf20Sopenharmony_ci data->sfc2 &= ~(1 << fan); 17098c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); 17108c2ecf20Sopenharmony_ci} 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_cistatic ssize_t fan_smart_tach_store(struct device *dev, 17138c2ecf20Sopenharmony_ci struct device_attribute *attr, 17148c2ecf20Sopenharmony_ci const char *buf, size_t count) 17158c2ecf20Sopenharmony_ci{ 17168c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 17178c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 17188c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 17198c2ecf20Sopenharmony_ci unsigned long val; 17208c2ecf20Sopenharmony_ci int err; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 17238c2ecf20Sopenharmony_ci if (err) 17248c2ecf20Sopenharmony_ci return err; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 17278c2ecf20Sopenharmony_ci /* sanity test, ignore the write otherwise */ 17288c2ecf20Sopenharmony_ci if (val <= 2) { 17298c2ecf20Sopenharmony_ci /* can't enable if pwm freq is 22.5KHz */ 17308c2ecf20Sopenharmony_ci if (val) { 17318c2ecf20Sopenharmony_ci u8 ctl4 = lm93_read_byte(client, 17328c2ecf20Sopenharmony_ci LM93_REG_PWM_CTL(val - 1, LM93_PWM_CTL4)); 17338c2ecf20Sopenharmony_ci if ((ctl4 & 0x07) == 0) 17348c2ecf20Sopenharmony_ci val = 0; 17358c2ecf20Sopenharmony_ci } 17368c2ecf20Sopenharmony_ci lm93_write_fan_smart_tach(client, data, nr, val); 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 17398c2ecf20Sopenharmony_ci return count; 17408c2ecf20Sopenharmony_ci} 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_smart_tach, fan_smart_tach, 0); 17438c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_smart_tach, fan_smart_tach, 1); 17448c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan3_smart_tach, fan_smart_tach, 2); 17458c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan4_smart_tach, fan_smart_tach, 3); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_cistatic ssize_t pwm_show(struct device *dev, struct device_attribute *attr, 17488c2ecf20Sopenharmony_ci char *buf) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 17518c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 17528c2ecf20Sopenharmony_ci u8 ctl2, ctl4; 17538c2ecf20Sopenharmony_ci long rc; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci ctl2 = data->block9[nr][LM93_PWM_CTL2]; 17568c2ecf20Sopenharmony_ci ctl4 = data->block9[nr][LM93_PWM_CTL4]; 17578c2ecf20Sopenharmony_ci if (ctl2 & 0x01) /* show user commanded value if enabled */ 17588c2ecf20Sopenharmony_ci rc = data->pwm_override[nr]; 17598c2ecf20Sopenharmony_ci else /* show present h/w value if manual pwm disabled */ 17608c2ecf20Sopenharmony_ci rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ? 17618c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ); 17628c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", rc); 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_cistatic ssize_t pwm_store(struct device *dev, struct device_attribute *attr, 17668c2ecf20Sopenharmony_ci const char *buf, size_t count) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 17698c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 17708c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 17718c2ecf20Sopenharmony_ci u8 ctl2, ctl4; 17728c2ecf20Sopenharmony_ci unsigned long val; 17738c2ecf20Sopenharmony_ci int err; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 17768c2ecf20Sopenharmony_ci if (err) 17778c2ecf20Sopenharmony_ci return err; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 17808c2ecf20Sopenharmony_ci ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2)); 17818c2ecf20Sopenharmony_ci ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); 17828c2ecf20Sopenharmony_ci ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? 17838c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4; 17848c2ecf20Sopenharmony_ci /* save user commanded value */ 17858c2ecf20Sopenharmony_ci data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4, 17868c2ecf20Sopenharmony_ci (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ : 17878c2ecf20Sopenharmony_ci LM93_PWM_MAP_HI_FREQ); 17888c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2); 17898c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 17908c2ecf20Sopenharmony_ci return count; 17918c2ecf20Sopenharmony_ci} 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0); 17948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic ssize_t pwm_enable_show(struct device *dev, 17978c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 17988c2ecf20Sopenharmony_ci{ 17998c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 18008c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 18018c2ecf20Sopenharmony_ci u8 ctl2; 18028c2ecf20Sopenharmony_ci long rc; 18038c2ecf20Sopenharmony_ci 18048c2ecf20Sopenharmony_ci ctl2 = data->block9[nr][LM93_PWM_CTL2]; 18058c2ecf20Sopenharmony_ci if (ctl2 & 0x01) /* manual override enabled ? */ 18068c2ecf20Sopenharmony_ci rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1; 18078c2ecf20Sopenharmony_ci else 18088c2ecf20Sopenharmony_ci rc = 2; 18098c2ecf20Sopenharmony_ci return sprintf(buf, "%ld\n", rc); 18108c2ecf20Sopenharmony_ci} 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_cistatic ssize_t pwm_enable_store(struct device *dev, 18138c2ecf20Sopenharmony_ci struct device_attribute *attr, 18148c2ecf20Sopenharmony_ci const char *buf, size_t count) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 18178c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 18188c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 18198c2ecf20Sopenharmony_ci u8 ctl2; 18208c2ecf20Sopenharmony_ci unsigned long val; 18218c2ecf20Sopenharmony_ci int err; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 18248c2ecf20Sopenharmony_ci if (err) 18258c2ecf20Sopenharmony_ci return err; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 18288c2ecf20Sopenharmony_ci ctl2 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2)); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci switch (val) { 18318c2ecf20Sopenharmony_ci case 0: 18328c2ecf20Sopenharmony_ci ctl2 |= 0xF1; /* enable manual override, set PWM to max */ 18338c2ecf20Sopenharmony_ci break; 18348c2ecf20Sopenharmony_ci case 1: 18358c2ecf20Sopenharmony_ci ctl2 |= 0x01; /* enable manual override */ 18368c2ecf20Sopenharmony_ci break; 18378c2ecf20Sopenharmony_ci case 2: 18388c2ecf20Sopenharmony_ci ctl2 &= ~0x01; /* disable manual override */ 18398c2ecf20Sopenharmony_ci break; 18408c2ecf20Sopenharmony_ci default: 18418c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 18428c2ecf20Sopenharmony_ci return -EINVAL; 18438c2ecf20Sopenharmony_ci } 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL2), ctl2); 18468c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 18478c2ecf20Sopenharmony_ci return count; 18488c2ecf20Sopenharmony_ci} 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_enable, pwm_enable, 0); 18518c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_enable, pwm_enable, 1); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_cistatic ssize_t pwm_freq_show(struct device *dev, 18548c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 18578c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 18588c2ecf20Sopenharmony_ci u8 ctl4; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci ctl4 = data->block9[nr][LM93_PWM_CTL4]; 18618c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_PWM_FREQ_FROM_REG(ctl4)); 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci/* 18658c2ecf20Sopenharmony_ci * helper function - must grab data->update_lock before calling 18668c2ecf20Sopenharmony_ci * pwm is 0-1, indicating pwm1-pwm2 18678c2ecf20Sopenharmony_ci * this disables smart tach for all tach channels bound to the given pwm 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_cistatic void lm93_disable_fan_smart_tach(struct i2c_client *client, 18708c2ecf20Sopenharmony_ci struct lm93_data *data, int pwm) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM); 18738c2ecf20Sopenharmony_ci int mask; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci /* collapse the mapping into a mask of enable bits */ 18768c2ecf20Sopenharmony_ci mapping = (mapping >> pwm) & 0x55; 18778c2ecf20Sopenharmony_ci mask = mapping & 0x01; 18788c2ecf20Sopenharmony_ci mask |= (mapping & 0x04) >> 1; 18798c2ecf20Sopenharmony_ci mask |= (mapping & 0x10) >> 2; 18808c2ecf20Sopenharmony_ci mask |= (mapping & 0x40) >> 3; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* disable smart tach according to the mask */ 18838c2ecf20Sopenharmony_ci data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2); 18848c2ecf20Sopenharmony_ci data->sfc2 &= ~mask; 18858c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SFC2, data->sfc2); 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic ssize_t pwm_freq_store(struct device *dev, 18898c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, 18908c2ecf20Sopenharmony_ci size_t count) 18918c2ecf20Sopenharmony_ci{ 18928c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 18938c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 18948c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 18958c2ecf20Sopenharmony_ci u8 ctl4; 18968c2ecf20Sopenharmony_ci unsigned long val; 18978c2ecf20Sopenharmony_ci int err; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 19008c2ecf20Sopenharmony_ci if (err) 19018c2ecf20Sopenharmony_ci return err; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 19048c2ecf20Sopenharmony_ci ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); 19058c2ecf20Sopenharmony_ci ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val); 19068c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL4] = ctl4; 19078c2ecf20Sopenharmony_ci /* ctl4 == 0 -> 22.5KHz -> disable smart tach */ 19088c2ecf20Sopenharmony_ci if (!ctl4) 19098c2ecf20Sopenharmony_ci lm93_disable_fan_smart_tach(client, data, nr); 19108c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4), ctl4); 19118c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 19128c2ecf20Sopenharmony_ci return count; 19138c2ecf20Sopenharmony_ci} 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_freq, pwm_freq, 0); 19168c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_freq, pwm_freq, 1); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_channels_show(struct device *dev, 19198c2ecf20Sopenharmony_ci struct device_attribute *attr, 19208c2ecf20Sopenharmony_ci char *buf) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 19238c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 19248c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->block9[nr][LM93_PWM_CTL1]); 19258c2ecf20Sopenharmony_ci} 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_channels_store(struct device *dev, 19288c2ecf20Sopenharmony_ci struct device_attribute *attr, 19298c2ecf20Sopenharmony_ci const char *buf, size_t count) 19308c2ecf20Sopenharmony_ci{ 19318c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 19328c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 19338c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 19348c2ecf20Sopenharmony_ci unsigned long val; 19358c2ecf20Sopenharmony_ci int err; 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 19388c2ecf20Sopenharmony_ci if (err) 19398c2ecf20Sopenharmony_ci return err; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 19428c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL1] = clamp_val(val, 0, 255); 19438c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL1), 19448c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL1]); 19458c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 19468c2ecf20Sopenharmony_ci return count; 19478c2ecf20Sopenharmony_ci} 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_channels, pwm_auto_channels, 0); 19508c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_channels, pwm_auto_channels, 1); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_spinup_min_show(struct device *dev, 19538c2ecf20Sopenharmony_ci struct device_attribute *attr, 19548c2ecf20Sopenharmony_ci char *buf) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 19578c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 19588c2ecf20Sopenharmony_ci u8 ctl3, ctl4; 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci ctl3 = data->block9[nr][LM93_PWM_CTL3]; 19618c2ecf20Sopenharmony_ci ctl4 = data->block9[nr][LM93_PWM_CTL4]; 19628c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 19638c2ecf20Sopenharmony_ci LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ? 19648c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ)); 19658c2ecf20Sopenharmony_ci} 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_spinup_min_store(struct device *dev, 19688c2ecf20Sopenharmony_ci struct device_attribute *attr, 19698c2ecf20Sopenharmony_ci const char *buf, size_t count) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 19728c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 19738c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 19748c2ecf20Sopenharmony_ci u8 ctl3, ctl4; 19758c2ecf20Sopenharmony_ci unsigned long val; 19768c2ecf20Sopenharmony_ci int err; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 19798c2ecf20Sopenharmony_ci if (err) 19808c2ecf20Sopenharmony_ci return err; 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 19838c2ecf20Sopenharmony_ci ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); 19848c2ecf20Sopenharmony_ci ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4)); 19858c2ecf20Sopenharmony_ci ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ? 19868c2ecf20Sopenharmony_ci LM93_PWM_MAP_LO_FREQ : 19878c2ecf20Sopenharmony_ci LM93_PWM_MAP_HI_FREQ); 19888c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL3] = ctl3; 19898c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); 19908c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 19918c2ecf20Sopenharmony_ci return count; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_spinup_min, pwm_auto_spinup_min, 0); 19958c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_spinup_min, pwm_auto_spinup_min, 1); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_spinup_time_show(struct device *dev, 19988c2ecf20Sopenharmony_ci struct device_attribute *attr, 19998c2ecf20Sopenharmony_ci char *buf) 20008c2ecf20Sopenharmony_ci{ 20018c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 20028c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 20038c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_SPINUP_TIME_FROM_REG( 20048c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL3])); 20058c2ecf20Sopenharmony_ci} 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_spinup_time_store(struct device *dev, 20088c2ecf20Sopenharmony_ci struct device_attribute *attr, 20098c2ecf20Sopenharmony_ci const char *buf, size_t count) 20108c2ecf20Sopenharmony_ci{ 20118c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 20128c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 20138c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 20148c2ecf20Sopenharmony_ci u8 ctl3; 20158c2ecf20Sopenharmony_ci unsigned long val; 20168c2ecf20Sopenharmony_ci int err; 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 20198c2ecf20Sopenharmony_ci if (err) 20208c2ecf20Sopenharmony_ci return err; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 20238c2ecf20Sopenharmony_ci ctl3 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3)); 20248c2ecf20Sopenharmony_ci ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0); 20258c2ecf20Sopenharmony_ci data->block9[nr][LM93_PWM_CTL3] = ctl3; 20268c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3); 20278c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 20288c2ecf20Sopenharmony_ci return count; 20298c2ecf20Sopenharmony_ci} 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1_auto_spinup_time, pwm_auto_spinup_time, 0); 20328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2_auto_spinup_time, pwm_auto_spinup_time, 1); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_prochot_ramp_show(struct device *dev, 20358c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 20368c2ecf20Sopenharmony_ci{ 20378c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 20388c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 20398c2ecf20Sopenharmony_ci LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f)); 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_prochot_ramp_store(struct device *dev, 20438c2ecf20Sopenharmony_ci struct device_attribute *attr, 20448c2ecf20Sopenharmony_ci const char *buf, size_t count) 20458c2ecf20Sopenharmony_ci{ 20468c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 20478c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 20488c2ecf20Sopenharmony_ci u8 ramp; 20498c2ecf20Sopenharmony_ci unsigned long val; 20508c2ecf20Sopenharmony_ci int err; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 20538c2ecf20Sopenharmony_ci if (err) 20548c2ecf20Sopenharmony_ci return err; 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 20578c2ecf20Sopenharmony_ci ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); 20588c2ecf20Sopenharmony_ci ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0); 20598c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp); 20608c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 20618c2ecf20Sopenharmony_ci return count; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pwm_auto_prochot_ramp); 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_vrdhot_ramp_show(struct device *dev, 20678c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 20708c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 20718c2ecf20Sopenharmony_ci LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f)); 20728c2ecf20Sopenharmony_ci} 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_cistatic ssize_t pwm_auto_vrdhot_ramp_store(struct device *dev, 20758c2ecf20Sopenharmony_ci struct device_attribute *attr, 20768c2ecf20Sopenharmony_ci const char *buf, size_t count) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 20798c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 20808c2ecf20Sopenharmony_ci u8 ramp; 20818c2ecf20Sopenharmony_ci unsigned long val; 20828c2ecf20Sopenharmony_ci int err; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 20858c2ecf20Sopenharmony_ci if (err) 20868c2ecf20Sopenharmony_ci return err; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 20898c2ecf20Sopenharmony_ci ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL); 20908c2ecf20Sopenharmony_ci ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f); 20918c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp); 20928c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 20938c2ecf20Sopenharmony_ci return 0; 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pwm_auto_vrdhot_ramp); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_cistatic ssize_t vid_show(struct device *dev, struct device_attribute *attr, 20998c2ecf20Sopenharmony_ci char *buf) 21008c2ecf20Sopenharmony_ci{ 21018c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21028c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 21038c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_VID_FROM_REG(data->vid[nr])); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(cpu0_vid, vid, 0); 21078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(cpu1_vid, vid, 1); 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_cistatic ssize_t prochot_show(struct device *dev, struct device_attribute *attr, 21108c2ecf20Sopenharmony_ci char *buf) 21118c2ecf20Sopenharmony_ci{ 21128c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21138c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 21148c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->block4[nr].cur); 21158c2ecf20Sopenharmony_ci} 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(prochot1, prochot, 0); 21188c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(prochot2, prochot, 1); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_cistatic ssize_t prochot_avg_show(struct device *dev, 21218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21248c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 21258c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->block4[nr].avg); 21268c2ecf20Sopenharmony_ci} 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(prochot1_avg, prochot_avg, 0); 21298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(prochot2_avg, prochot_avg, 1); 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_cistatic ssize_t prochot_max_show(struct device *dev, 21328c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 21338c2ecf20Sopenharmony_ci{ 21348c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21358c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 21368c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->prochot_max[nr]); 21378c2ecf20Sopenharmony_ci} 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_cistatic ssize_t prochot_max_store(struct device *dev, 21408c2ecf20Sopenharmony_ci struct device_attribute *attr, 21418c2ecf20Sopenharmony_ci const char *buf, size_t count) 21428c2ecf20Sopenharmony_ci{ 21438c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21448c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 21458c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 21468c2ecf20Sopenharmony_ci unsigned long val; 21478c2ecf20Sopenharmony_ci int err; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 21508c2ecf20Sopenharmony_ci if (err) 21518c2ecf20Sopenharmony_ci return err; 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 21548c2ecf20Sopenharmony_ci data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val); 21558c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr), 21568c2ecf20Sopenharmony_ci data->prochot_max[nr]); 21578c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 21588c2ecf20Sopenharmony_ci return count; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot1_max, prochot_max, 0); 21628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot2_max, prochot_max, 1); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic const u8 prochot_override_mask[] = { 0x80, 0x40 }; 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic ssize_t prochot_override_show(struct device *dev, 21678c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21708c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 21718c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 21728c2ecf20Sopenharmony_ci (data->prochot_override & prochot_override_mask[nr]) ? 1 : 0); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cistatic ssize_t prochot_override_store(struct device *dev, 21768c2ecf20Sopenharmony_ci struct device_attribute *attr, 21778c2ecf20Sopenharmony_ci const char *buf, size_t count) 21788c2ecf20Sopenharmony_ci{ 21798c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 21808c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 21818c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 21828c2ecf20Sopenharmony_ci unsigned long val; 21838c2ecf20Sopenharmony_ci int err; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 21868c2ecf20Sopenharmony_ci if (err) 21878c2ecf20Sopenharmony_ci return err; 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 21908c2ecf20Sopenharmony_ci if (val) 21918c2ecf20Sopenharmony_ci data->prochot_override |= prochot_override_mask[nr]; 21928c2ecf20Sopenharmony_ci else 21938c2ecf20Sopenharmony_ci data->prochot_override &= (~prochot_override_mask[nr]); 21948c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, 21958c2ecf20Sopenharmony_ci data->prochot_override); 21968c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 21978c2ecf20Sopenharmony_ci return count; 21988c2ecf20Sopenharmony_ci} 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot1_override, prochot_override, 0); 22018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot2_override, prochot_override, 1); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_cistatic ssize_t prochot_interval_show(struct device *dev, 22048c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22058c2ecf20Sopenharmony_ci{ 22068c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 22078c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 22088c2ecf20Sopenharmony_ci u8 tmp; 22098c2ecf20Sopenharmony_ci if (nr == 1) 22108c2ecf20Sopenharmony_ci tmp = (data->prochot_interval & 0xf0) >> 4; 22118c2ecf20Sopenharmony_ci else 22128c2ecf20Sopenharmony_ci tmp = data->prochot_interval & 0x0f; 22138c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_INTERVAL_FROM_REG(tmp)); 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_cistatic ssize_t prochot_interval_store(struct device *dev, 22178c2ecf20Sopenharmony_ci struct device_attribute *attr, 22188c2ecf20Sopenharmony_ci const char *buf, size_t count) 22198c2ecf20Sopenharmony_ci{ 22208c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 22218c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 22228c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 22238c2ecf20Sopenharmony_ci u8 tmp; 22248c2ecf20Sopenharmony_ci unsigned long val; 22258c2ecf20Sopenharmony_ci int err; 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 22288c2ecf20Sopenharmony_ci if (err) 22298c2ecf20Sopenharmony_ci return err; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 22328c2ecf20Sopenharmony_ci tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL); 22338c2ecf20Sopenharmony_ci if (nr == 1) 22348c2ecf20Sopenharmony_ci tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4); 22358c2ecf20Sopenharmony_ci else 22368c2ecf20Sopenharmony_ci tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val); 22378c2ecf20Sopenharmony_ci data->prochot_interval = tmp; 22388c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp); 22398c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 22408c2ecf20Sopenharmony_ci return count; 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot1_interval, prochot_interval, 0); 22448c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(prochot2_interval, prochot_interval, 1); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_cistatic ssize_t prochot_override_duty_cycle_show(struct device *dev, 22478c2ecf20Sopenharmony_ci struct device_attribute *attr, 22488c2ecf20Sopenharmony_ci char *buf) 22498c2ecf20Sopenharmony_ci{ 22508c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 22518c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->prochot_override & 0x0f); 22528c2ecf20Sopenharmony_ci} 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_cistatic ssize_t prochot_override_duty_cycle_store(struct device *dev, 22558c2ecf20Sopenharmony_ci struct device_attribute *attr, 22568c2ecf20Sopenharmony_ci const char *buf, size_t count) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 22598c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 22608c2ecf20Sopenharmony_ci unsigned long val; 22618c2ecf20Sopenharmony_ci int err; 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 22648c2ecf20Sopenharmony_ci if (err) 22658c2ecf20Sopenharmony_ci return err; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 22688c2ecf20Sopenharmony_ci data->prochot_override = (data->prochot_override & 0xf0) | 22698c2ecf20Sopenharmony_ci clamp_val(val, 0, 15); 22708c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE, 22718c2ecf20Sopenharmony_ci data->prochot_override); 22728c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 22738c2ecf20Sopenharmony_ci return count; 22748c2ecf20Sopenharmony_ci} 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(prochot_override_duty_cycle); 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_cistatic ssize_t prochot_short_show(struct device *dev, 22798c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 22808c2ecf20Sopenharmony_ci{ 22818c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 22828c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (data->config & 0x10) ? 1 : 0); 22838c2ecf20Sopenharmony_ci} 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_cistatic ssize_t prochot_short_store(struct device *dev, 22868c2ecf20Sopenharmony_ci struct device_attribute *attr, 22878c2ecf20Sopenharmony_ci const char *buf, size_t count) 22888c2ecf20Sopenharmony_ci{ 22898c2ecf20Sopenharmony_ci struct lm93_data *data = dev_get_drvdata(dev); 22908c2ecf20Sopenharmony_ci struct i2c_client *client = data->client; 22918c2ecf20Sopenharmony_ci unsigned long val; 22928c2ecf20Sopenharmony_ci int err; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &val); 22958c2ecf20Sopenharmony_ci if (err) 22968c2ecf20Sopenharmony_ci return err; 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 22998c2ecf20Sopenharmony_ci if (val) 23008c2ecf20Sopenharmony_ci data->config |= 0x10; 23018c2ecf20Sopenharmony_ci else 23028c2ecf20Sopenharmony_ci data->config &= ~0x10; 23038c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_CONFIG, data->config); 23048c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 23058c2ecf20Sopenharmony_ci return count; 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(prochot_short); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic ssize_t vrdhot_show(struct device *dev, struct device_attribute *attr, 23118c2ecf20Sopenharmony_ci char *buf) 23128c2ecf20Sopenharmony_ci{ 23138c2ecf20Sopenharmony_ci int nr = (to_sensor_dev_attr(attr))->index; 23148c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 23158c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 23168c2ecf20Sopenharmony_ci data->block1.host_status_1 & (1 << (nr + 4)) ? 1 : 0); 23178c2ecf20Sopenharmony_ci} 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(vrdhot1, vrdhot, 0); 23208c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(vrdhot2, vrdhot, 1); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_cistatic ssize_t gpio_show(struct device *dev, struct device_attribute *attr, 23238c2ecf20Sopenharmony_ci char *buf) 23248c2ecf20Sopenharmony_ci{ 23258c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 23268c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_GPI_FROM_REG(data->gpi)); 23278c2ecf20Sopenharmony_ci} 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(gpio); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr, 23328c2ecf20Sopenharmony_ci char *buf) 23338c2ecf20Sopenharmony_ci{ 23348c2ecf20Sopenharmony_ci struct lm93_data *data = lm93_update_device(dev); 23358c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", LM93_ALARMS_FROM_REG(data->block1)); 23368c2ecf20Sopenharmony_ci} 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(alarms); 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_cistatic struct attribute *lm93_attrs[] = { 23418c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_input.dev_attr.attr, 23428c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_input.dev_attr.attr, 23438c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_input.dev_attr.attr, 23448c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_input.dev_attr.attr, 23458c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_input.dev_attr.attr, 23468c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_input.dev_attr.attr, 23478c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_input.dev_attr.attr, 23488c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_input.dev_attr.attr, 23498c2ecf20Sopenharmony_ci &sensor_dev_attr_in9_input.dev_attr.attr, 23508c2ecf20Sopenharmony_ci &sensor_dev_attr_in10_input.dev_attr.attr, 23518c2ecf20Sopenharmony_ci &sensor_dev_attr_in11_input.dev_attr.attr, 23528c2ecf20Sopenharmony_ci &sensor_dev_attr_in12_input.dev_attr.attr, 23538c2ecf20Sopenharmony_ci &sensor_dev_attr_in13_input.dev_attr.attr, 23548c2ecf20Sopenharmony_ci &sensor_dev_attr_in14_input.dev_attr.attr, 23558c2ecf20Sopenharmony_ci &sensor_dev_attr_in15_input.dev_attr.attr, 23568c2ecf20Sopenharmony_ci &sensor_dev_attr_in16_input.dev_attr.attr, 23578c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_min.dev_attr.attr, 23588c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_min.dev_attr.attr, 23598c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_min.dev_attr.attr, 23608c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_min.dev_attr.attr, 23618c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_min.dev_attr.attr, 23628c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_min.dev_attr.attr, 23638c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_min.dev_attr.attr, 23648c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_min.dev_attr.attr, 23658c2ecf20Sopenharmony_ci &sensor_dev_attr_in9_min.dev_attr.attr, 23668c2ecf20Sopenharmony_ci &sensor_dev_attr_in10_min.dev_attr.attr, 23678c2ecf20Sopenharmony_ci &sensor_dev_attr_in11_min.dev_attr.attr, 23688c2ecf20Sopenharmony_ci &sensor_dev_attr_in12_min.dev_attr.attr, 23698c2ecf20Sopenharmony_ci &sensor_dev_attr_in13_min.dev_attr.attr, 23708c2ecf20Sopenharmony_ci &sensor_dev_attr_in14_min.dev_attr.attr, 23718c2ecf20Sopenharmony_ci &sensor_dev_attr_in15_min.dev_attr.attr, 23728c2ecf20Sopenharmony_ci &sensor_dev_attr_in16_min.dev_attr.attr, 23738c2ecf20Sopenharmony_ci &sensor_dev_attr_in1_max.dev_attr.attr, 23748c2ecf20Sopenharmony_ci &sensor_dev_attr_in2_max.dev_attr.attr, 23758c2ecf20Sopenharmony_ci &sensor_dev_attr_in3_max.dev_attr.attr, 23768c2ecf20Sopenharmony_ci &sensor_dev_attr_in4_max.dev_attr.attr, 23778c2ecf20Sopenharmony_ci &sensor_dev_attr_in5_max.dev_attr.attr, 23788c2ecf20Sopenharmony_ci &sensor_dev_attr_in6_max.dev_attr.attr, 23798c2ecf20Sopenharmony_ci &sensor_dev_attr_in7_max.dev_attr.attr, 23808c2ecf20Sopenharmony_ci &sensor_dev_attr_in8_max.dev_attr.attr, 23818c2ecf20Sopenharmony_ci &sensor_dev_attr_in9_max.dev_attr.attr, 23828c2ecf20Sopenharmony_ci &sensor_dev_attr_in10_max.dev_attr.attr, 23838c2ecf20Sopenharmony_ci &sensor_dev_attr_in11_max.dev_attr.attr, 23848c2ecf20Sopenharmony_ci &sensor_dev_attr_in12_max.dev_attr.attr, 23858c2ecf20Sopenharmony_ci &sensor_dev_attr_in13_max.dev_attr.attr, 23868c2ecf20Sopenharmony_ci &sensor_dev_attr_in14_max.dev_attr.attr, 23878c2ecf20Sopenharmony_ci &sensor_dev_attr_in15_max.dev_attr.attr, 23888c2ecf20Sopenharmony_ci &sensor_dev_attr_in16_max.dev_attr.attr, 23898c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 23908c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_input.dev_attr.attr, 23918c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_input.dev_attr.attr, 23928c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_min.dev_attr.attr, 23938c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_min.dev_attr.attr, 23948c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_min.dev_attr.attr, 23958c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_max.dev_attr.attr, 23968c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_max.dev_attr.attr, 23978c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_max.dev_attr.attr, 23988c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_base.dev_attr.attr, 23998c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_base.dev_attr.attr, 24008c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_base.dev_attr.attr, 24018c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_boost.dev_attr.attr, 24028c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_boost.dev_attr.attr, 24038c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_boost.dev_attr.attr, 24048c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr, 24058c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr, 24068c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr, 24078c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset1.dev_attr.attr, 24088c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset2.dev_attr.attr, 24098c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset3.dev_attr.attr, 24108c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset4.dev_attr.attr, 24118c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset5.dev_attr.attr, 24128c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset6.dev_attr.attr, 24138c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset7.dev_attr.attr, 24148c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset8.dev_attr.attr, 24158c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset9.dev_attr.attr, 24168c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset10.dev_attr.attr, 24178c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset11.dev_attr.attr, 24188c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset12.dev_attr.attr, 24198c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset1.dev_attr.attr, 24208c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset2.dev_attr.attr, 24218c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset3.dev_attr.attr, 24228c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset4.dev_attr.attr, 24238c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset5.dev_attr.attr, 24248c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset6.dev_attr.attr, 24258c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset7.dev_attr.attr, 24268c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset8.dev_attr.attr, 24278c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset9.dev_attr.attr, 24288c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset10.dev_attr.attr, 24298c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset11.dev_attr.attr, 24308c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset12.dev_attr.attr, 24318c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset1.dev_attr.attr, 24328c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset2.dev_attr.attr, 24338c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset3.dev_attr.attr, 24348c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset4.dev_attr.attr, 24358c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset5.dev_attr.attr, 24368c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset6.dev_attr.attr, 24378c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset7.dev_attr.attr, 24388c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset8.dev_attr.attr, 24398c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset9.dev_attr.attr, 24408c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset10.dev_attr.attr, 24418c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset11.dev_attr.attr, 24428c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset12.dev_attr.attr, 24438c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr, 24448c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr, 24458c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr, 24468c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr, 24478c2ecf20Sopenharmony_ci &sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr, 24488c2ecf20Sopenharmony_ci &sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr, 24498c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_input.dev_attr.attr, 24508c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_input.dev_attr.attr, 24518c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_input.dev_attr.attr, 24528c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_input.dev_attr.attr, 24538c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_min.dev_attr.attr, 24548c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_min.dev_attr.attr, 24558c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_min.dev_attr.attr, 24568c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_min.dev_attr.attr, 24578c2ecf20Sopenharmony_ci &sensor_dev_attr_fan1_smart_tach.dev_attr.attr, 24588c2ecf20Sopenharmony_ci &sensor_dev_attr_fan2_smart_tach.dev_attr.attr, 24598c2ecf20Sopenharmony_ci &sensor_dev_attr_fan3_smart_tach.dev_attr.attr, 24608c2ecf20Sopenharmony_ci &sensor_dev_attr_fan4_smart_tach.dev_attr.attr, 24618c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1.dev_attr.attr, 24628c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2.dev_attr.attr, 24638c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_enable.dev_attr.attr, 24648c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_enable.dev_attr.attr, 24658c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_freq.dev_attr.attr, 24668c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_freq.dev_attr.attr, 24678c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr, 24688c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr, 24698c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr, 24708c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr, 24718c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr, 24728c2ecf20Sopenharmony_ci &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr, 24738c2ecf20Sopenharmony_ci &dev_attr_pwm_auto_prochot_ramp.attr, 24748c2ecf20Sopenharmony_ci &dev_attr_pwm_auto_vrdhot_ramp.attr, 24758c2ecf20Sopenharmony_ci &sensor_dev_attr_cpu0_vid.dev_attr.attr, 24768c2ecf20Sopenharmony_ci &sensor_dev_attr_cpu1_vid.dev_attr.attr, 24778c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot1.dev_attr.attr, 24788c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot2.dev_attr.attr, 24798c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot1_avg.dev_attr.attr, 24808c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot2_avg.dev_attr.attr, 24818c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot1_max.dev_attr.attr, 24828c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot2_max.dev_attr.attr, 24838c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot1_override.dev_attr.attr, 24848c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot2_override.dev_attr.attr, 24858c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot1_interval.dev_attr.attr, 24868c2ecf20Sopenharmony_ci &sensor_dev_attr_prochot2_interval.dev_attr.attr, 24878c2ecf20Sopenharmony_ci &dev_attr_prochot_override_duty_cycle.attr, 24888c2ecf20Sopenharmony_ci &dev_attr_prochot_short.attr, 24898c2ecf20Sopenharmony_ci &sensor_dev_attr_vrdhot1.dev_attr.attr, 24908c2ecf20Sopenharmony_ci &sensor_dev_attr_vrdhot2.dev_attr.attr, 24918c2ecf20Sopenharmony_ci &dev_attr_gpio.attr, 24928c2ecf20Sopenharmony_ci &dev_attr_alarms.attr, 24938c2ecf20Sopenharmony_ci NULL 24948c2ecf20Sopenharmony_ci}; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(lm93); 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_cistatic void lm93_init_client(struct i2c_client *client) 24998c2ecf20Sopenharmony_ci{ 25008c2ecf20Sopenharmony_ci int i; 25018c2ecf20Sopenharmony_ci u8 reg; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci /* configure VID pin input thresholds */ 25048c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL); 25058c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_GPI_VID_CTL, 25068c2ecf20Sopenharmony_ci reg | (vid_agtl ? 0x03 : 0x00)); 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci if (init) { 25098c2ecf20Sopenharmony_ci /* enable #ALERT pin */ 25108c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_CONFIG); 25118c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* enable ASF mode for BMC status registers */ 25148c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL); 25158c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02); 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci /* set sleep state to S0 */ 25188c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0); 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci /* unmask #VRDHOT and dynamic VCCP (if nec) error events */ 25218c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK); 25228c2ecf20Sopenharmony_ci reg &= ~0x03; 25238c2ecf20Sopenharmony_ci reg &= ~(vccp_limit_type[0] ? 0x10 : 0); 25248c2ecf20Sopenharmony_ci reg &= ~(vccp_limit_type[1] ? 0x20 : 0); 25258c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg); 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci /* start monitoring */ 25298c2ecf20Sopenharmony_ci reg = lm93_read_byte(client, LM93_REG_CONFIG); 25308c2ecf20Sopenharmony_ci lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci /* spin until ready */ 25338c2ecf20Sopenharmony_ci for (i = 0; i < 20; i++) { 25348c2ecf20Sopenharmony_ci msleep(10); 25358c2ecf20Sopenharmony_ci if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80) 25368c2ecf20Sopenharmony_ci return; 25378c2ecf20Sopenharmony_ci } 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci dev_warn(&client->dev, 25408c2ecf20Sopenharmony_ci "timed out waiting for sensor chip to signal ready!\n"); 25418c2ecf20Sopenharmony_ci} 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */ 25448c2ecf20Sopenharmony_cistatic int lm93_detect(struct i2c_client *client, struct i2c_board_info *info) 25458c2ecf20Sopenharmony_ci{ 25468c2ecf20Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 25478c2ecf20Sopenharmony_ci int mfr, ver; 25488c2ecf20Sopenharmony_ci const char *name; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci if (!i2c_check_functionality(adapter, LM93_SMBUS_FUNC_MIN)) 25518c2ecf20Sopenharmony_ci return -ENODEV; 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci /* detection */ 25548c2ecf20Sopenharmony_ci mfr = lm93_read_byte(client, LM93_REG_MFR_ID); 25558c2ecf20Sopenharmony_ci if (mfr != 0x01) { 25568c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 25578c2ecf20Sopenharmony_ci "detect failed, bad manufacturer id 0x%02x!\n", mfr); 25588c2ecf20Sopenharmony_ci return -ENODEV; 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci ver = lm93_read_byte(client, LM93_REG_VER); 25628c2ecf20Sopenharmony_ci switch (ver) { 25638c2ecf20Sopenharmony_ci case LM93_MFR_ID: 25648c2ecf20Sopenharmony_ci case LM93_MFR_ID_PROTOTYPE: 25658c2ecf20Sopenharmony_ci name = "lm93"; 25668c2ecf20Sopenharmony_ci break; 25678c2ecf20Sopenharmony_ci case LM94_MFR_ID_2: 25688c2ecf20Sopenharmony_ci case LM94_MFR_ID: 25698c2ecf20Sopenharmony_ci case LM94_MFR_ID_PROTOTYPE: 25708c2ecf20Sopenharmony_ci name = "lm94"; 25718c2ecf20Sopenharmony_ci break; 25728c2ecf20Sopenharmony_ci default: 25738c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, 25748c2ecf20Sopenharmony_ci "detect failed, bad version id 0x%02x!\n", ver); 25758c2ecf20Sopenharmony_ci return -ENODEV; 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci 25788c2ecf20Sopenharmony_ci strlcpy(info->type, name, I2C_NAME_SIZE); 25798c2ecf20Sopenharmony_ci dev_dbg(&adapter->dev, "loading %s at %d, 0x%02x\n", 25808c2ecf20Sopenharmony_ci client->name, i2c_adapter_id(client->adapter), 25818c2ecf20Sopenharmony_ci client->addr); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci return 0; 25848c2ecf20Sopenharmony_ci} 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_cistatic int lm93_probe(struct i2c_client *client) 25878c2ecf20Sopenharmony_ci{ 25888c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 25898c2ecf20Sopenharmony_ci struct lm93_data *data; 25908c2ecf20Sopenharmony_ci struct device *hwmon_dev; 25918c2ecf20Sopenharmony_ci int func; 25928c2ecf20Sopenharmony_ci void (*update)(struct lm93_data *, struct i2c_client *); 25938c2ecf20Sopenharmony_ci 25948c2ecf20Sopenharmony_ci /* choose update routine based on bus capabilities */ 25958c2ecf20Sopenharmony_ci func = i2c_get_functionality(client->adapter); 25968c2ecf20Sopenharmony_ci if (((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) && 25978c2ecf20Sopenharmony_ci (!disable_block)) { 25988c2ecf20Sopenharmony_ci dev_dbg(dev, "using SMBus block data transactions\n"); 25998c2ecf20Sopenharmony_ci update = lm93_update_client_full; 26008c2ecf20Sopenharmony_ci } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) { 26018c2ecf20Sopenharmony_ci dev_dbg(dev, "disabled SMBus block data transactions\n"); 26028c2ecf20Sopenharmony_ci update = lm93_update_client_min; 26038c2ecf20Sopenharmony_ci } else { 26048c2ecf20Sopenharmony_ci dev_dbg(dev, "detect failed, smbus byte and/or word data not supported!\n"); 26058c2ecf20Sopenharmony_ci return -ENODEV; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci data = devm_kzalloc(dev, sizeof(struct lm93_data), GFP_KERNEL); 26098c2ecf20Sopenharmony_ci if (!data) 26108c2ecf20Sopenharmony_ci return -ENOMEM; 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci /* housekeeping */ 26138c2ecf20Sopenharmony_ci data->client = client; 26148c2ecf20Sopenharmony_ci data->update = update; 26158c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci /* initialize the chip */ 26188c2ecf20Sopenharmony_ci lm93_init_client(client); 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 26218c2ecf20Sopenharmony_ci data, 26228c2ecf20Sopenharmony_ci lm93_groups); 26238c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 26248c2ecf20Sopenharmony_ci} 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm93_id[] = { 26278c2ecf20Sopenharmony_ci { "lm93", 0 }, 26288c2ecf20Sopenharmony_ci { "lm94", 0 }, 26298c2ecf20Sopenharmony_ci { } 26308c2ecf20Sopenharmony_ci}; 26318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm93_id); 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_cistatic struct i2c_driver lm93_driver = { 26348c2ecf20Sopenharmony_ci .class = I2C_CLASS_HWMON, 26358c2ecf20Sopenharmony_ci .driver = { 26368c2ecf20Sopenharmony_ci .name = "lm93", 26378c2ecf20Sopenharmony_ci }, 26388c2ecf20Sopenharmony_ci .probe_new = lm93_probe, 26398c2ecf20Sopenharmony_ci .id_table = lm93_id, 26408c2ecf20Sopenharmony_ci .detect = lm93_detect, 26418c2ecf20Sopenharmony_ci .address_list = normal_i2c, 26428c2ecf20Sopenharmony_ci}; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_cimodule_i2c_driver(lm93_driver); 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, " 26478c2ecf20Sopenharmony_ci "Hans J. Koch <hjk@hansjkoch.de>"); 26488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM93 driver"); 26498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2650