xref: /kernel/linux/linux-5.10/drivers/hwmon/lm93.c (revision 8c2ecf20)
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