162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  w83795.c - Linux kernel driver for hardware monitoring
462306a36Sopenharmony_ci *  Copyright (C) 2008 Nuvoton Technology Corp.
562306a36Sopenharmony_ci *                Wei Song
662306a36Sopenharmony_ci *  Copyright (C) 2010 Jean Delvare <jdelvare@suse.de>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  Supports following chips:
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci *  Chip       #vin   #fanin #pwm #temp #dts wchipid  vendid  i2c  ISA
1162306a36Sopenharmony_ci *  w83795g     21     14     8     6     8    0x79   0x5ca3  yes   no
1262306a36Sopenharmony_ci *  w83795adg   18     14     2     6     8    0x79   0x5ca3  yes   no
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/i2c.h>
2062306a36Sopenharmony_ci#include <linux/hwmon.h>
2162306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h>
2262306a36Sopenharmony_ci#include <linux/err.h>
2362306a36Sopenharmony_ci#include <linux/mutex.h>
2462306a36Sopenharmony_ci#include <linux/jiffies.h>
2562306a36Sopenharmony_ci#include <linux/util_macros.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Addresses to scan */
2862306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = {
2962306a36Sopenharmony_ci	0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic bool reset;
3462306a36Sopenharmony_cimodule_param(reset, bool, 0);
3562306a36Sopenharmony_ciMODULE_PARM_DESC(reset, "Set to 1 to reset chip, not recommended");
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define W83795_REG_BANKSEL		0x00
3962306a36Sopenharmony_ci#define W83795_REG_VENDORID		0xfd
4062306a36Sopenharmony_ci#define W83795_REG_CHIPID		0xfe
4162306a36Sopenharmony_ci#define W83795_REG_DEVICEID		0xfb
4262306a36Sopenharmony_ci#define W83795_REG_DEVICEID_A		0xff
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define W83795_REG_I2C_ADDR		0xfc
4562306a36Sopenharmony_ci#define W83795_REG_CONFIG		0x01
4662306a36Sopenharmony_ci#define W83795_REG_CONFIG_CONFIG48	0x04
4762306a36Sopenharmony_ci#define W83795_REG_CONFIG_START	0x01
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/* Multi-Function Pin Ctrl Registers */
5062306a36Sopenharmony_ci#define W83795_REG_VOLT_CTRL1		0x02
5162306a36Sopenharmony_ci#define W83795_REG_VOLT_CTRL2		0x03
5262306a36Sopenharmony_ci#define W83795_REG_TEMP_CTRL1		0x04
5362306a36Sopenharmony_ci#define W83795_REG_TEMP_CTRL2		0x05
5462306a36Sopenharmony_ci#define W83795_REG_FANIN_CTRL1		0x06
5562306a36Sopenharmony_ci#define W83795_REG_FANIN_CTRL2		0x07
5662306a36Sopenharmony_ci#define W83795_REG_VMIGB_CTRL		0x08
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define TEMP_READ			0
5962306a36Sopenharmony_ci#define TEMP_CRIT			1
6062306a36Sopenharmony_ci#define TEMP_CRIT_HYST			2
6162306a36Sopenharmony_ci#define TEMP_WARN			3
6262306a36Sopenharmony_ci#define TEMP_WARN_HYST			4
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * only crit and crit_hyst affect real-time alarm status
6562306a36Sopenharmony_ci * current crit crit_hyst warn warn_hyst
6662306a36Sopenharmony_ci */
6762306a36Sopenharmony_cistatic const u16 W83795_REG_TEMP[][5] = {
6862306a36Sopenharmony_ci	{0x21, 0x96, 0x97, 0x98, 0x99},	/* TD1/TR1 */
6962306a36Sopenharmony_ci	{0x22, 0x9a, 0x9b, 0x9c, 0x9d},	/* TD2/TR2 */
7062306a36Sopenharmony_ci	{0x23, 0x9e, 0x9f, 0xa0, 0xa1},	/* TD3/TR3 */
7162306a36Sopenharmony_ci	{0x24, 0xa2, 0xa3, 0xa4, 0xa5},	/* TD4/TR4 */
7262306a36Sopenharmony_ci	{0x1f, 0xa6, 0xa7, 0xa8, 0xa9},	/* TR5 */
7362306a36Sopenharmony_ci	{0x20, 0xaa, 0xab, 0xac, 0xad},	/* TR6 */
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#define IN_READ				0
7762306a36Sopenharmony_ci#define IN_MAX				1
7862306a36Sopenharmony_ci#define IN_LOW				2
7962306a36Sopenharmony_cistatic const u16 W83795_REG_IN[][3] = {
8062306a36Sopenharmony_ci	/* Current, HL, LL */
8162306a36Sopenharmony_ci	{0x10, 0x70, 0x71},	/* VSEN1 */
8262306a36Sopenharmony_ci	{0x11, 0x72, 0x73},	/* VSEN2 */
8362306a36Sopenharmony_ci	{0x12, 0x74, 0x75},	/* VSEN3 */
8462306a36Sopenharmony_ci	{0x13, 0x76, 0x77},	/* VSEN4 */
8562306a36Sopenharmony_ci	{0x14, 0x78, 0x79},	/* VSEN5 */
8662306a36Sopenharmony_ci	{0x15, 0x7a, 0x7b},	/* VSEN6 */
8762306a36Sopenharmony_ci	{0x16, 0x7c, 0x7d},	/* VSEN7 */
8862306a36Sopenharmony_ci	{0x17, 0x7e, 0x7f},	/* VSEN8 */
8962306a36Sopenharmony_ci	{0x18, 0x80, 0x81},	/* VSEN9 */
9062306a36Sopenharmony_ci	{0x19, 0x82, 0x83},	/* VSEN10 */
9162306a36Sopenharmony_ci	{0x1A, 0x84, 0x85},	/* VSEN11 */
9262306a36Sopenharmony_ci	{0x1B, 0x86, 0x87},	/* VTT */
9362306a36Sopenharmony_ci	{0x1C, 0x88, 0x89},	/* 3VDD */
9462306a36Sopenharmony_ci	{0x1D, 0x8a, 0x8b},	/* 3VSB */
9562306a36Sopenharmony_ci	{0x1E, 0x8c, 0x8d},	/* VBAT */
9662306a36Sopenharmony_ci	{0x1F, 0xa6, 0xa7},	/* VSEN12 */
9762306a36Sopenharmony_ci	{0x20, 0xaa, 0xab},	/* VSEN13 */
9862306a36Sopenharmony_ci	{0x21, 0x96, 0x97},	/* VSEN14 */
9962306a36Sopenharmony_ci	{0x22, 0x9a, 0x9b},	/* VSEN15 */
10062306a36Sopenharmony_ci	{0x23, 0x9e, 0x9f},	/* VSEN16 */
10162306a36Sopenharmony_ci	{0x24, 0xa2, 0xa3},	/* VSEN17 */
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci#define W83795_REG_VRLSB		0x3C
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic const u8 W83795_REG_IN_HL_LSB[] = {
10662306a36Sopenharmony_ci	0x8e,	/* VSEN1-4 */
10762306a36Sopenharmony_ci	0x90,	/* VSEN5-8 */
10862306a36Sopenharmony_ci	0x92,	/* VSEN9-11 */
10962306a36Sopenharmony_ci	0x94,	/* VTT, 3VDD, 3VSB, 3VBAT */
11062306a36Sopenharmony_ci	0xa8,	/* VSEN12 */
11162306a36Sopenharmony_ci	0xac,	/* VSEN13 */
11262306a36Sopenharmony_ci	0x98,	/* VSEN14 */
11362306a36Sopenharmony_ci	0x9c,	/* VSEN15 */
11462306a36Sopenharmony_ci	0xa0,	/* VSEN16 */
11562306a36Sopenharmony_ci	0xa4,	/* VSEN17 */
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define IN_LSB_REG(index, type) \
11962306a36Sopenharmony_ci	(((type) == 1) ? W83795_REG_IN_HL_LSB[(index)] \
12062306a36Sopenharmony_ci	: (W83795_REG_IN_HL_LSB[(index)] + 1))
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define IN_LSB_SHIFT			0
12362306a36Sopenharmony_ci#define IN_LSB_IDX			1
12462306a36Sopenharmony_cistatic const u8 IN_LSB_SHIFT_IDX[][2] = {
12562306a36Sopenharmony_ci	/* High/Low LSB shift, LSB No. */
12662306a36Sopenharmony_ci	{0x00, 0x00},	/* VSEN1 */
12762306a36Sopenharmony_ci	{0x02, 0x00},	/* VSEN2 */
12862306a36Sopenharmony_ci	{0x04, 0x00},	/* VSEN3 */
12962306a36Sopenharmony_ci	{0x06, 0x00},	/* VSEN4 */
13062306a36Sopenharmony_ci	{0x00, 0x01},	/* VSEN5 */
13162306a36Sopenharmony_ci	{0x02, 0x01},	/* VSEN6 */
13262306a36Sopenharmony_ci	{0x04, 0x01},	/* VSEN7 */
13362306a36Sopenharmony_ci	{0x06, 0x01},	/* VSEN8 */
13462306a36Sopenharmony_ci	{0x00, 0x02},	/* VSEN9 */
13562306a36Sopenharmony_ci	{0x02, 0x02},	/* VSEN10 */
13662306a36Sopenharmony_ci	{0x04, 0x02},	/* VSEN11 */
13762306a36Sopenharmony_ci	{0x00, 0x03},	/* VTT */
13862306a36Sopenharmony_ci	{0x02, 0x03},	/* 3VDD */
13962306a36Sopenharmony_ci	{0x04, 0x03},	/* 3VSB	*/
14062306a36Sopenharmony_ci	{0x06, 0x03},	/* VBAT	*/
14162306a36Sopenharmony_ci	{0x06, 0x04},	/* VSEN12 */
14262306a36Sopenharmony_ci	{0x06, 0x05},	/* VSEN13 */
14362306a36Sopenharmony_ci	{0x06, 0x06},	/* VSEN14 */
14462306a36Sopenharmony_ci	{0x06, 0x07},	/* VSEN15 */
14562306a36Sopenharmony_ci	{0x06, 0x08},	/* VSEN16 */
14662306a36Sopenharmony_ci	{0x06, 0x09},	/* VSEN17 */
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#define W83795_REG_FAN(index)		(0x2E + (index))
15162306a36Sopenharmony_ci#define W83795_REG_FAN_MIN_HL(index)	(0xB6 + (index))
15262306a36Sopenharmony_ci#define W83795_REG_FAN_MIN_LSB(index)	(0xC4 + (index) / 2)
15362306a36Sopenharmony_ci#define W83795_REG_FAN_MIN_LSB_SHIFT(index) \
15462306a36Sopenharmony_ci	(((index) & 1) ? 4 : 0)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define W83795_REG_VID_CTRL		0x6A
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci#define W83795_REG_ALARM_CTRL		0x40
15962306a36Sopenharmony_ci#define ALARM_CTRL_RTSACS		(1 << 7)
16062306a36Sopenharmony_ci#define W83795_REG_ALARM(index)		(0x41 + (index))
16162306a36Sopenharmony_ci#define W83795_REG_CLR_CHASSIS		0x4D
16262306a36Sopenharmony_ci#define W83795_REG_BEEP(index)		(0x50 + (index))
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define W83795_REG_OVT_CFG		0x58
16562306a36Sopenharmony_ci#define OVT_CFG_SEL			(1 << 7)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci#define W83795_REG_FCMS1		0x201
16962306a36Sopenharmony_ci#define W83795_REG_FCMS2		0x208
17062306a36Sopenharmony_ci#define W83795_REG_TFMR(index)		(0x202 + (index))
17162306a36Sopenharmony_ci#define W83795_REG_FOMC			0x20F
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define W83795_REG_TSS(index)		(0x209 + (index))
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define TSS_MAP_RESERVED		0xff
17662306a36Sopenharmony_cistatic const u8 tss_map[4][6] = {
17762306a36Sopenharmony_ci	{ 0,  1,  2,  3,  4,  5},
17862306a36Sopenharmony_ci	{ 6,  7,  8,  9,  0,  1},
17962306a36Sopenharmony_ci	{10, 11, 12, 13,  2,  3},
18062306a36Sopenharmony_ci	{ 4,  5,  4,  5, TSS_MAP_RESERVED, TSS_MAP_RESERVED},
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define PWM_OUTPUT			0
18462306a36Sopenharmony_ci#define PWM_FREQ			1
18562306a36Sopenharmony_ci#define PWM_START			2
18662306a36Sopenharmony_ci#define PWM_NONSTOP			3
18762306a36Sopenharmony_ci#define PWM_STOP_TIME			4
18862306a36Sopenharmony_ci#define W83795_REG_PWM(index, nr)	(0x210 + (nr) * 8 + (index))
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci#define W83795_REG_FTSH(index)		(0x240 + (index) * 2)
19162306a36Sopenharmony_ci#define W83795_REG_FTSL(index)		(0x241 + (index) * 2)
19262306a36Sopenharmony_ci#define W83795_REG_TFTS			0x250
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci#define TEMP_PWM_TTTI			0
19562306a36Sopenharmony_ci#define TEMP_PWM_CTFS			1
19662306a36Sopenharmony_ci#define TEMP_PWM_HCT			2
19762306a36Sopenharmony_ci#define TEMP_PWM_HOT			3
19862306a36Sopenharmony_ci#define W83795_REG_TTTI(index)		(0x260 + (index))
19962306a36Sopenharmony_ci#define W83795_REG_CTFS(index)		(0x268 + (index))
20062306a36Sopenharmony_ci#define W83795_REG_HT(index)		(0x270 + (index))
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci#define SF4_TEMP			0
20362306a36Sopenharmony_ci#define SF4_PWM				1
20462306a36Sopenharmony_ci#define W83795_REG_SF4_TEMP(temp_num, index) \
20562306a36Sopenharmony_ci	(0x280 + 0x10 * (temp_num) + (index))
20662306a36Sopenharmony_ci#define W83795_REG_SF4_PWM(temp_num, index) \
20762306a36Sopenharmony_ci	(0x288 + 0x10 * (temp_num) + (index))
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define W83795_REG_DTSC			0x301
21062306a36Sopenharmony_ci#define W83795_REG_DTSE			0x302
21162306a36Sopenharmony_ci#define W83795_REG_DTS(index)		(0x26 + (index))
21262306a36Sopenharmony_ci#define W83795_REG_PECI_TBASE(index)	(0x320 + (index))
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci#define DTS_CRIT			0
21562306a36Sopenharmony_ci#define DTS_CRIT_HYST			1
21662306a36Sopenharmony_ci#define DTS_WARN			2
21762306a36Sopenharmony_ci#define DTS_WARN_HYST			3
21862306a36Sopenharmony_ci#define W83795_REG_DTS_EXT(index)	(0xB2 + (index))
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#define SETUP_PWM_DEFAULT		0
22162306a36Sopenharmony_ci#define SETUP_PWM_UPTIME		1
22262306a36Sopenharmony_ci#define SETUP_PWM_DOWNTIME		2
22362306a36Sopenharmony_ci#define W83795_REG_SETUP_PWM(index)    (0x20C + (index))
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic inline u16 in_from_reg(u8 index, u16 val)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	/* 3VDD, 3VSB and VBAT: 6 mV/bit; other inputs: 2 mV/bit */
22862306a36Sopenharmony_ci	if (index >= 12 && index <= 14)
22962306a36Sopenharmony_ci		return val * 6;
23062306a36Sopenharmony_ci	else
23162306a36Sopenharmony_ci		return val * 2;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic inline u16 in_to_reg(u8 index, u16 val)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	if (index >= 12 && index <= 14)
23762306a36Sopenharmony_ci		return val / 6;
23862306a36Sopenharmony_ci	else
23962306a36Sopenharmony_ci		return val / 2;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic inline unsigned long fan_from_reg(u16 val)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	if ((val == 0xfff) || (val == 0))
24562306a36Sopenharmony_ci		return 0;
24662306a36Sopenharmony_ci	return 1350000UL / val;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic inline u16 fan_to_reg(long rpm)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	if (rpm <= 0)
25262306a36Sopenharmony_ci		return 0x0fff;
25362306a36Sopenharmony_ci	return clamp_val((1350000 + (rpm >> 1)) / rpm, 1, 0xffe);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic inline unsigned long time_from_reg(u8 reg)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	return reg * 100;
25962306a36Sopenharmony_ci}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_cistatic inline u8 time_to_reg(unsigned long val)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	return clamp_val((val + 50) / 100, 0, 0xff);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic inline long temp_from_reg(s8 reg)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	return reg * 1000;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic inline s8 temp_to_reg(long val, s8 min, s8 max)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	return clamp_val(val / 1000, min, max);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic const u16 pwm_freq_cksel0[16] = {
27762306a36Sopenharmony_ci	1024, 512, 341, 256, 205, 171, 146, 128,
27862306a36Sopenharmony_ci	85, 64, 32, 16, 8, 4, 2, 1
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic unsigned int pwm_freq_from_reg(u8 reg, u16 clkin)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	unsigned long base_clock;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (reg & 0x80) {
28662306a36Sopenharmony_ci		base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
28762306a36Sopenharmony_ci		return base_clock / ((reg & 0x7f) + 1);
28862306a36Sopenharmony_ci	} else
28962306a36Sopenharmony_ci		return pwm_freq_cksel0[reg & 0x0f];
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	unsigned long base_clock;
29562306a36Sopenharmony_ci	u8 reg0, reg1;
29662306a36Sopenharmony_ci	unsigned long best0, best1;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Best fit for cksel = 0 */
29962306a36Sopenharmony_ci	reg0 = find_closest_descending(val, pwm_freq_cksel0,
30062306a36Sopenharmony_ci				       ARRAY_SIZE(pwm_freq_cksel0));
30162306a36Sopenharmony_ci	if (val < 375)	/* cksel = 1 can't beat this */
30262306a36Sopenharmony_ci		return reg0;
30362306a36Sopenharmony_ci	best0 = pwm_freq_cksel0[reg0];
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Best fit for cksel = 1 */
30662306a36Sopenharmony_ci	base_clock = clkin * 1000 / ((clkin == 48000) ? 384 : 256);
30762306a36Sopenharmony_ci	reg1 = clamp_val(DIV_ROUND_CLOSEST(base_clock, val), 1, 128);
30862306a36Sopenharmony_ci	best1 = base_clock / reg1;
30962306a36Sopenharmony_ci	reg1 = 0x80 | (reg1 - 1);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Choose the closest one */
31262306a36Sopenharmony_ci	if (abs(val - best0) > abs(val - best1))
31362306a36Sopenharmony_ci		return reg1;
31462306a36Sopenharmony_ci	else
31562306a36Sopenharmony_ci		return reg0;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cienum chip_types {w83795g, w83795adg};
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistruct w83795_data {
32162306a36Sopenharmony_ci	struct device *hwmon_dev;
32262306a36Sopenharmony_ci	struct mutex update_lock;
32362306a36Sopenharmony_ci	unsigned long last_updated;	/* In jiffies */
32462306a36Sopenharmony_ci	enum chip_types chip_type;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	u8 bank;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	u32 has_in;		/* Enable monitor VIN or not */
32962306a36Sopenharmony_ci	u8 has_dyn_in;		/* Only in2-0 can have this */
33062306a36Sopenharmony_ci	u16 in[21][3];		/* Register value, read/high/low */
33162306a36Sopenharmony_ci	u8 in_lsb[10][3];	/* LSB Register value, high/low */
33262306a36Sopenharmony_ci	u8 has_gain;		/* has gain: in17-20 * 8 */
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	u16 has_fan;		/* Enable fan14-1 or not */
33562306a36Sopenharmony_ci	u16 fan[14];		/* Register value combine */
33662306a36Sopenharmony_ci	u16 fan_min[14];	/* Register value combine */
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	u8 has_temp;		/* Enable monitor temp6-1 or not */
33962306a36Sopenharmony_ci	s8 temp[6][5];		/* current, crit, crit_hyst, warn, warn_hyst */
34062306a36Sopenharmony_ci	u8 temp_read_vrlsb[6];
34162306a36Sopenharmony_ci	u8 temp_mode;		/* Bit vector, 0 = TR, 1 = TD */
34262306a36Sopenharmony_ci	u8 temp_src[3];		/* Register value */
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	u8 enable_dts;		/*
34562306a36Sopenharmony_ci				 * Enable PECI and SB-TSI,
34662306a36Sopenharmony_ci				 * bit 0: =1 enable, =0 disable,
34762306a36Sopenharmony_ci				 * bit 1: =1 AMD SB-TSI, =0 Intel PECI
34862306a36Sopenharmony_ci				 */
34962306a36Sopenharmony_ci	u8 has_dts;		/* Enable monitor DTS temp */
35062306a36Sopenharmony_ci	s8 dts[8];		/* Register value */
35162306a36Sopenharmony_ci	u8 dts_read_vrlsb[8];	/* Register value */
35262306a36Sopenharmony_ci	s8 dts_ext[4];		/* Register value */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	u8 has_pwm;		/*
35562306a36Sopenharmony_ci				 * 795g supports 8 pwm, 795adg only supports 2,
35662306a36Sopenharmony_ci				 * no config register, only affected by chip
35762306a36Sopenharmony_ci				 * type
35862306a36Sopenharmony_ci				 */
35962306a36Sopenharmony_ci	u8 pwm[8][5];		/*
36062306a36Sopenharmony_ci				 * Register value, output, freq, start,
36162306a36Sopenharmony_ci				 *  non stop, stop time
36262306a36Sopenharmony_ci				 */
36362306a36Sopenharmony_ci	u16 clkin;		/* CLKIN frequency in kHz */
36462306a36Sopenharmony_ci	u8 pwm_fcms[2];		/* Register value */
36562306a36Sopenharmony_ci	u8 pwm_tfmr[6];		/* Register value */
36662306a36Sopenharmony_ci	u8 pwm_fomc;		/* Register value */
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	u16 target_speed[8];	/*
36962306a36Sopenharmony_ci				 * Register value, target speed for speed
37062306a36Sopenharmony_ci				 * cruise
37162306a36Sopenharmony_ci				 */
37262306a36Sopenharmony_ci	u8 tol_speed;		/* tolerance of target speed */
37362306a36Sopenharmony_ci	u8 pwm_temp[6][4];	/* TTTI, CTFS, HCT, HOT */
37462306a36Sopenharmony_ci	u8 sf4_reg[6][2][7];	/* 6 temp, temp/dcpwm, 7 registers */
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	u8 setup_pwm[3];	/* Register value */
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	u8 alarms[6];		/* Register value */
37962306a36Sopenharmony_ci	u8 enable_beep;
38062306a36Sopenharmony_ci	u8 beeps[6];		/* Register value */
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	bool valid;
38362306a36Sopenharmony_ci	char valid_limits;
38462306a36Sopenharmony_ci	char valid_pwm_config;
38562306a36Sopenharmony_ci};
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/*
38862306a36Sopenharmony_ci * Hardware access
38962306a36Sopenharmony_ci * We assume that nobdody can change the bank outside the driver.
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */
39362306a36Sopenharmony_cistatic int w83795_set_bank(struct i2c_client *client, u8 bank)
39462306a36Sopenharmony_ci{
39562306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
39662306a36Sopenharmony_ci	int err;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* If the same bank is already set, nothing to do */
39962306a36Sopenharmony_ci	if ((data->bank & 0x07) == bank)
40062306a36Sopenharmony_ci		return 0;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Change to new bank, preserve all other bits */
40362306a36Sopenharmony_ci	bank |= data->bank & ~0x07;
40462306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL, bank);
40562306a36Sopenharmony_ci	if (err < 0) {
40662306a36Sopenharmony_ci		dev_err(&client->dev,
40762306a36Sopenharmony_ci			"Failed to set bank to %d, err %d\n",
40862306a36Sopenharmony_ci			(int)bank, err);
40962306a36Sopenharmony_ci		return err;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	data->bank = bank;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	return 0;
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */
41762306a36Sopenharmony_cistatic u8 w83795_read(struct i2c_client *client, u16 reg)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	int err;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	err = w83795_set_bank(client, reg >> 8);
42262306a36Sopenharmony_ci	if (err < 0)
42362306a36Sopenharmony_ci		return 0x00;	/* Arbitrary */
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	err = i2c_smbus_read_byte_data(client, reg & 0xff);
42662306a36Sopenharmony_ci	if (err < 0) {
42762306a36Sopenharmony_ci		dev_err(&client->dev,
42862306a36Sopenharmony_ci			"Failed to read from register 0x%03x, err %d\n",
42962306a36Sopenharmony_ci			(int)reg, err);
43062306a36Sopenharmony_ci		return 0x00;	/* Arbitrary */
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	return err;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci/* Must be called with data->update_lock held, except during initialization */
43662306a36Sopenharmony_cistatic int w83795_write(struct i2c_client *client, u16 reg, u8 value)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	int err;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	err = w83795_set_bank(client, reg >> 8);
44162306a36Sopenharmony_ci	if (err < 0)
44262306a36Sopenharmony_ci		return err;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, reg & 0xff, value);
44562306a36Sopenharmony_ci	if (err < 0)
44662306a36Sopenharmony_ci		dev_err(&client->dev,
44762306a36Sopenharmony_ci			"Failed to write to register 0x%03x, err %d\n",
44862306a36Sopenharmony_ci			(int)reg, err);
44962306a36Sopenharmony_ci	return err;
45062306a36Sopenharmony_ci}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic void w83795_update_limits(struct i2c_client *client)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
45562306a36Sopenharmony_ci	int i, limit;
45662306a36Sopenharmony_ci	u8 lsb;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* Read the voltage limits */
45962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
46062306a36Sopenharmony_ci		if (!(data->has_in & (1 << i)))
46162306a36Sopenharmony_ci			continue;
46262306a36Sopenharmony_ci		data->in[i][IN_MAX] =
46362306a36Sopenharmony_ci			w83795_read(client, W83795_REG_IN[i][IN_MAX]);
46462306a36Sopenharmony_ci		data->in[i][IN_LOW] =
46562306a36Sopenharmony_ci			w83795_read(client, W83795_REG_IN[i][IN_LOW]);
46662306a36Sopenharmony_ci	}
46762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->in_lsb); i++) {
46862306a36Sopenharmony_ci		if ((i == 2 && data->chip_type == w83795adg) ||
46962306a36Sopenharmony_ci		    (i >= 4 && !(data->has_in & (1 << (i + 11)))))
47062306a36Sopenharmony_ci			continue;
47162306a36Sopenharmony_ci		data->in_lsb[i][IN_MAX] =
47262306a36Sopenharmony_ci			w83795_read(client, IN_LSB_REG(i, IN_MAX));
47362306a36Sopenharmony_ci		data->in_lsb[i][IN_LOW] =
47462306a36Sopenharmony_ci			w83795_read(client, IN_LSB_REG(i, IN_LOW));
47562306a36Sopenharmony_ci	}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Read the fan limits */
47862306a36Sopenharmony_ci	lsb = 0; /* Silent false gcc warning */
47962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
48062306a36Sopenharmony_ci		/*
48162306a36Sopenharmony_ci		 * Each register contains LSB for 2 fans, but we want to
48262306a36Sopenharmony_ci		 * read it only once to save time
48362306a36Sopenharmony_ci		 */
48462306a36Sopenharmony_ci		if ((i & 1) == 0 && (data->has_fan & (3 << i)))
48562306a36Sopenharmony_ci			lsb = w83795_read(client, W83795_REG_FAN_MIN_LSB(i));
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		if (!(data->has_fan & (1 << i)))
48862306a36Sopenharmony_ci			continue;
48962306a36Sopenharmony_ci		data->fan_min[i] =
49062306a36Sopenharmony_ci			w83795_read(client, W83795_REG_FAN_MIN_HL(i)) << 4;
49162306a36Sopenharmony_ci		data->fan_min[i] |=
49262306a36Sopenharmony_ci			(lsb >> W83795_REG_FAN_MIN_LSB_SHIFT(i)) & 0x0F;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Read the temperature limits */
49662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
49762306a36Sopenharmony_ci		if (!(data->has_temp & (1 << i)))
49862306a36Sopenharmony_ci			continue;
49962306a36Sopenharmony_ci		for (limit = TEMP_CRIT; limit <= TEMP_WARN_HYST; limit++)
50062306a36Sopenharmony_ci			data->temp[i][limit] =
50162306a36Sopenharmony_ci				w83795_read(client, W83795_REG_TEMP[i][limit]);
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* Read the DTS limits */
50562306a36Sopenharmony_ci	if (data->enable_dts) {
50662306a36Sopenharmony_ci		for (limit = DTS_CRIT; limit <= DTS_WARN_HYST; limit++)
50762306a36Sopenharmony_ci			data->dts_ext[limit] =
50862306a36Sopenharmony_ci				w83795_read(client, W83795_REG_DTS_EXT(limit));
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Read beep settings */
51262306a36Sopenharmony_ci	if (data->enable_beep) {
51362306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(data->beeps); i++)
51462306a36Sopenharmony_ci			data->beeps[i] =
51562306a36Sopenharmony_ci				w83795_read(client, W83795_REG_BEEP(i));
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	data->valid_limits = 1;
51962306a36Sopenharmony_ci}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic struct w83795_data *w83795_update_pwm_config(struct device *dev)
52262306a36Sopenharmony_ci{
52362306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
52462306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
52562306a36Sopenharmony_ci	int i, tmp;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (data->valid_pwm_config)
53062306a36Sopenharmony_ci		goto END;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* Read temperature source selection */
53362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->temp_src); i++)
53462306a36Sopenharmony_ci		data->temp_src[i] = w83795_read(client, W83795_REG_TSS(i));
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Read automatic fan speed control settings */
53762306a36Sopenharmony_ci	data->pwm_fcms[0] = w83795_read(client, W83795_REG_FCMS1);
53862306a36Sopenharmony_ci	data->pwm_fcms[1] = w83795_read(client, W83795_REG_FCMS2);
53962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->pwm_tfmr); i++)
54062306a36Sopenharmony_ci		data->pwm_tfmr[i] = w83795_read(client, W83795_REG_TFMR(i));
54162306a36Sopenharmony_ci	data->pwm_fomc = w83795_read(client, W83795_REG_FOMC);
54262306a36Sopenharmony_ci	for (i = 0; i < data->has_pwm; i++) {
54362306a36Sopenharmony_ci		for (tmp = PWM_FREQ; tmp <= PWM_STOP_TIME; tmp++)
54462306a36Sopenharmony_ci			data->pwm[i][tmp] =
54562306a36Sopenharmony_ci				w83795_read(client, W83795_REG_PWM(i, tmp));
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->target_speed); i++) {
54862306a36Sopenharmony_ci		data->target_speed[i] =
54962306a36Sopenharmony_ci			w83795_read(client, W83795_REG_FTSH(i)) << 4;
55062306a36Sopenharmony_ci		data->target_speed[i] |=
55162306a36Sopenharmony_ci			w83795_read(client, W83795_REG_FTSL(i)) >> 4;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	data->tol_speed = w83795_read(client, W83795_REG_TFTS) & 0x3f;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->pwm_temp); i++) {
55662306a36Sopenharmony_ci		data->pwm_temp[i][TEMP_PWM_TTTI] =
55762306a36Sopenharmony_ci			w83795_read(client, W83795_REG_TTTI(i)) & 0x7f;
55862306a36Sopenharmony_ci		data->pwm_temp[i][TEMP_PWM_CTFS] =
55962306a36Sopenharmony_ci			w83795_read(client, W83795_REG_CTFS(i));
56062306a36Sopenharmony_ci		tmp = w83795_read(client, W83795_REG_HT(i));
56162306a36Sopenharmony_ci		data->pwm_temp[i][TEMP_PWM_HCT] = tmp >> 4;
56262306a36Sopenharmony_ci		data->pwm_temp[i][TEMP_PWM_HOT] = tmp & 0x0f;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* Read SmartFanIV trip points */
56662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->sf4_reg); i++) {
56762306a36Sopenharmony_ci		for (tmp = 0; tmp < 7; tmp++) {
56862306a36Sopenharmony_ci			data->sf4_reg[i][SF4_TEMP][tmp] =
56962306a36Sopenharmony_ci				w83795_read(client,
57062306a36Sopenharmony_ci					    W83795_REG_SF4_TEMP(i, tmp));
57162306a36Sopenharmony_ci			data->sf4_reg[i][SF4_PWM][tmp] =
57262306a36Sopenharmony_ci				w83795_read(client, W83795_REG_SF4_PWM(i, tmp));
57362306a36Sopenharmony_ci		}
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	/* Read setup PWM */
57762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->setup_pwm); i++)
57862306a36Sopenharmony_ci		data->setup_pwm[i] =
57962306a36Sopenharmony_ci			w83795_read(client, W83795_REG_SETUP_PWM(i));
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	data->valid_pwm_config = 1;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ciEND:
58462306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
58562306a36Sopenharmony_ci	return data;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic struct w83795_data *w83795_update_device(struct device *dev)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
59162306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
59262306a36Sopenharmony_ci	u16 tmp;
59362306a36Sopenharmony_ci	u8 intrusion;
59462306a36Sopenharmony_ci	int i;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (!data->valid_limits)
59962306a36Sopenharmony_ci		w83795_update_limits(client);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (!(time_after(jiffies, data->last_updated + HZ * 2)
60262306a36Sopenharmony_ci	      || !data->valid))
60362306a36Sopenharmony_ci		goto END;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* Update the voltages value */
60662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->in); i++) {
60762306a36Sopenharmony_ci		if (!(data->has_in & (1 << i)))
60862306a36Sopenharmony_ci			continue;
60962306a36Sopenharmony_ci		tmp = w83795_read(client, W83795_REG_IN[i][IN_READ]) << 2;
61062306a36Sopenharmony_ci		tmp |= w83795_read(client, W83795_REG_VRLSB) >> 6;
61162306a36Sopenharmony_ci		data->in[i][IN_READ] = tmp;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	/* in0-2 can have dynamic limits (W83795G only) */
61562306a36Sopenharmony_ci	if (data->has_dyn_in) {
61662306a36Sopenharmony_ci		u8 lsb_max = w83795_read(client, IN_LSB_REG(0, IN_MAX));
61762306a36Sopenharmony_ci		u8 lsb_low = w83795_read(client, IN_LSB_REG(0, IN_LOW));
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
62062306a36Sopenharmony_ci			if (!(data->has_dyn_in & (1 << i)))
62162306a36Sopenharmony_ci				continue;
62262306a36Sopenharmony_ci			data->in[i][IN_MAX] =
62362306a36Sopenharmony_ci				w83795_read(client, W83795_REG_IN[i][IN_MAX]);
62462306a36Sopenharmony_ci			data->in[i][IN_LOW] =
62562306a36Sopenharmony_ci				w83795_read(client, W83795_REG_IN[i][IN_LOW]);
62662306a36Sopenharmony_ci			data->in_lsb[i][IN_MAX] = (lsb_max >> (2 * i)) & 0x03;
62762306a36Sopenharmony_ci			data->in_lsb[i][IN_LOW] = (lsb_low >> (2 * i)) & 0x03;
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	/* Update fan */
63262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->fan); i++) {
63362306a36Sopenharmony_ci		if (!(data->has_fan & (1 << i)))
63462306a36Sopenharmony_ci			continue;
63562306a36Sopenharmony_ci		data->fan[i] = w83795_read(client, W83795_REG_FAN(i)) << 4;
63662306a36Sopenharmony_ci		data->fan[i] |= w83795_read(client, W83795_REG_VRLSB) >> 4;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* Update temperature */
64062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
64162306a36Sopenharmony_ci		data->temp[i][TEMP_READ] =
64262306a36Sopenharmony_ci			w83795_read(client, W83795_REG_TEMP[i][TEMP_READ]);
64362306a36Sopenharmony_ci		data->temp_read_vrlsb[i] =
64462306a36Sopenharmony_ci			w83795_read(client, W83795_REG_VRLSB);
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* Update dts temperature */
64862306a36Sopenharmony_ci	if (data->enable_dts) {
64962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(data->dts); i++) {
65062306a36Sopenharmony_ci			if (!(data->has_dts & (1 << i)))
65162306a36Sopenharmony_ci				continue;
65262306a36Sopenharmony_ci			data->dts[i] =
65362306a36Sopenharmony_ci				w83795_read(client, W83795_REG_DTS(i));
65462306a36Sopenharmony_ci			data->dts_read_vrlsb[i] =
65562306a36Sopenharmony_ci				w83795_read(client, W83795_REG_VRLSB);
65662306a36Sopenharmony_ci		}
65762306a36Sopenharmony_ci	}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* Update pwm output */
66062306a36Sopenharmony_ci	for (i = 0; i < data->has_pwm; i++) {
66162306a36Sopenharmony_ci		data->pwm[i][PWM_OUTPUT] =
66262306a36Sopenharmony_ci		    w83795_read(client, W83795_REG_PWM(i, PWM_OUTPUT));
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * Update intrusion and alarms
66762306a36Sopenharmony_ci	 * It is important to read intrusion first, because reading from
66862306a36Sopenharmony_ci	 * register SMI STS6 clears the interrupt status temporarily.
66962306a36Sopenharmony_ci	 */
67062306a36Sopenharmony_ci	tmp = w83795_read(client, W83795_REG_ALARM_CTRL);
67162306a36Sopenharmony_ci	/* Switch to interrupt status for intrusion if needed */
67262306a36Sopenharmony_ci	if (tmp & ALARM_CTRL_RTSACS)
67362306a36Sopenharmony_ci		w83795_write(client, W83795_REG_ALARM_CTRL,
67462306a36Sopenharmony_ci			     tmp & ~ALARM_CTRL_RTSACS);
67562306a36Sopenharmony_ci	intrusion = w83795_read(client, W83795_REG_ALARM(5)) & (1 << 6);
67662306a36Sopenharmony_ci	/* Switch to real-time alarms */
67762306a36Sopenharmony_ci	w83795_write(client, W83795_REG_ALARM_CTRL, tmp | ALARM_CTRL_RTSACS);
67862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data->alarms); i++)
67962306a36Sopenharmony_ci		data->alarms[i] = w83795_read(client, W83795_REG_ALARM(i));
68062306a36Sopenharmony_ci	data->alarms[5] |= intrusion;
68162306a36Sopenharmony_ci	/* Restore original configuration if needed */
68262306a36Sopenharmony_ci	if (!(tmp & ALARM_CTRL_RTSACS))
68362306a36Sopenharmony_ci		w83795_write(client, W83795_REG_ALARM_CTRL,
68462306a36Sopenharmony_ci			     tmp & ~ALARM_CTRL_RTSACS);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	data->last_updated = jiffies;
68762306a36Sopenharmony_ci	data->valid = true;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ciEND:
69062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
69162306a36Sopenharmony_ci	return data;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/*
69562306a36Sopenharmony_ci * Sysfs attributes
69662306a36Sopenharmony_ci */
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci#define ALARM_STATUS      0
69962306a36Sopenharmony_ci#define BEEP_ENABLE       1
70062306a36Sopenharmony_cistatic ssize_t
70162306a36Sopenharmony_cishow_alarm_beep(struct device *dev, struct device_attribute *attr, char *buf)
70262306a36Sopenharmony_ci{
70362306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_device(dev);
70462306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
70562306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
70662306a36Sopenharmony_ci	int nr = sensor_attr->nr;
70762306a36Sopenharmony_ci	int index = sensor_attr->index >> 3;
70862306a36Sopenharmony_ci	int bit = sensor_attr->index & 0x07;
70962306a36Sopenharmony_ci	u8 val;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	if (nr == ALARM_STATUS)
71262306a36Sopenharmony_ci		val = (data->alarms[index] >> bit) & 1;
71362306a36Sopenharmony_ci	else		/* BEEP_ENABLE */
71462306a36Sopenharmony_ci		val = (data->beeps[index] >> bit) & 1;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	return sprintf(buf, "%u\n", val);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_cistatic ssize_t
72062306a36Sopenharmony_cistore_beep(struct device *dev, struct device_attribute *attr,
72162306a36Sopenharmony_ci	   const char *buf, size_t count)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
72462306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
72562306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
72662306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
72762306a36Sopenharmony_ci	int index = sensor_attr->index >> 3;
72862306a36Sopenharmony_ci	int shift = sensor_attr->index & 0x07;
72962306a36Sopenharmony_ci	u8 beep_bit = 1 << shift;
73062306a36Sopenharmony_ci	unsigned long val;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
73362306a36Sopenharmony_ci		return -EINVAL;
73462306a36Sopenharmony_ci	if (val != 0 && val != 1)
73562306a36Sopenharmony_ci		return -EINVAL;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
73862306a36Sopenharmony_ci	data->beeps[index] = w83795_read(client, W83795_REG_BEEP(index));
73962306a36Sopenharmony_ci	data->beeps[index] &= ~beep_bit;
74062306a36Sopenharmony_ci	data->beeps[index] |= val << shift;
74162306a36Sopenharmony_ci	w83795_write(client, W83795_REG_BEEP(index), data->beeps[index]);
74262306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return count;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci/* Write 0 to clear chassis alarm */
74862306a36Sopenharmony_cistatic ssize_t
74962306a36Sopenharmony_cistore_chassis_clear(struct device *dev,
75062306a36Sopenharmony_ci		    struct device_attribute *attr, const char *buf,
75162306a36Sopenharmony_ci		    size_t count)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
75462306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
75562306a36Sopenharmony_ci	unsigned long val;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0 || val != 0)
75862306a36Sopenharmony_ci		return -EINVAL;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
76162306a36Sopenharmony_ci	val = w83795_read(client, W83795_REG_CLR_CHASSIS);
76262306a36Sopenharmony_ci	val |= 0x80;
76362306a36Sopenharmony_ci	w83795_write(client, W83795_REG_CLR_CHASSIS, val);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/* Clear status and force cache refresh */
76662306a36Sopenharmony_ci	w83795_read(client, W83795_REG_ALARM(5));
76762306a36Sopenharmony_ci	data->valid = false;
76862306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
76962306a36Sopenharmony_ci	return count;
77062306a36Sopenharmony_ci}
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci#define FAN_INPUT     0
77362306a36Sopenharmony_ci#define FAN_MIN       1
77462306a36Sopenharmony_cistatic ssize_t
77562306a36Sopenharmony_cishow_fan(struct device *dev, struct device_attribute *attr, char *buf)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
77862306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
77962306a36Sopenharmony_ci	int nr = sensor_attr->nr;
78062306a36Sopenharmony_ci	int index = sensor_attr->index;
78162306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_device(dev);
78262306a36Sopenharmony_ci	u16 val;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	if (nr == FAN_INPUT)
78562306a36Sopenharmony_ci		val = data->fan[index] & 0x0fff;
78662306a36Sopenharmony_ci	else
78762306a36Sopenharmony_ci		val = data->fan_min[index] & 0x0fff;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return sprintf(buf, "%lu\n", fan_from_reg(val));
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_cistatic ssize_t
79362306a36Sopenharmony_cistore_fan_min(struct device *dev, struct device_attribute *attr,
79462306a36Sopenharmony_ci	      const char *buf, size_t count)
79562306a36Sopenharmony_ci{
79662306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
79762306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
79862306a36Sopenharmony_ci	int index = sensor_attr->index;
79962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
80062306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
80162306a36Sopenharmony_ci	unsigned long val;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val))
80462306a36Sopenharmony_ci		return -EINVAL;
80562306a36Sopenharmony_ci	val = fan_to_reg(val);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
80862306a36Sopenharmony_ci	data->fan_min[index] = val;
80962306a36Sopenharmony_ci	w83795_write(client, W83795_REG_FAN_MIN_HL(index), (val >> 4) & 0xff);
81062306a36Sopenharmony_ci	val &= 0x0f;
81162306a36Sopenharmony_ci	if (index & 1) {
81262306a36Sopenharmony_ci		val <<= 4;
81362306a36Sopenharmony_ci		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
81462306a36Sopenharmony_ci		       & 0x0f;
81562306a36Sopenharmony_ci	} else {
81662306a36Sopenharmony_ci		val |= w83795_read(client, W83795_REG_FAN_MIN_LSB(index))
81762306a36Sopenharmony_ci		       & 0xf0;
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci	w83795_write(client, W83795_REG_FAN_MIN_LSB(index), val & 0xff);
82062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return count;
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic ssize_t
82662306a36Sopenharmony_cishow_pwm(struct device *dev, struct device_attribute *attr, char *buf)
82762306a36Sopenharmony_ci{
82862306a36Sopenharmony_ci	struct w83795_data *data;
82962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
83062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
83162306a36Sopenharmony_ci	int nr = sensor_attr->nr;
83262306a36Sopenharmony_ci	int index = sensor_attr->index;
83362306a36Sopenharmony_ci	unsigned int val;
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	data = nr == PWM_OUTPUT ? w83795_update_device(dev)
83662306a36Sopenharmony_ci				: w83795_update_pwm_config(dev);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	switch (nr) {
83962306a36Sopenharmony_ci	case PWM_STOP_TIME:
84062306a36Sopenharmony_ci		val = time_from_reg(data->pwm[index][nr]);
84162306a36Sopenharmony_ci		break;
84262306a36Sopenharmony_ci	case PWM_FREQ:
84362306a36Sopenharmony_ci		val = pwm_freq_from_reg(data->pwm[index][nr], data->clkin);
84462306a36Sopenharmony_ci		break;
84562306a36Sopenharmony_ci	default:
84662306a36Sopenharmony_ci		val = data->pwm[index][nr];
84762306a36Sopenharmony_ci		break;
84862306a36Sopenharmony_ci	}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	return sprintf(buf, "%u\n", val);
85162306a36Sopenharmony_ci}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_cistatic ssize_t
85462306a36Sopenharmony_cistore_pwm(struct device *dev, struct device_attribute *attr,
85562306a36Sopenharmony_ci	  const char *buf, size_t count)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
85862306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
85962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
86062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
86162306a36Sopenharmony_ci	int nr = sensor_attr->nr;
86262306a36Sopenharmony_ci	int index = sensor_attr->index;
86362306a36Sopenharmony_ci	unsigned long val;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
86662306a36Sopenharmony_ci		return -EINVAL;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
86962306a36Sopenharmony_ci	switch (nr) {
87062306a36Sopenharmony_ci	case PWM_STOP_TIME:
87162306a36Sopenharmony_ci		val = time_to_reg(val);
87262306a36Sopenharmony_ci		break;
87362306a36Sopenharmony_ci	case PWM_FREQ:
87462306a36Sopenharmony_ci		val = pwm_freq_to_reg(val, data->clkin);
87562306a36Sopenharmony_ci		break;
87662306a36Sopenharmony_ci	default:
87762306a36Sopenharmony_ci		val = clamp_val(val, 0, 0xff);
87862306a36Sopenharmony_ci		break;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci	w83795_write(client, W83795_REG_PWM(index, nr), val);
88162306a36Sopenharmony_ci	data->pwm[index][nr] = val;
88262306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
88362306a36Sopenharmony_ci	return count;
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic ssize_t
88762306a36Sopenharmony_cishow_pwm_enable(struct device *dev, struct device_attribute *attr, char *buf)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
89062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
89162306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
89262306a36Sopenharmony_ci	int index = sensor_attr->index;
89362306a36Sopenharmony_ci	u8 tmp;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	/* Speed cruise mode */
89662306a36Sopenharmony_ci	if (data->pwm_fcms[0] & (1 << index)) {
89762306a36Sopenharmony_ci		tmp = 2;
89862306a36Sopenharmony_ci		goto out;
89962306a36Sopenharmony_ci	}
90062306a36Sopenharmony_ci	/* Thermal cruise or SmartFan IV mode */
90162306a36Sopenharmony_ci	for (tmp = 0; tmp < 6; tmp++) {
90262306a36Sopenharmony_ci		if (data->pwm_tfmr[tmp] & (1 << index)) {
90362306a36Sopenharmony_ci			tmp = 3;
90462306a36Sopenharmony_ci			goto out;
90562306a36Sopenharmony_ci		}
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci	/* Manual mode */
90862306a36Sopenharmony_ci	tmp = 1;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ciout:
91162306a36Sopenharmony_ci	return sprintf(buf, "%u\n", tmp);
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic ssize_t
91562306a36Sopenharmony_cistore_pwm_enable(struct device *dev, struct device_attribute *attr,
91662306a36Sopenharmony_ci	  const char *buf, size_t count)
91762306a36Sopenharmony_ci{
91862306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
91962306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
92062306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
92162306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
92262306a36Sopenharmony_ci	int index = sensor_attr->index;
92362306a36Sopenharmony_ci	unsigned long val;
92462306a36Sopenharmony_ci	int i;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
92762306a36Sopenharmony_ci		return -EINVAL;
92862306a36Sopenharmony_ci	if (val < 1 || val > 2)
92962306a36Sopenharmony_ci		return -EINVAL;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci#ifndef CONFIG_SENSORS_W83795_FANCTRL
93262306a36Sopenharmony_ci	if (val > 1) {
93362306a36Sopenharmony_ci		dev_warn(dev, "Automatic fan speed control support disabled\n");
93462306a36Sopenharmony_ci		dev_warn(dev, "Build with CONFIG_SENSORS_W83795_FANCTRL=y if you want it\n");
93562306a36Sopenharmony_ci		return -EOPNOTSUPP;
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci#endif
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
94062306a36Sopenharmony_ci	switch (val) {
94162306a36Sopenharmony_ci	case 1:
94262306a36Sopenharmony_ci		/* Clear speed cruise mode bits */
94362306a36Sopenharmony_ci		data->pwm_fcms[0] &= ~(1 << index);
94462306a36Sopenharmony_ci		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
94562306a36Sopenharmony_ci		/* Clear thermal cruise mode bits */
94662306a36Sopenharmony_ci		for (i = 0; i < 6; i++) {
94762306a36Sopenharmony_ci			data->pwm_tfmr[i] &= ~(1 << index);
94862306a36Sopenharmony_ci			w83795_write(client, W83795_REG_TFMR(i),
94962306a36Sopenharmony_ci				data->pwm_tfmr[i]);
95062306a36Sopenharmony_ci		}
95162306a36Sopenharmony_ci		break;
95262306a36Sopenharmony_ci	case 2:
95362306a36Sopenharmony_ci		data->pwm_fcms[0] |= (1 << index);
95462306a36Sopenharmony_ci		w83795_write(client, W83795_REG_FCMS1, data->pwm_fcms[0]);
95562306a36Sopenharmony_ci		break;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
95862306a36Sopenharmony_ci	return count;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_cistatic ssize_t
96262306a36Sopenharmony_cishow_pwm_mode(struct device *dev, struct device_attribute *attr, char *buf)
96362306a36Sopenharmony_ci{
96462306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
96562306a36Sopenharmony_ci	int index = to_sensor_dev_attr_2(attr)->index;
96662306a36Sopenharmony_ci	unsigned int mode;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	if (data->pwm_fomc & (1 << index))
96962306a36Sopenharmony_ci		mode = 0;	/* DC */
97062306a36Sopenharmony_ci	else
97162306a36Sopenharmony_ci		mode = 1;	/* PWM */
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	return sprintf(buf, "%u\n", mode);
97462306a36Sopenharmony_ci}
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci/*
97762306a36Sopenharmony_ci * Check whether a given temperature source can ever be useful.
97862306a36Sopenharmony_ci * Returns the number of selectable temperature channels which are
97962306a36Sopenharmony_ci * enabled.
98062306a36Sopenharmony_ci */
98162306a36Sopenharmony_cistatic int w83795_tss_useful(const struct w83795_data *data, int tsrc)
98262306a36Sopenharmony_ci{
98362306a36Sopenharmony_ci	int useful = 0, i;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
98662306a36Sopenharmony_ci		if (tss_map[i][tsrc] == TSS_MAP_RESERVED)
98762306a36Sopenharmony_ci			continue;
98862306a36Sopenharmony_ci		if (tss_map[i][tsrc] < 6)	/* Analog */
98962306a36Sopenharmony_ci			useful += (data->has_temp >> tss_map[i][tsrc]) & 1;
99062306a36Sopenharmony_ci		else				/* Digital */
99162306a36Sopenharmony_ci			useful += (data->has_dts >> (tss_map[i][tsrc] - 6)) & 1;
99262306a36Sopenharmony_ci	}
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	return useful;
99562306a36Sopenharmony_ci}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_cistatic ssize_t
99862306a36Sopenharmony_cishow_temp_src(struct device *dev, struct device_attribute *attr, char *buf)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
100162306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
100262306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
100362306a36Sopenharmony_ci	int index = sensor_attr->index;
100462306a36Sopenharmony_ci	u8 tmp = data->temp_src[index / 2];
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (index & 1)
100762306a36Sopenharmony_ci		tmp >>= 4;	/* Pick high nibble */
100862306a36Sopenharmony_ci	else
100962306a36Sopenharmony_ci		tmp &= 0x0f;	/* Pick low nibble */
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/* Look-up the actual temperature channel number */
101262306a36Sopenharmony_ci	if (tmp >= 4 || tss_map[tmp][index] == TSS_MAP_RESERVED)
101362306a36Sopenharmony_ci		return -EINVAL;		/* Shouldn't happen */
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	return sprintf(buf, "%u\n", (unsigned int)tss_map[tmp][index] + 1);
101662306a36Sopenharmony_ci}
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_cistatic ssize_t
101962306a36Sopenharmony_cistore_temp_src(struct device *dev, struct device_attribute *attr,
102062306a36Sopenharmony_ci	  const char *buf, size_t count)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
102362306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
102462306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
102562306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
102662306a36Sopenharmony_ci	int index = sensor_attr->index;
102762306a36Sopenharmony_ci	int tmp;
102862306a36Sopenharmony_ci	unsigned long channel;
102962306a36Sopenharmony_ci	u8 val = index / 2;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &channel) < 0 ||
103262306a36Sopenharmony_ci	    channel < 1 || channel > 14)
103362306a36Sopenharmony_ci		return -EINVAL;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Check if request can be fulfilled */
103662306a36Sopenharmony_ci	for (tmp = 0; tmp < 4; tmp++) {
103762306a36Sopenharmony_ci		if (tss_map[tmp][index] == channel - 1)
103862306a36Sopenharmony_ci			break;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci	if (tmp == 4)	/* No match */
104162306a36Sopenharmony_ci		return -EINVAL;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
104462306a36Sopenharmony_ci	if (index & 1) {
104562306a36Sopenharmony_ci		tmp <<= 4;
104662306a36Sopenharmony_ci		data->temp_src[val] &= 0x0f;
104762306a36Sopenharmony_ci	} else {
104862306a36Sopenharmony_ci		data->temp_src[val] &= 0xf0;
104962306a36Sopenharmony_ci	}
105062306a36Sopenharmony_ci	data->temp_src[val] |= tmp;
105162306a36Sopenharmony_ci	w83795_write(client, W83795_REG_TSS(val), data->temp_src[val]);
105262306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return count;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci#define TEMP_PWM_ENABLE   0
105862306a36Sopenharmony_ci#define TEMP_PWM_FAN_MAP  1
105962306a36Sopenharmony_cistatic ssize_t
106062306a36Sopenharmony_cishow_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
106162306a36Sopenharmony_ci		     char *buf)
106262306a36Sopenharmony_ci{
106362306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
106462306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
106562306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
106662306a36Sopenharmony_ci	int nr = sensor_attr->nr;
106762306a36Sopenharmony_ci	int index = sensor_attr->index;
106862306a36Sopenharmony_ci	u8 tmp = 0xff;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	switch (nr) {
107162306a36Sopenharmony_ci	case TEMP_PWM_ENABLE:
107262306a36Sopenharmony_ci		tmp = (data->pwm_fcms[1] >> index) & 1;
107362306a36Sopenharmony_ci		if (tmp)
107462306a36Sopenharmony_ci			tmp = 4;
107562306a36Sopenharmony_ci		else
107662306a36Sopenharmony_ci			tmp = 3;
107762306a36Sopenharmony_ci		break;
107862306a36Sopenharmony_ci	case TEMP_PWM_FAN_MAP:
107962306a36Sopenharmony_ci		tmp = data->pwm_tfmr[index];
108062306a36Sopenharmony_ci		break;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	return sprintf(buf, "%u\n", tmp);
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic ssize_t
108762306a36Sopenharmony_cistore_temp_pwm_enable(struct device *dev, struct device_attribute *attr,
108862306a36Sopenharmony_ci	  const char *buf, size_t count)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
109162306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
109262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
109362306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
109462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
109562306a36Sopenharmony_ci	int index = sensor_attr->index;
109662306a36Sopenharmony_ci	unsigned long tmp;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &tmp) < 0)
109962306a36Sopenharmony_ci		return -EINVAL;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	switch (nr) {
110262306a36Sopenharmony_ci	case TEMP_PWM_ENABLE:
110362306a36Sopenharmony_ci		if (tmp != 3 && tmp != 4)
110462306a36Sopenharmony_ci			return -EINVAL;
110562306a36Sopenharmony_ci		tmp -= 3;
110662306a36Sopenharmony_ci		mutex_lock(&data->update_lock);
110762306a36Sopenharmony_ci		data->pwm_fcms[1] &= ~(1 << index);
110862306a36Sopenharmony_ci		data->pwm_fcms[1] |= tmp << index;
110962306a36Sopenharmony_ci		w83795_write(client, W83795_REG_FCMS2, data->pwm_fcms[1]);
111062306a36Sopenharmony_ci		mutex_unlock(&data->update_lock);
111162306a36Sopenharmony_ci		break;
111262306a36Sopenharmony_ci	case TEMP_PWM_FAN_MAP:
111362306a36Sopenharmony_ci		mutex_lock(&data->update_lock);
111462306a36Sopenharmony_ci		tmp = clamp_val(tmp, 0, 0xff);
111562306a36Sopenharmony_ci		w83795_write(client, W83795_REG_TFMR(index), tmp);
111662306a36Sopenharmony_ci		data->pwm_tfmr[index] = tmp;
111762306a36Sopenharmony_ci		mutex_unlock(&data->update_lock);
111862306a36Sopenharmony_ci		break;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci	return count;
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci#define FANIN_TARGET   0
112462306a36Sopenharmony_ci#define FANIN_TOL      1
112562306a36Sopenharmony_cistatic ssize_t
112662306a36Sopenharmony_cishow_fanin(struct device *dev, struct device_attribute *attr, char *buf)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
112962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
113062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
113162306a36Sopenharmony_ci	int nr = sensor_attr->nr;
113262306a36Sopenharmony_ci	int index = sensor_attr->index;
113362306a36Sopenharmony_ci	u16 tmp = 0;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	switch (nr) {
113662306a36Sopenharmony_ci	case FANIN_TARGET:
113762306a36Sopenharmony_ci		tmp = fan_from_reg(data->target_speed[index]);
113862306a36Sopenharmony_ci		break;
113962306a36Sopenharmony_ci	case FANIN_TOL:
114062306a36Sopenharmony_ci		tmp = data->tol_speed;
114162306a36Sopenharmony_ci		break;
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	return sprintf(buf, "%u\n", tmp);
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_cistatic ssize_t
114862306a36Sopenharmony_cistore_fanin(struct device *dev, struct device_attribute *attr,
114962306a36Sopenharmony_ci	  const char *buf, size_t count)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
115262306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
115362306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
115462306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
115562306a36Sopenharmony_ci	int nr = sensor_attr->nr;
115662306a36Sopenharmony_ci	int index = sensor_attr->index;
115762306a36Sopenharmony_ci	unsigned long val;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
116062306a36Sopenharmony_ci		return -EINVAL;
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
116362306a36Sopenharmony_ci	switch (nr) {
116462306a36Sopenharmony_ci	case FANIN_TARGET:
116562306a36Sopenharmony_ci		val = fan_to_reg(clamp_val(val, 0, 0xfff));
116662306a36Sopenharmony_ci		w83795_write(client, W83795_REG_FTSH(index), val >> 4);
116762306a36Sopenharmony_ci		w83795_write(client, W83795_REG_FTSL(index), (val << 4) & 0xf0);
116862306a36Sopenharmony_ci		data->target_speed[index] = val;
116962306a36Sopenharmony_ci		break;
117062306a36Sopenharmony_ci	case FANIN_TOL:
117162306a36Sopenharmony_ci		val = clamp_val(val, 0, 0x3f);
117262306a36Sopenharmony_ci		w83795_write(client, W83795_REG_TFTS, val);
117362306a36Sopenharmony_ci		data->tol_speed = val;
117462306a36Sopenharmony_ci		break;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	return count;
117962306a36Sopenharmony_ci}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_cistatic ssize_t
118362306a36Sopenharmony_cishow_temp_pwm(struct device *dev, struct device_attribute *attr, char *buf)
118462306a36Sopenharmony_ci{
118562306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
118662306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
118762306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
118862306a36Sopenharmony_ci	int nr = sensor_attr->nr;
118962306a36Sopenharmony_ci	int index = sensor_attr->index;
119062306a36Sopenharmony_ci	long tmp = temp_from_reg(data->pwm_temp[index][nr]);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", tmp);
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_cistatic ssize_t
119662306a36Sopenharmony_cistore_temp_pwm(struct device *dev, struct device_attribute *attr,
119762306a36Sopenharmony_ci	  const char *buf, size_t count)
119862306a36Sopenharmony_ci{
119962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
120062306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
120162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
120262306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
120362306a36Sopenharmony_ci	int nr = sensor_attr->nr;
120462306a36Sopenharmony_ci	int index = sensor_attr->index;
120562306a36Sopenharmony_ci	unsigned long val;
120662306a36Sopenharmony_ci	u8 tmp;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
120962306a36Sopenharmony_ci		return -EINVAL;
121062306a36Sopenharmony_ci	val /= 1000;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
121362306a36Sopenharmony_ci	switch (nr) {
121462306a36Sopenharmony_ci	case TEMP_PWM_TTTI:
121562306a36Sopenharmony_ci		val = clamp_val(val, 0, 0x7f);
121662306a36Sopenharmony_ci		w83795_write(client, W83795_REG_TTTI(index), val);
121762306a36Sopenharmony_ci		break;
121862306a36Sopenharmony_ci	case TEMP_PWM_CTFS:
121962306a36Sopenharmony_ci		val = clamp_val(val, 0, 0x7f);
122062306a36Sopenharmony_ci		w83795_write(client, W83795_REG_CTFS(index), val);
122162306a36Sopenharmony_ci		break;
122262306a36Sopenharmony_ci	case TEMP_PWM_HCT:
122362306a36Sopenharmony_ci		val = clamp_val(val, 0, 0x0f);
122462306a36Sopenharmony_ci		tmp = w83795_read(client, W83795_REG_HT(index));
122562306a36Sopenharmony_ci		tmp &= 0x0f;
122662306a36Sopenharmony_ci		tmp |= (val << 4) & 0xf0;
122762306a36Sopenharmony_ci		w83795_write(client, W83795_REG_HT(index), tmp);
122862306a36Sopenharmony_ci		break;
122962306a36Sopenharmony_ci	case TEMP_PWM_HOT:
123062306a36Sopenharmony_ci		val = clamp_val(val, 0, 0x0f);
123162306a36Sopenharmony_ci		tmp = w83795_read(client, W83795_REG_HT(index));
123262306a36Sopenharmony_ci		tmp &= 0xf0;
123362306a36Sopenharmony_ci		tmp |= val & 0x0f;
123462306a36Sopenharmony_ci		w83795_write(client, W83795_REG_HT(index), tmp);
123562306a36Sopenharmony_ci		break;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci	data->pwm_temp[index][nr] = val;
123862306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	return count;
124162306a36Sopenharmony_ci}
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_cistatic ssize_t
124462306a36Sopenharmony_cishow_sf4_pwm(struct device *dev, struct device_attribute *attr, char *buf)
124562306a36Sopenharmony_ci{
124662306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
124762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
124862306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
124962306a36Sopenharmony_ci	int nr = sensor_attr->nr;
125062306a36Sopenharmony_ci	int index = sensor_attr->index;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	return sprintf(buf, "%u\n", data->sf4_reg[index][SF4_PWM][nr]);
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic ssize_t
125662306a36Sopenharmony_cistore_sf4_pwm(struct device *dev, struct device_attribute *attr,
125762306a36Sopenharmony_ci	  const char *buf, size_t count)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
126062306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
126162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
126262306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
126362306a36Sopenharmony_ci	int nr = sensor_attr->nr;
126462306a36Sopenharmony_ci	int index = sensor_attr->index;
126562306a36Sopenharmony_ci	unsigned long val;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
126862306a36Sopenharmony_ci		return -EINVAL;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
127162306a36Sopenharmony_ci	w83795_write(client, W83795_REG_SF4_PWM(index, nr), val);
127262306a36Sopenharmony_ci	data->sf4_reg[index][SF4_PWM][nr] = val;
127362306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	return count;
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic ssize_t
127962306a36Sopenharmony_cishow_sf4_temp(struct device *dev, struct device_attribute *attr, char *buf)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
128262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
128362306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
128462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
128562306a36Sopenharmony_ci	int index = sensor_attr->index;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	return sprintf(buf, "%u\n",
128862306a36Sopenharmony_ci		(data->sf4_reg[index][SF4_TEMP][nr]) * 1000);
128962306a36Sopenharmony_ci}
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_cistatic ssize_t
129262306a36Sopenharmony_cistore_sf4_temp(struct device *dev, struct device_attribute *attr,
129362306a36Sopenharmony_ci	  const char *buf, size_t count)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
129662306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
129762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
129862306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
129962306a36Sopenharmony_ci	int nr = sensor_attr->nr;
130062306a36Sopenharmony_ci	int index = sensor_attr->index;
130162306a36Sopenharmony_ci	unsigned long val;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
130462306a36Sopenharmony_ci		return -EINVAL;
130562306a36Sopenharmony_ci	val /= 1000;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
130862306a36Sopenharmony_ci	w83795_write(client, W83795_REG_SF4_TEMP(index, nr), val);
130962306a36Sopenharmony_ci	data->sf4_reg[index][SF4_TEMP][nr] = val;
131062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return count;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_cistatic ssize_t
131762306a36Sopenharmony_cishow_temp(struct device *dev, struct device_attribute *attr, char *buf)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
132062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
132162306a36Sopenharmony_ci	int nr = sensor_attr->nr;
132262306a36Sopenharmony_ci	int index = sensor_attr->index;
132362306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_device(dev);
132462306a36Sopenharmony_ci	long temp = temp_from_reg(data->temp[index][nr]);
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	if (nr == TEMP_READ)
132762306a36Sopenharmony_ci		temp += (data->temp_read_vrlsb[index] >> 6) * 250;
132862306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", temp);
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic ssize_t
133262306a36Sopenharmony_cistore_temp(struct device *dev, struct device_attribute *attr,
133362306a36Sopenharmony_ci	   const char *buf, size_t count)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
133662306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
133762306a36Sopenharmony_ci	int nr = sensor_attr->nr;
133862306a36Sopenharmony_ci	int index = sensor_attr->index;
133962306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
134062306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
134162306a36Sopenharmony_ci	long tmp;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	if (kstrtol(buf, 10, &tmp) < 0)
134462306a36Sopenharmony_ci		return -EINVAL;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
134762306a36Sopenharmony_ci	data->temp[index][nr] = temp_to_reg(tmp, -128, 127);
134862306a36Sopenharmony_ci	w83795_write(client, W83795_REG_TEMP[index][nr], data->temp[index][nr]);
134962306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
135062306a36Sopenharmony_ci	return count;
135162306a36Sopenharmony_ci}
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_cistatic ssize_t
135562306a36Sopenharmony_cishow_dts_mode(struct device *dev, struct device_attribute *attr, char *buf)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	struct w83795_data *data = dev_get_drvdata(dev);
135862306a36Sopenharmony_ci	int tmp;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	if (data->enable_dts & 2)
136162306a36Sopenharmony_ci		tmp = 5;
136262306a36Sopenharmony_ci	else
136362306a36Sopenharmony_ci		tmp = 6;
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", tmp);
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_cistatic ssize_t
136962306a36Sopenharmony_cishow_dts(struct device *dev, struct device_attribute *attr, char *buf)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
137262306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
137362306a36Sopenharmony_ci	int index = sensor_attr->index;
137462306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_device(dev);
137562306a36Sopenharmony_ci	long temp = temp_from_reg(data->dts[index]);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	temp += (data->dts_read_vrlsb[index] >> 6) * 250;
137862306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", temp);
137962306a36Sopenharmony_ci}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_cistatic ssize_t
138262306a36Sopenharmony_cishow_dts_ext(struct device *dev, struct device_attribute *attr, char *buf)
138362306a36Sopenharmony_ci{
138462306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
138562306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
138662306a36Sopenharmony_ci	int nr = sensor_attr->nr;
138762306a36Sopenharmony_ci	struct w83795_data *data = dev_get_drvdata(dev);
138862306a36Sopenharmony_ci	long temp = temp_from_reg(data->dts_ext[nr]);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	return sprintf(buf, "%ld\n", temp);
139162306a36Sopenharmony_ci}
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_cistatic ssize_t
139462306a36Sopenharmony_cistore_dts_ext(struct device *dev, struct device_attribute *attr,
139562306a36Sopenharmony_ci	   const char *buf, size_t count)
139662306a36Sopenharmony_ci{
139762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
139862306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
139962306a36Sopenharmony_ci	int nr = sensor_attr->nr;
140062306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
140162306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
140262306a36Sopenharmony_ci	long tmp;
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	if (kstrtol(buf, 10, &tmp) < 0)
140562306a36Sopenharmony_ci		return -EINVAL;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
140862306a36Sopenharmony_ci	data->dts_ext[nr] = temp_to_reg(tmp, -128, 127);
140962306a36Sopenharmony_ci	w83795_write(client, W83795_REG_DTS_EXT(nr), data->dts_ext[nr]);
141062306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
141162306a36Sopenharmony_ci	return count;
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_cistatic ssize_t
141662306a36Sopenharmony_cishow_temp_mode(struct device *dev, struct device_attribute *attr, char *buf)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	struct w83795_data *data = dev_get_drvdata(dev);
141962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
142062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
142162306a36Sopenharmony_ci	int index = sensor_attr->index;
142262306a36Sopenharmony_ci	int tmp;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (data->temp_mode & (1 << index))
142562306a36Sopenharmony_ci		tmp = 3;	/* Thermal diode */
142662306a36Sopenharmony_ci	else
142762306a36Sopenharmony_ci		tmp = 4;	/* Thermistor */
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	return sprintf(buf, "%d\n", tmp);
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci/* Only for temp1-4 (temp5-6 can only be thermistor) */
143362306a36Sopenharmony_cistatic ssize_t
143462306a36Sopenharmony_cistore_temp_mode(struct device *dev, struct device_attribute *attr,
143562306a36Sopenharmony_ci		const char *buf, size_t count)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
143862306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
143962306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
144062306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
144162306a36Sopenharmony_ci	int index = sensor_attr->index;
144262306a36Sopenharmony_ci	int reg_shift;
144362306a36Sopenharmony_ci	unsigned long val;
144462306a36Sopenharmony_ci	u8 tmp;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
144762306a36Sopenharmony_ci		return -EINVAL;
144862306a36Sopenharmony_ci	if ((val != 4) && (val != 3))
144962306a36Sopenharmony_ci		return -EINVAL;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
145262306a36Sopenharmony_ci	if (val == 3) {
145362306a36Sopenharmony_ci		/* Thermal diode */
145462306a36Sopenharmony_ci		val = 0x01;
145562306a36Sopenharmony_ci		data->temp_mode |= 1 << index;
145662306a36Sopenharmony_ci	} else if (val == 4) {
145762306a36Sopenharmony_ci		/* Thermistor */
145862306a36Sopenharmony_ci		val = 0x03;
145962306a36Sopenharmony_ci		data->temp_mode &= ~(1 << index);
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	reg_shift = 2 * index;
146362306a36Sopenharmony_ci	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
146462306a36Sopenharmony_ci	tmp &= ~(0x03 << reg_shift);
146562306a36Sopenharmony_ci	tmp |= val << reg_shift;
146662306a36Sopenharmony_ci	w83795_write(client, W83795_REG_TEMP_CTRL2, tmp);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
146962306a36Sopenharmony_ci	return count;
147062306a36Sopenharmony_ci}
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci/* show/store VIN */
147462306a36Sopenharmony_cistatic ssize_t
147562306a36Sopenharmony_cishow_in(struct device *dev, struct device_attribute *attr, char *buf)
147662306a36Sopenharmony_ci{
147762306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
147862306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
147962306a36Sopenharmony_ci	int nr = sensor_attr->nr;
148062306a36Sopenharmony_ci	int index = sensor_attr->index;
148162306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_device(dev);
148262306a36Sopenharmony_ci	u16 val = data->in[index][nr];
148362306a36Sopenharmony_ci	u8 lsb_idx;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	switch (nr) {
148662306a36Sopenharmony_ci	case IN_READ:
148762306a36Sopenharmony_ci		/* calculate this value again by sensors as sensors3.conf */
148862306a36Sopenharmony_ci		if ((index >= 17) &&
148962306a36Sopenharmony_ci		    !((data->has_gain >> (index - 17)) & 1))
149062306a36Sopenharmony_ci			val *= 8;
149162306a36Sopenharmony_ci		break;
149262306a36Sopenharmony_ci	case IN_MAX:
149362306a36Sopenharmony_ci	case IN_LOW:
149462306a36Sopenharmony_ci		lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
149562306a36Sopenharmony_ci		val <<= 2;
149662306a36Sopenharmony_ci		val |= (data->in_lsb[lsb_idx][nr] >>
149762306a36Sopenharmony_ci			IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]) & 0x03;
149862306a36Sopenharmony_ci		if ((index >= 17) &&
149962306a36Sopenharmony_ci		    !((data->has_gain >> (index - 17)) & 1))
150062306a36Sopenharmony_ci			val *= 8;
150162306a36Sopenharmony_ci		break;
150262306a36Sopenharmony_ci	}
150362306a36Sopenharmony_ci	val = in_from_reg(index, val);
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", val);
150662306a36Sopenharmony_ci}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_cistatic ssize_t
150962306a36Sopenharmony_cistore_in(struct device *dev, struct device_attribute *attr,
151062306a36Sopenharmony_ci	 const char *buf, size_t count)
151162306a36Sopenharmony_ci{
151262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
151362306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
151462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
151562306a36Sopenharmony_ci	int index = sensor_attr->index;
151662306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
151762306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
151862306a36Sopenharmony_ci	unsigned long val;
151962306a36Sopenharmony_ci	u8 tmp;
152062306a36Sopenharmony_ci	u8 lsb_idx;
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
152362306a36Sopenharmony_ci		return -EINVAL;
152462306a36Sopenharmony_ci	val = in_to_reg(index, val);
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	if ((index >= 17) &&
152762306a36Sopenharmony_ci	    !((data->has_gain >> (index - 17)) & 1))
152862306a36Sopenharmony_ci		val /= 8;
152962306a36Sopenharmony_ci	val = clamp_val(val, 0, 0x3FF);
153062306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	lsb_idx = IN_LSB_SHIFT_IDX[index][IN_LSB_IDX];
153362306a36Sopenharmony_ci	tmp = w83795_read(client, IN_LSB_REG(lsb_idx, nr));
153462306a36Sopenharmony_ci	tmp &= ~(0x03 << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT]);
153562306a36Sopenharmony_ci	tmp |= (val & 0x03) << IN_LSB_SHIFT_IDX[index][IN_LSB_SHIFT];
153662306a36Sopenharmony_ci	w83795_write(client, IN_LSB_REG(lsb_idx, nr), tmp);
153762306a36Sopenharmony_ci	data->in_lsb[lsb_idx][nr] = tmp;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci	tmp = (val >> 2) & 0xff;
154062306a36Sopenharmony_ci	w83795_write(client, W83795_REG_IN[index][nr], tmp);
154162306a36Sopenharmony_ci	data->in[index][nr] = tmp;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
154462306a36Sopenharmony_ci	return count;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL
154962306a36Sopenharmony_cistatic ssize_t
155062306a36Sopenharmony_cishow_sf_setup(struct device *dev, struct device_attribute *attr, char *buf)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
155362306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
155462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
155562306a36Sopenharmony_ci	struct w83795_data *data = w83795_update_pwm_config(dev);
155662306a36Sopenharmony_ci	u16 val = data->setup_pwm[nr];
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	switch (nr) {
155962306a36Sopenharmony_ci	case SETUP_PWM_UPTIME:
156062306a36Sopenharmony_ci	case SETUP_PWM_DOWNTIME:
156162306a36Sopenharmony_ci		val = time_from_reg(val);
156262306a36Sopenharmony_ci		break;
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", val);
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic ssize_t
156962306a36Sopenharmony_cistore_sf_setup(struct device *dev, struct device_attribute *attr,
157062306a36Sopenharmony_ci	 const char *buf, size_t count)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct sensor_device_attribute_2 *sensor_attr =
157362306a36Sopenharmony_ci	    to_sensor_dev_attr_2(attr);
157462306a36Sopenharmony_ci	int nr = sensor_attr->nr;
157562306a36Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
157662306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
157762306a36Sopenharmony_ci	unsigned long val;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	if (kstrtoul(buf, 10, &val) < 0)
158062306a36Sopenharmony_ci		return -EINVAL;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	switch (nr) {
158362306a36Sopenharmony_ci	case SETUP_PWM_DEFAULT:
158462306a36Sopenharmony_ci		val = clamp_val(val, 0, 0xff);
158562306a36Sopenharmony_ci		break;
158662306a36Sopenharmony_ci	case SETUP_PWM_UPTIME:
158762306a36Sopenharmony_ci	case SETUP_PWM_DOWNTIME:
158862306a36Sopenharmony_ci		val = time_to_reg(val);
158962306a36Sopenharmony_ci		if (val == 0)
159062306a36Sopenharmony_ci			return -EINVAL;
159162306a36Sopenharmony_ci		break;
159262306a36Sopenharmony_ci	}
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	mutex_lock(&data->update_lock);
159562306a36Sopenharmony_ci	data->setup_pwm[nr] = val;
159662306a36Sopenharmony_ci	w83795_write(client, W83795_REG_SETUP_PWM(nr), val);
159762306a36Sopenharmony_ci	mutex_unlock(&data->update_lock);
159862306a36Sopenharmony_ci	return count;
159962306a36Sopenharmony_ci}
160062306a36Sopenharmony_ci#endif
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci#define NOT_USED			-1
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci/*
160662306a36Sopenharmony_ci * Don't change the attribute order, _max, _min and _beep are accessed by index
160762306a36Sopenharmony_ci * somewhere else in the code
160862306a36Sopenharmony_ci */
160962306a36Sopenharmony_ci#define SENSOR_ATTR_IN(index) {						\
161062306a36Sopenharmony_ci	SENSOR_ATTR_2(in##index##_input, S_IRUGO, show_in, NULL,	\
161162306a36Sopenharmony_ci		IN_READ, index), \
161262306a36Sopenharmony_ci	SENSOR_ATTR_2(in##index##_max, S_IRUGO | S_IWUSR, show_in,	\
161362306a36Sopenharmony_ci		store_in, IN_MAX, index),				\
161462306a36Sopenharmony_ci	SENSOR_ATTR_2(in##index##_min, S_IRUGO | S_IWUSR, show_in,	\
161562306a36Sopenharmony_ci		store_in, IN_LOW, index),				\
161662306a36Sopenharmony_ci	SENSOR_ATTR_2(in##index##_alarm, S_IRUGO, show_alarm_beep,	\
161762306a36Sopenharmony_ci		NULL, ALARM_STATUS, index + ((index > 14) ? 1 : 0)), \
161862306a36Sopenharmony_ci	SENSOR_ATTR_2(in##index##_beep, S_IWUSR | S_IRUGO,		\
161962306a36Sopenharmony_ci		show_alarm_beep, store_beep, BEEP_ENABLE,		\
162062306a36Sopenharmony_ci		index + ((index > 14) ? 1 : 0)) }
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci/*
162362306a36Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index
162462306a36Sopenharmony_ci * somewhere else in the code
162562306a36Sopenharmony_ci */
162662306a36Sopenharmony_ci#define SENSOR_ATTR_FAN(index) {					\
162762306a36Sopenharmony_ci	SENSOR_ATTR_2(fan##index##_input, S_IRUGO, show_fan,		\
162862306a36Sopenharmony_ci		NULL, FAN_INPUT, index - 1), \
162962306a36Sopenharmony_ci	SENSOR_ATTR_2(fan##index##_min, S_IWUSR | S_IRUGO,		\
163062306a36Sopenharmony_ci		show_fan, store_fan_min, FAN_MIN, index - 1),	\
163162306a36Sopenharmony_ci	SENSOR_ATTR_2(fan##index##_alarm, S_IRUGO, show_alarm_beep,	\
163262306a36Sopenharmony_ci		NULL, ALARM_STATUS, index + 31),			\
163362306a36Sopenharmony_ci	SENSOR_ATTR_2(fan##index##_beep, S_IWUSR | S_IRUGO,		\
163462306a36Sopenharmony_ci		show_alarm_beep, store_beep, BEEP_ENABLE, index + 31) }
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci#define SENSOR_ATTR_PWM(index) {					\
163762306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index, S_IWUSR | S_IRUGO, show_pwm,		\
163862306a36Sopenharmony_ci		store_pwm, PWM_OUTPUT, index - 1),			\
163962306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_enable, S_IWUSR | S_IRUGO,		\
164062306a36Sopenharmony_ci		show_pwm_enable, store_pwm_enable, NOT_USED, index - 1), \
164162306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_mode, S_IRUGO,			\
164262306a36Sopenharmony_ci		show_pwm_mode, NULL, NOT_USED, index - 1),		\
164362306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_freq, S_IWUSR | S_IRUGO,		\
164462306a36Sopenharmony_ci		show_pwm, store_pwm, PWM_FREQ, index - 1),		\
164562306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_nonstop, S_IWUSR | S_IRUGO,		\
164662306a36Sopenharmony_ci		show_pwm, store_pwm, PWM_NONSTOP, index - 1),		\
164762306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_start, S_IWUSR | S_IRUGO,		\
164862306a36Sopenharmony_ci		show_pwm, store_pwm, PWM_START, index - 1),		\
164962306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm##index##_stop_time, S_IWUSR | S_IRUGO,	\
165062306a36Sopenharmony_ci		show_pwm, store_pwm, PWM_STOP_TIME, index - 1),	 \
165162306a36Sopenharmony_ci	SENSOR_ATTR_2(fan##index##_target, S_IWUSR | S_IRUGO, \
165262306a36Sopenharmony_ci		show_fanin, store_fanin, FANIN_TARGET, index - 1) }
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci/*
165562306a36Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index
165662306a36Sopenharmony_ci * somewhere else in the code
165762306a36Sopenharmony_ci */
165862306a36Sopenharmony_ci#define SENSOR_ATTR_DTS(index) {					\
165962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_type, S_IRUGO ,		\
166062306a36Sopenharmony_ci		show_dts_mode, NULL, NOT_USED, index - 7),	\
166162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_dts,		\
166262306a36Sopenharmony_ci		NULL, NOT_USED, index - 7),				\
166362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_dts_ext, \
166462306a36Sopenharmony_ci		store_dts_ext, DTS_CRIT, NOT_USED),			\
166562306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
166662306a36Sopenharmony_ci		show_dts_ext, store_dts_ext, DTS_CRIT_HYST, NOT_USED),	\
166762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_dts_ext, \
166862306a36Sopenharmony_ci		store_dts_ext, DTS_WARN, NOT_USED),			\
166962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
167062306a36Sopenharmony_ci		show_dts_ext, store_dts_ext, DTS_WARN_HYST, NOT_USED),	\
167162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
167262306a36Sopenharmony_ci		show_alarm_beep, NULL, ALARM_STATUS, index + 17),	\
167362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
167462306a36Sopenharmony_ci		show_alarm_beep, store_beep, BEEP_ENABLE, index + 17) }
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci/*
167762306a36Sopenharmony_ci * Don't change the attribute order, _beep is accessed by index
167862306a36Sopenharmony_ci * somewhere else in the code
167962306a36Sopenharmony_ci */
168062306a36Sopenharmony_ci#define SENSOR_ATTR_TEMP(index) {					\
168162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_type, S_IRUGO | (index < 5 ? S_IWUSR : 0), \
168262306a36Sopenharmony_ci		show_temp_mode, store_temp_mode, NOT_USED, index - 1),	\
168362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_input, S_IRUGO, show_temp,		\
168462306a36Sopenharmony_ci		NULL, TEMP_READ, index - 1),				\
168562306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_crit, S_IRUGO | S_IWUSR, show_temp,	\
168662306a36Sopenharmony_ci		store_temp, TEMP_CRIT, index - 1),			\
168762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_crit_hyst, S_IRUGO | S_IWUSR,	\
168862306a36Sopenharmony_ci		show_temp, store_temp, TEMP_CRIT_HYST, index - 1),	\
168962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_max, S_IRUGO | S_IWUSR, show_temp,	\
169062306a36Sopenharmony_ci		store_temp, TEMP_WARN, index - 1),			\
169162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_max_hyst, S_IRUGO | S_IWUSR,	\
169262306a36Sopenharmony_ci		show_temp, store_temp, TEMP_WARN_HYST, index - 1),	\
169362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_alarm, S_IRUGO,			\
169462306a36Sopenharmony_ci		show_alarm_beep, NULL, ALARM_STATUS,			\
169562306a36Sopenharmony_ci		index + (index > 4 ? 11 : 17)),				\
169662306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_beep, S_IWUSR | S_IRUGO,		\
169762306a36Sopenharmony_ci		show_alarm_beep, store_beep, BEEP_ENABLE,		\
169862306a36Sopenharmony_ci		index + (index > 4 ? 11 : 17)),				\
169962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_pwm_enable, S_IWUSR | S_IRUGO,	\
170062306a36Sopenharmony_ci		show_temp_pwm_enable, store_temp_pwm_enable,		\
170162306a36Sopenharmony_ci		TEMP_PWM_ENABLE, index - 1),				\
170262306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_channels_pwm, S_IWUSR | S_IRUGO, \
170362306a36Sopenharmony_ci		show_temp_pwm_enable, store_temp_pwm_enable,		\
170462306a36Sopenharmony_ci		TEMP_PWM_FAN_MAP, index - 1),				\
170562306a36Sopenharmony_ci	SENSOR_ATTR_2(thermal_cruise##index, S_IWUSR | S_IRUGO,		\
170662306a36Sopenharmony_ci		show_temp_pwm, store_temp_pwm, TEMP_PWM_TTTI, index - 1), \
170762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_warn, S_IWUSR | S_IRUGO,		\
170862306a36Sopenharmony_ci		show_temp_pwm, store_temp_pwm, TEMP_PWM_CTFS, index - 1), \
170962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_warn_hyst, S_IWUSR | S_IRUGO,	\
171062306a36Sopenharmony_ci		show_temp_pwm, store_temp_pwm, TEMP_PWM_HCT, index - 1), \
171162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_operation_hyst, S_IWUSR | S_IRUGO,	\
171262306a36Sopenharmony_ci		show_temp_pwm, store_temp_pwm, TEMP_PWM_HOT, index - 1), \
171362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point1_pwm, S_IRUGO | S_IWUSR, \
171462306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 0, index - 1),		\
171562306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point2_pwm, S_IRUGO | S_IWUSR, \
171662306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 1, index - 1),		\
171762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point3_pwm, S_IRUGO | S_IWUSR, \
171862306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 2, index - 1),		\
171962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point4_pwm, S_IRUGO | S_IWUSR, \
172062306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 3, index - 1),		\
172162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point5_pwm, S_IRUGO | S_IWUSR, \
172262306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 4, index - 1),		\
172362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point6_pwm, S_IRUGO | S_IWUSR, \
172462306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 5, index - 1),		\
172562306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point7_pwm, S_IRUGO | S_IWUSR, \
172662306a36Sopenharmony_ci		show_sf4_pwm, store_sf4_pwm, 6, index - 1),		\
172762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point1_temp, S_IRUGO | S_IWUSR,\
172862306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 0, index - 1),		\
172962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point2_temp, S_IRUGO | S_IWUSR,\
173062306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 1, index - 1),		\
173162306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point3_temp, S_IRUGO | S_IWUSR,\
173262306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 2, index - 1),		\
173362306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point4_temp, S_IRUGO | S_IWUSR,\
173462306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 3, index - 1),		\
173562306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point5_temp, S_IRUGO | S_IWUSR,\
173662306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 4, index - 1),		\
173762306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point6_temp, S_IRUGO | S_IWUSR,\
173862306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 5, index - 1),		\
173962306a36Sopenharmony_ci	SENSOR_ATTR_2(temp##index##_auto_point7_temp, S_IRUGO | S_IWUSR,\
174062306a36Sopenharmony_ci		show_sf4_temp, store_sf4_temp, 6, index - 1) }
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_cistatic struct sensor_device_attribute_2 w83795_in[][5] = {
174462306a36Sopenharmony_ci	SENSOR_ATTR_IN(0),
174562306a36Sopenharmony_ci	SENSOR_ATTR_IN(1),
174662306a36Sopenharmony_ci	SENSOR_ATTR_IN(2),
174762306a36Sopenharmony_ci	SENSOR_ATTR_IN(3),
174862306a36Sopenharmony_ci	SENSOR_ATTR_IN(4),
174962306a36Sopenharmony_ci	SENSOR_ATTR_IN(5),
175062306a36Sopenharmony_ci	SENSOR_ATTR_IN(6),
175162306a36Sopenharmony_ci	SENSOR_ATTR_IN(7),
175262306a36Sopenharmony_ci	SENSOR_ATTR_IN(8),
175362306a36Sopenharmony_ci	SENSOR_ATTR_IN(9),
175462306a36Sopenharmony_ci	SENSOR_ATTR_IN(10),
175562306a36Sopenharmony_ci	SENSOR_ATTR_IN(11),
175662306a36Sopenharmony_ci	SENSOR_ATTR_IN(12),
175762306a36Sopenharmony_ci	SENSOR_ATTR_IN(13),
175862306a36Sopenharmony_ci	SENSOR_ATTR_IN(14),
175962306a36Sopenharmony_ci	SENSOR_ATTR_IN(15),
176062306a36Sopenharmony_ci	SENSOR_ATTR_IN(16),
176162306a36Sopenharmony_ci	SENSOR_ATTR_IN(17),
176262306a36Sopenharmony_ci	SENSOR_ATTR_IN(18),
176362306a36Sopenharmony_ci	SENSOR_ATTR_IN(19),
176462306a36Sopenharmony_ci	SENSOR_ATTR_IN(20),
176562306a36Sopenharmony_ci};
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_fan[][4] = {
176862306a36Sopenharmony_ci	SENSOR_ATTR_FAN(1),
176962306a36Sopenharmony_ci	SENSOR_ATTR_FAN(2),
177062306a36Sopenharmony_ci	SENSOR_ATTR_FAN(3),
177162306a36Sopenharmony_ci	SENSOR_ATTR_FAN(4),
177262306a36Sopenharmony_ci	SENSOR_ATTR_FAN(5),
177362306a36Sopenharmony_ci	SENSOR_ATTR_FAN(6),
177462306a36Sopenharmony_ci	SENSOR_ATTR_FAN(7),
177562306a36Sopenharmony_ci	SENSOR_ATTR_FAN(8),
177662306a36Sopenharmony_ci	SENSOR_ATTR_FAN(9),
177762306a36Sopenharmony_ci	SENSOR_ATTR_FAN(10),
177862306a36Sopenharmony_ci	SENSOR_ATTR_FAN(11),
177962306a36Sopenharmony_ci	SENSOR_ATTR_FAN(12),
178062306a36Sopenharmony_ci	SENSOR_ATTR_FAN(13),
178162306a36Sopenharmony_ci	SENSOR_ATTR_FAN(14),
178262306a36Sopenharmony_ci};
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_temp[][28] = {
178562306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(1),
178662306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(2),
178762306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(3),
178862306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(4),
178962306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(5),
179062306a36Sopenharmony_ci	SENSOR_ATTR_TEMP(6),
179162306a36Sopenharmony_ci};
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_dts[][8] = {
179462306a36Sopenharmony_ci	SENSOR_ATTR_DTS(7),
179562306a36Sopenharmony_ci	SENSOR_ATTR_DTS(8),
179662306a36Sopenharmony_ci	SENSOR_ATTR_DTS(9),
179762306a36Sopenharmony_ci	SENSOR_ATTR_DTS(10),
179862306a36Sopenharmony_ci	SENSOR_ATTR_DTS(11),
179962306a36Sopenharmony_ci	SENSOR_ATTR_DTS(12),
180062306a36Sopenharmony_ci	SENSOR_ATTR_DTS(13),
180162306a36Sopenharmony_ci	SENSOR_ATTR_DTS(14),
180262306a36Sopenharmony_ci};
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_pwm[][8] = {
180562306a36Sopenharmony_ci	SENSOR_ATTR_PWM(1),
180662306a36Sopenharmony_ci	SENSOR_ATTR_PWM(2),
180762306a36Sopenharmony_ci	SENSOR_ATTR_PWM(3),
180862306a36Sopenharmony_ci	SENSOR_ATTR_PWM(4),
180962306a36Sopenharmony_ci	SENSOR_ATTR_PWM(5),
181062306a36Sopenharmony_ci	SENSOR_ATTR_PWM(6),
181162306a36Sopenharmony_ci	SENSOR_ATTR_PWM(7),
181262306a36Sopenharmony_ci	SENSOR_ATTR_PWM(8),
181362306a36Sopenharmony_ci};
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 w83795_tss[6] = {
181662306a36Sopenharmony_ci	SENSOR_ATTR_2(temp1_source_sel, S_IWUSR | S_IRUGO,
181762306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 0),
181862306a36Sopenharmony_ci	SENSOR_ATTR_2(temp2_source_sel, S_IWUSR | S_IRUGO,
181962306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 1),
182062306a36Sopenharmony_ci	SENSOR_ATTR_2(temp3_source_sel, S_IWUSR | S_IRUGO,
182162306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 2),
182262306a36Sopenharmony_ci	SENSOR_ATTR_2(temp4_source_sel, S_IWUSR | S_IRUGO,
182362306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 3),
182462306a36Sopenharmony_ci	SENSOR_ATTR_2(temp5_source_sel, S_IWUSR | S_IRUGO,
182562306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 4),
182662306a36Sopenharmony_ci	SENSOR_ATTR_2(temp6_source_sel, S_IWUSR | S_IRUGO,
182762306a36Sopenharmony_ci		      show_temp_src, store_temp_src, NOT_USED, 5),
182862306a36Sopenharmony_ci};
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 sda_single_files[] = {
183162306a36Sopenharmony_ci	SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep,
183262306a36Sopenharmony_ci		      store_chassis_clear, ALARM_STATUS, 46),
183362306a36Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL
183462306a36Sopenharmony_ci	SENSOR_ATTR_2(speed_cruise_tolerance, S_IWUSR | S_IRUGO, show_fanin,
183562306a36Sopenharmony_ci		store_fanin, FANIN_TOL, NOT_USED),
183662306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm_default, S_IWUSR | S_IRUGO, show_sf_setup,
183762306a36Sopenharmony_ci		      store_sf_setup, SETUP_PWM_DEFAULT, NOT_USED),
183862306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm_uptime, S_IWUSR | S_IRUGO, show_sf_setup,
183962306a36Sopenharmony_ci		      store_sf_setup, SETUP_PWM_UPTIME, NOT_USED),
184062306a36Sopenharmony_ci	SENSOR_ATTR_2(pwm_downtime, S_IWUSR | S_IRUGO, show_sf_setup,
184162306a36Sopenharmony_ci		      store_sf_setup, SETUP_PWM_DOWNTIME, NOT_USED),
184262306a36Sopenharmony_ci#endif
184362306a36Sopenharmony_ci};
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_cistatic const struct sensor_device_attribute_2 sda_beep_files[] = {
184662306a36Sopenharmony_ci	SENSOR_ATTR_2(intrusion0_beep, S_IWUSR | S_IRUGO, show_alarm_beep,
184762306a36Sopenharmony_ci		      store_beep, BEEP_ENABLE, 46),
184862306a36Sopenharmony_ci	SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_alarm_beep,
184962306a36Sopenharmony_ci		      store_beep, BEEP_ENABLE, 47),
185062306a36Sopenharmony_ci};
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci/*
185362306a36Sopenharmony_ci * Driver interface
185462306a36Sopenharmony_ci */
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_cistatic void w83795_init_client(struct i2c_client *client)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
185962306a36Sopenharmony_ci	static const u16 clkin[4] = {	/* in kHz */
186062306a36Sopenharmony_ci		14318, 24000, 33333, 48000
186162306a36Sopenharmony_ci	};
186262306a36Sopenharmony_ci	u8 config;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	if (reset)
186562306a36Sopenharmony_ci		w83795_write(client, W83795_REG_CONFIG, 0x80);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	/* Start monitoring if needed */
186862306a36Sopenharmony_ci	config = w83795_read(client, W83795_REG_CONFIG);
186962306a36Sopenharmony_ci	if (!(config & W83795_REG_CONFIG_START)) {
187062306a36Sopenharmony_ci		dev_info(&client->dev, "Enabling monitoring operations\n");
187162306a36Sopenharmony_ci		w83795_write(client, W83795_REG_CONFIG,
187262306a36Sopenharmony_ci			     config | W83795_REG_CONFIG_START);
187362306a36Sopenharmony_ci	}
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	data->clkin = clkin[(config >> 3) & 0x3];
187662306a36Sopenharmony_ci	dev_dbg(&client->dev, "clkin = %u kHz\n", data->clkin);
187762306a36Sopenharmony_ci}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_cistatic int w83795_get_device_id(struct i2c_client *client)
188062306a36Sopenharmony_ci{
188162306a36Sopenharmony_ci	int device_id;
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	device_id = i2c_smbus_read_byte_data(client, W83795_REG_DEVICEID);
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	/*
188662306a36Sopenharmony_ci	 * Special case for rev. A chips; can't be checked first because later
188762306a36Sopenharmony_ci	 * revisions emulate this for compatibility
188862306a36Sopenharmony_ci	 */
188962306a36Sopenharmony_ci	if (device_id < 0 || (device_id & 0xf0) != 0x50) {
189062306a36Sopenharmony_ci		int alt_id;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci		alt_id = i2c_smbus_read_byte_data(client,
189362306a36Sopenharmony_ci						  W83795_REG_DEVICEID_A);
189462306a36Sopenharmony_ci		if (alt_id == 0x50)
189562306a36Sopenharmony_ci			device_id = alt_id;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	return device_id;
189962306a36Sopenharmony_ci}
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
190262306a36Sopenharmony_cistatic int w83795_detect(struct i2c_client *client,
190362306a36Sopenharmony_ci			 struct i2c_board_info *info)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	int bank, vendor_id, device_id, expected, i2c_addr, config;
190662306a36Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
190762306a36Sopenharmony_ci	unsigned short address = client->addr;
190862306a36Sopenharmony_ci	const char *chip_name;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
191162306a36Sopenharmony_ci		return -ENODEV;
191262306a36Sopenharmony_ci	bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
191362306a36Sopenharmony_ci	if (bank < 0 || (bank & 0x7c)) {
191462306a36Sopenharmony_ci		dev_dbg(&adapter->dev,
191562306a36Sopenharmony_ci			"w83795: Detection failed at addr 0x%02hx, check %s\n",
191662306a36Sopenharmony_ci			address, "bank");
191762306a36Sopenharmony_ci		return -ENODEV;
191862306a36Sopenharmony_ci	}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci	/* Check Nuvoton vendor ID */
192162306a36Sopenharmony_ci	vendor_id = i2c_smbus_read_byte_data(client, W83795_REG_VENDORID);
192262306a36Sopenharmony_ci	expected = bank & 0x80 ? 0x5c : 0xa3;
192362306a36Sopenharmony_ci	if (vendor_id != expected) {
192462306a36Sopenharmony_ci		dev_dbg(&adapter->dev,
192562306a36Sopenharmony_ci			"w83795: Detection failed at addr 0x%02hx, check %s\n",
192662306a36Sopenharmony_ci			address, "vendor id");
192762306a36Sopenharmony_ci		return -ENODEV;
192862306a36Sopenharmony_ci	}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_ci	/* Check device ID */
193162306a36Sopenharmony_ci	device_id = w83795_get_device_id(client) |
193262306a36Sopenharmony_ci		    (i2c_smbus_read_byte_data(client, W83795_REG_CHIPID) << 8);
193362306a36Sopenharmony_ci	if ((device_id >> 4) != 0x795) {
193462306a36Sopenharmony_ci		dev_dbg(&adapter->dev,
193562306a36Sopenharmony_ci			"w83795: Detection failed at addr 0x%02hx, check %s\n",
193662306a36Sopenharmony_ci			address, "device id\n");
193762306a36Sopenharmony_ci		return -ENODEV;
193862306a36Sopenharmony_ci	}
193962306a36Sopenharmony_ci
194062306a36Sopenharmony_ci	/*
194162306a36Sopenharmony_ci	 * If Nuvoton chip, address of chip and W83795_REG_I2C_ADDR
194262306a36Sopenharmony_ci	 * should match
194362306a36Sopenharmony_ci	 */
194462306a36Sopenharmony_ci	if ((bank & 0x07) == 0) {
194562306a36Sopenharmony_ci		i2c_addr = i2c_smbus_read_byte_data(client,
194662306a36Sopenharmony_ci						    W83795_REG_I2C_ADDR);
194762306a36Sopenharmony_ci		if ((i2c_addr & 0x7f) != address) {
194862306a36Sopenharmony_ci			dev_dbg(&adapter->dev,
194962306a36Sopenharmony_ci				"w83795: Detection failed at addr 0x%02hx, "
195062306a36Sopenharmony_ci				"check %s\n", address, "i2c addr");
195162306a36Sopenharmony_ci			return -ENODEV;
195262306a36Sopenharmony_ci		}
195362306a36Sopenharmony_ci	}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/*
195662306a36Sopenharmony_ci	 * Check 795 chip type: 795G or 795ADG
195762306a36Sopenharmony_ci	 * Usually we don't write to chips during detection, but here we don't
195862306a36Sopenharmony_ci	 * quite have the choice; hopefully it's OK, we are about to return
195962306a36Sopenharmony_ci	 * success anyway
196062306a36Sopenharmony_ci	 */
196162306a36Sopenharmony_ci	if ((bank & 0x07) != 0)
196262306a36Sopenharmony_ci		i2c_smbus_write_byte_data(client, W83795_REG_BANKSEL,
196362306a36Sopenharmony_ci					  bank & ~0x07);
196462306a36Sopenharmony_ci	config = i2c_smbus_read_byte_data(client, W83795_REG_CONFIG);
196562306a36Sopenharmony_ci	if (config & W83795_REG_CONFIG_CONFIG48)
196662306a36Sopenharmony_ci		chip_name = "w83795adg";
196762306a36Sopenharmony_ci	else
196862306a36Sopenharmony_ci		chip_name = "w83795g";
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	strscpy(info->type, chip_name, I2C_NAME_SIZE);
197162306a36Sopenharmony_ci	dev_info(&adapter->dev, "Found %s rev. %c at 0x%02hx\n", chip_name,
197262306a36Sopenharmony_ci		 'A' + (device_id & 0xf), address);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	return 0;
197562306a36Sopenharmony_ci}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci#ifdef CONFIG_SENSORS_W83795_FANCTRL
197862306a36Sopenharmony_ci#define NUM_PWM_ATTRIBUTES	ARRAY_SIZE(w83795_pwm[0])
197962306a36Sopenharmony_ci#define NUM_TEMP_ATTRIBUTES	ARRAY_SIZE(w83795_temp[0])
198062306a36Sopenharmony_ci#else
198162306a36Sopenharmony_ci#define NUM_PWM_ATTRIBUTES	4
198262306a36Sopenharmony_ci#define NUM_TEMP_ATTRIBUTES	8
198362306a36Sopenharmony_ci#endif
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_cistatic int w83795_handle_files(struct device *dev, int (*fn)(struct device *,
198662306a36Sopenharmony_ci			       const struct device_attribute *))
198762306a36Sopenharmony_ci{
198862306a36Sopenharmony_ci	struct w83795_data *data = dev_get_drvdata(dev);
198962306a36Sopenharmony_ci	int err, i, j;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w83795_in); i++) {
199262306a36Sopenharmony_ci		if (!(data->has_in & (1 << i)))
199362306a36Sopenharmony_ci			continue;
199462306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(w83795_in[0]); j++) {
199562306a36Sopenharmony_ci			if (j == 4 && !data->enable_beep)
199662306a36Sopenharmony_ci				continue;
199762306a36Sopenharmony_ci			err = fn(dev, &w83795_in[i][j].dev_attr);
199862306a36Sopenharmony_ci			if (err)
199962306a36Sopenharmony_ci				return err;
200062306a36Sopenharmony_ci		}
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w83795_fan); i++) {
200462306a36Sopenharmony_ci		if (!(data->has_fan & (1 << i)))
200562306a36Sopenharmony_ci			continue;
200662306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(w83795_fan[0]); j++) {
200762306a36Sopenharmony_ci			if (j == 3 && !data->enable_beep)
200862306a36Sopenharmony_ci				continue;
200962306a36Sopenharmony_ci			err = fn(dev, &w83795_fan[i][j].dev_attr);
201062306a36Sopenharmony_ci			if (err)
201162306a36Sopenharmony_ci				return err;
201262306a36Sopenharmony_ci		}
201362306a36Sopenharmony_ci	}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w83795_tss); i++) {
201662306a36Sopenharmony_ci		j = w83795_tss_useful(data, i);
201762306a36Sopenharmony_ci		if (!j)
201862306a36Sopenharmony_ci			continue;
201962306a36Sopenharmony_ci		err = fn(dev, &w83795_tss[i].dev_attr);
202062306a36Sopenharmony_ci		if (err)
202162306a36Sopenharmony_ci			return err;
202262306a36Sopenharmony_ci	}
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
202562306a36Sopenharmony_ci		err = fn(dev, &sda_single_files[i].dev_attr);
202662306a36Sopenharmony_ci		if (err)
202762306a36Sopenharmony_ci			return err;
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (data->enable_beep) {
203162306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(sda_beep_files); i++) {
203262306a36Sopenharmony_ci			err = fn(dev, &sda_beep_files[i].dev_attr);
203362306a36Sopenharmony_ci			if (err)
203462306a36Sopenharmony_ci				return err;
203562306a36Sopenharmony_ci		}
203662306a36Sopenharmony_ci	}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	for (i = 0; i < data->has_pwm; i++) {
203962306a36Sopenharmony_ci		for (j = 0; j < NUM_PWM_ATTRIBUTES; j++) {
204062306a36Sopenharmony_ci			err = fn(dev, &w83795_pwm[i][j].dev_attr);
204162306a36Sopenharmony_ci			if (err)
204262306a36Sopenharmony_ci				return err;
204362306a36Sopenharmony_ci		}
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(w83795_temp); i++) {
204762306a36Sopenharmony_ci		if (!(data->has_temp & (1 << i)))
204862306a36Sopenharmony_ci			continue;
204962306a36Sopenharmony_ci		for (j = 0; j < NUM_TEMP_ATTRIBUTES; j++) {
205062306a36Sopenharmony_ci			if (j == 7 && !data->enable_beep)
205162306a36Sopenharmony_ci				continue;
205262306a36Sopenharmony_ci			err = fn(dev, &w83795_temp[i][j].dev_attr);
205362306a36Sopenharmony_ci			if (err)
205462306a36Sopenharmony_ci				return err;
205562306a36Sopenharmony_ci		}
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	if (data->enable_dts) {
205962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(w83795_dts); i++) {
206062306a36Sopenharmony_ci			if (!(data->has_dts & (1 << i)))
206162306a36Sopenharmony_ci				continue;
206262306a36Sopenharmony_ci			for (j = 0; j < ARRAY_SIZE(w83795_dts[0]); j++) {
206362306a36Sopenharmony_ci				if (j == 7 && !data->enable_beep)
206462306a36Sopenharmony_ci					continue;
206562306a36Sopenharmony_ci				err = fn(dev, &w83795_dts[i][j].dev_attr);
206662306a36Sopenharmony_ci				if (err)
206762306a36Sopenharmony_ci					return err;
206862306a36Sopenharmony_ci			}
206962306a36Sopenharmony_ci		}
207062306a36Sopenharmony_ci	}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	return 0;
207362306a36Sopenharmony_ci}
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci/* We need a wrapper that fits in w83795_handle_files */
207662306a36Sopenharmony_cistatic int device_remove_file_wrapper(struct device *dev,
207762306a36Sopenharmony_ci				      const struct device_attribute *attr)
207862306a36Sopenharmony_ci{
207962306a36Sopenharmony_ci	device_remove_file(dev, attr);
208062306a36Sopenharmony_ci	return 0;
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic void w83795_check_dynamic_in_limits(struct i2c_client *client)
208462306a36Sopenharmony_ci{
208562306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
208662306a36Sopenharmony_ci	u8 vid_ctl;
208762306a36Sopenharmony_ci	int i, err_max, err_min;
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_ci	vid_ctl = w83795_read(client, W83795_REG_VID_CTRL);
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci	/* Return immediately if VRM isn't configured */
209262306a36Sopenharmony_ci	if ((vid_ctl & 0x07) == 0x00 || (vid_ctl & 0x07) == 0x07)
209362306a36Sopenharmony_ci		return;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	data->has_dyn_in = (vid_ctl >> 3) & 0x07;
209662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
209762306a36Sopenharmony_ci		if (!(data->has_dyn_in & (1 << i)))
209862306a36Sopenharmony_ci			continue;
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci		/* Voltage limits in dynamic mode, switch to read-only */
210162306a36Sopenharmony_ci		err_max = sysfs_chmod_file(&client->dev.kobj,
210262306a36Sopenharmony_ci					   &w83795_in[i][2].dev_attr.attr,
210362306a36Sopenharmony_ci					   S_IRUGO);
210462306a36Sopenharmony_ci		err_min = sysfs_chmod_file(&client->dev.kobj,
210562306a36Sopenharmony_ci					   &w83795_in[i][3].dev_attr.attr,
210662306a36Sopenharmony_ci					   S_IRUGO);
210762306a36Sopenharmony_ci		if (err_max || err_min)
210862306a36Sopenharmony_ci			dev_warn(&client->dev,
210962306a36Sopenharmony_ci				 "Failed to set in%d limits read-only (%d, %d)\n",
211062306a36Sopenharmony_ci				 i, err_max, err_min);
211162306a36Sopenharmony_ci		else
211262306a36Sopenharmony_ci			dev_info(&client->dev,
211362306a36Sopenharmony_ci				 "in%d limits set dynamically from VID\n", i);
211462306a36Sopenharmony_ci	}
211562306a36Sopenharmony_ci}
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci/* Check pins that can be used for either temperature or voltage monitoring */
211862306a36Sopenharmony_cistatic void w83795_apply_temp_config(struct w83795_data *data, u8 config,
211962306a36Sopenharmony_ci				     int temp_chan, int in_chan)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	/* config is a 2-bit value */
212262306a36Sopenharmony_ci	switch (config) {
212362306a36Sopenharmony_ci	case 0x2: /* Voltage monitoring */
212462306a36Sopenharmony_ci		data->has_in |= 1 << in_chan;
212562306a36Sopenharmony_ci		break;
212662306a36Sopenharmony_ci	case 0x1: /* Thermal diode */
212762306a36Sopenharmony_ci		if (temp_chan >= 4)
212862306a36Sopenharmony_ci			break;
212962306a36Sopenharmony_ci		data->temp_mode |= 1 << temp_chan;
213062306a36Sopenharmony_ci		fallthrough;
213162306a36Sopenharmony_ci	case 0x3: /* Thermistor */
213262306a36Sopenharmony_ci		data->has_temp |= 1 << temp_chan;
213362306a36Sopenharmony_ci		break;
213462306a36Sopenharmony_ci	}
213562306a36Sopenharmony_ci}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_cistatic const struct i2c_device_id w83795_id[];
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_cistatic int w83795_probe(struct i2c_client *client)
214062306a36Sopenharmony_ci{
214162306a36Sopenharmony_ci	int i;
214262306a36Sopenharmony_ci	u8 tmp;
214362306a36Sopenharmony_ci	struct device *dev = &client->dev;
214462306a36Sopenharmony_ci	struct w83795_data *data;
214562306a36Sopenharmony_ci	int err;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct w83795_data), GFP_KERNEL);
214862306a36Sopenharmony_ci	if (!data)
214962306a36Sopenharmony_ci		return -ENOMEM;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	i2c_set_clientdata(client, data);
215262306a36Sopenharmony_ci	data->chip_type = i2c_match_id(w83795_id, client)->driver_data;
215362306a36Sopenharmony_ci	data->bank = i2c_smbus_read_byte_data(client, W83795_REG_BANKSEL);
215462306a36Sopenharmony_ci	mutex_init(&data->update_lock);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	/* Initialize the chip */
215762306a36Sopenharmony_ci	w83795_init_client(client);
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	/* Check which voltages and fans are present */
216062306a36Sopenharmony_ci	data->has_in = w83795_read(client, W83795_REG_VOLT_CTRL1)
216162306a36Sopenharmony_ci		     | (w83795_read(client, W83795_REG_VOLT_CTRL2) << 8);
216262306a36Sopenharmony_ci	data->has_fan = w83795_read(client, W83795_REG_FANIN_CTRL1)
216362306a36Sopenharmony_ci		      | (w83795_read(client, W83795_REG_FANIN_CTRL2) << 8);
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	/* Check which analog temperatures and extra voltages are present */
216662306a36Sopenharmony_ci	tmp = w83795_read(client, W83795_REG_TEMP_CTRL1);
216762306a36Sopenharmony_ci	if (tmp & 0x20)
216862306a36Sopenharmony_ci		data->enable_dts = 1;
216962306a36Sopenharmony_ci	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 5, 16);
217062306a36Sopenharmony_ci	w83795_apply_temp_config(data, tmp & 0x3, 4, 15);
217162306a36Sopenharmony_ci	tmp = w83795_read(client, W83795_REG_TEMP_CTRL2);
217262306a36Sopenharmony_ci	w83795_apply_temp_config(data, tmp >> 6, 3, 20);
217362306a36Sopenharmony_ci	w83795_apply_temp_config(data, (tmp >> 4) & 0x3, 2, 19);
217462306a36Sopenharmony_ci	w83795_apply_temp_config(data, (tmp >> 2) & 0x3, 1, 18);
217562306a36Sopenharmony_ci	w83795_apply_temp_config(data, tmp & 0x3, 0, 17);
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci	/* Check DTS enable status */
217862306a36Sopenharmony_ci	if (data->enable_dts) {
217962306a36Sopenharmony_ci		if (1 & w83795_read(client, W83795_REG_DTSC))
218062306a36Sopenharmony_ci			data->enable_dts |= 2;
218162306a36Sopenharmony_ci		data->has_dts = w83795_read(client, W83795_REG_DTSE);
218262306a36Sopenharmony_ci	}
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	/* Report PECI Tbase values */
218562306a36Sopenharmony_ci	if (data->enable_dts == 1) {
218662306a36Sopenharmony_ci		for (i = 0; i < 8; i++) {
218762306a36Sopenharmony_ci			if (!(data->has_dts & (1 << i)))
218862306a36Sopenharmony_ci				continue;
218962306a36Sopenharmony_ci			tmp = w83795_read(client, W83795_REG_PECI_TBASE(i));
219062306a36Sopenharmony_ci			dev_info(&client->dev,
219162306a36Sopenharmony_ci				 "PECI agent %d Tbase temperature: %u\n",
219262306a36Sopenharmony_ci				 i + 1, (unsigned int)tmp & 0x7f);
219362306a36Sopenharmony_ci		}
219462306a36Sopenharmony_ci	}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	data->has_gain = w83795_read(client, W83795_REG_VMIGB_CTRL) & 0x0f;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci	/* pwm and smart fan */
219962306a36Sopenharmony_ci	if (data->chip_type == w83795g)
220062306a36Sopenharmony_ci		data->has_pwm = 8;
220162306a36Sopenharmony_ci	else
220262306a36Sopenharmony_ci		data->has_pwm = 2;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	/* Check if BEEP pin is available */
220562306a36Sopenharmony_ci	if (data->chip_type == w83795g) {
220662306a36Sopenharmony_ci		/* The W83795G has a dedicated BEEP pin */
220762306a36Sopenharmony_ci		data->enable_beep = 1;
220862306a36Sopenharmony_ci	} else {
220962306a36Sopenharmony_ci		/*
221062306a36Sopenharmony_ci		 * The W83795ADG has a shared pin for OVT# and BEEP, so you
221162306a36Sopenharmony_ci		 * can't have both
221262306a36Sopenharmony_ci		 */
221362306a36Sopenharmony_ci		tmp = w83795_read(client, W83795_REG_OVT_CFG);
221462306a36Sopenharmony_ci		if ((tmp & OVT_CFG_SEL) == 0)
221562306a36Sopenharmony_ci			data->enable_beep = 1;
221662306a36Sopenharmony_ci	}
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	err = w83795_handle_files(dev, device_create_file);
221962306a36Sopenharmony_ci	if (err)
222062306a36Sopenharmony_ci		goto exit_remove;
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (data->chip_type == w83795g)
222362306a36Sopenharmony_ci		w83795_check_dynamic_in_limits(client);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	data->hwmon_dev = hwmon_device_register(dev);
222662306a36Sopenharmony_ci	if (IS_ERR(data->hwmon_dev)) {
222762306a36Sopenharmony_ci		err = PTR_ERR(data->hwmon_dev);
222862306a36Sopenharmony_ci		goto exit_remove;
222962306a36Sopenharmony_ci	}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci	return 0;
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ciexit_remove:
223462306a36Sopenharmony_ci	w83795_handle_files(dev, device_remove_file_wrapper);
223562306a36Sopenharmony_ci	return err;
223662306a36Sopenharmony_ci}
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_cistatic void w83795_remove(struct i2c_client *client)
223962306a36Sopenharmony_ci{
224062306a36Sopenharmony_ci	struct w83795_data *data = i2c_get_clientdata(client);
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	hwmon_device_unregister(data->hwmon_dev);
224362306a36Sopenharmony_ci	w83795_handle_files(&client->dev, device_remove_file_wrapper);
224462306a36Sopenharmony_ci}
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci
224762306a36Sopenharmony_cistatic const struct i2c_device_id w83795_id[] = {
224862306a36Sopenharmony_ci	{ "w83795g", w83795g },
224962306a36Sopenharmony_ci	{ "w83795adg", w83795adg },
225062306a36Sopenharmony_ci	{ }
225162306a36Sopenharmony_ci};
225262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, w83795_id);
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_cistatic struct i2c_driver w83795_driver = {
225562306a36Sopenharmony_ci	.driver = {
225662306a36Sopenharmony_ci		   .name = "w83795",
225762306a36Sopenharmony_ci	},
225862306a36Sopenharmony_ci	.probe		= w83795_probe,
225962306a36Sopenharmony_ci	.remove		= w83795_remove,
226062306a36Sopenharmony_ci	.id_table	= w83795_id,
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
226362306a36Sopenharmony_ci	.detect		= w83795_detect,
226462306a36Sopenharmony_ci	.address_list	= normal_i2c,
226562306a36Sopenharmony_ci};
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_cimodule_i2c_driver(w83795_driver);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ciMODULE_AUTHOR("Wei Song, Jean Delvare <jdelvare@suse.de>");
227062306a36Sopenharmony_ciMODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver");
227162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2272