18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * adm1031.c - Part of lm_sensors, Linux kernel modules for hardware
48c2ecf20Sopenharmony_ci *	       monitoring
58c2ecf20Sopenharmony_ci * Based on lm75.c and lm85.c
68c2ecf20Sopenharmony_ci * Supports adm1030 / adm1031
78c2ecf20Sopenharmony_ci * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
88c2ecf20Sopenharmony_ci * Reworked by Jean Delvare <jdelvare@suse.de>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
158c2ecf20Sopenharmony_ci#include <linux/i2c.h>
168c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
178c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h>
188c2ecf20Sopenharmony_ci#include <linux/err.h>
198c2ecf20Sopenharmony_ci#include <linux/mutex.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Following macros takes channel parameter starting from 0 to 2 */
228c2ecf20Sopenharmony_ci#define ADM1031_REG_FAN_SPEED(nr)	(0x08 + (nr))
238c2ecf20Sopenharmony_ci#define ADM1031_REG_FAN_DIV(nr)		(0x20 + (nr))
248c2ecf20Sopenharmony_ci#define ADM1031_REG_PWM			(0x22)
258c2ecf20Sopenharmony_ci#define ADM1031_REG_FAN_MIN(nr)		(0x10 + (nr))
268c2ecf20Sopenharmony_ci#define ADM1031_REG_FAN_FILTER		(0x23)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define ADM1031_REG_TEMP_OFFSET(nr)	(0x0d + (nr))
298c2ecf20Sopenharmony_ci#define ADM1031_REG_TEMP_MAX(nr)	(0x14 + 4 * (nr))
308c2ecf20Sopenharmony_ci#define ADM1031_REG_TEMP_MIN(nr)	(0x15 + 4 * (nr))
318c2ecf20Sopenharmony_ci#define ADM1031_REG_TEMP_CRIT(nr)	(0x16 + 4 * (nr))
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define ADM1031_REG_TEMP(nr)		(0x0a + (nr))
348c2ecf20Sopenharmony_ci#define ADM1031_REG_AUTO_TEMP(nr)	(0x24 + (nr))
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define ADM1031_REG_STATUS(nr)		(0x2 + (nr))
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ADM1031_REG_CONF1		0x00
398c2ecf20Sopenharmony_ci#define ADM1031_REG_CONF2		0x01
408c2ecf20Sopenharmony_ci#define ADM1031_REG_EXT_TEMP		0x06
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define ADM1031_CONF1_MONITOR_ENABLE	0x01	/* Monitoring enable */
438c2ecf20Sopenharmony_ci#define ADM1031_CONF1_PWM_INVERT	0x08	/* PWM Invert */
448c2ecf20Sopenharmony_ci#define ADM1031_CONF1_AUTO_MODE		0x80	/* Auto FAN */
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define ADM1031_CONF2_PWM1_ENABLE	0x01
478c2ecf20Sopenharmony_ci#define ADM1031_CONF2_PWM2_ENABLE	0x02
488c2ecf20Sopenharmony_ci#define ADM1031_CONF2_TACH1_ENABLE	0x04
498c2ecf20Sopenharmony_ci#define ADM1031_CONF2_TACH2_ENABLE	0x08
508c2ecf20Sopenharmony_ci#define ADM1031_CONF2_TEMP_ENABLE(chan)	(0x10 << (chan))
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define ADM1031_UPDATE_RATE_MASK	0x1c
538c2ecf20Sopenharmony_ci#define ADM1031_UPDATE_RATE_SHIFT	2
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Addresses to scan */
568c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cienum chips { adm1030, adm1031 };
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_citypedef u8 auto_chan_table_t[8][2];
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci/* Each client has this additional data */
638c2ecf20Sopenharmony_cistruct adm1031_data {
648c2ecf20Sopenharmony_ci	struct i2c_client *client;
658c2ecf20Sopenharmony_ci	const struct attribute_group *groups[3];
668c2ecf20Sopenharmony_ci	struct mutex update_lock;
678c2ecf20Sopenharmony_ci	int chip_type;
688c2ecf20Sopenharmony_ci	char valid;		/* !=0 if following fields are valid */
698c2ecf20Sopenharmony_ci	unsigned long last_updated;	/* In jiffies */
708c2ecf20Sopenharmony_ci	unsigned int update_interval;	/* In milliseconds */
718c2ecf20Sopenharmony_ci	/*
728c2ecf20Sopenharmony_ci	 * The chan_select_table contains the possible configurations for
738c2ecf20Sopenharmony_ci	 * auto fan control.
748c2ecf20Sopenharmony_ci	 */
758c2ecf20Sopenharmony_ci	const auto_chan_table_t *chan_select_table;
768c2ecf20Sopenharmony_ci	u16 alarm;
778c2ecf20Sopenharmony_ci	u8 conf1;
788c2ecf20Sopenharmony_ci	u8 conf2;
798c2ecf20Sopenharmony_ci	u8 fan[2];
808c2ecf20Sopenharmony_ci	u8 fan_div[2];
818c2ecf20Sopenharmony_ci	u8 fan_min[2];
828c2ecf20Sopenharmony_ci	u8 pwm[2];
838c2ecf20Sopenharmony_ci	u8 old_pwm[2];
848c2ecf20Sopenharmony_ci	s8 temp[3];
858c2ecf20Sopenharmony_ci	u8 ext_temp[3];
868c2ecf20Sopenharmony_ci	u8 auto_temp[3];
878c2ecf20Sopenharmony_ci	u8 auto_temp_min[3];
888c2ecf20Sopenharmony_ci	u8 auto_temp_off[3];
898c2ecf20Sopenharmony_ci	u8 auto_temp_max[3];
908c2ecf20Sopenharmony_ci	s8 temp_offset[3];
918c2ecf20Sopenharmony_ci	s8 temp_min[3];
928c2ecf20Sopenharmony_ci	s8 temp_max[3];
938c2ecf20Sopenharmony_ci	s8 temp_crit[3];
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic inline u8 adm1031_read_value(struct i2c_client *client, u8 reg)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	return i2c_smbus_read_byte_data(client, reg);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic inline int
1028c2ecf20Sopenharmony_ciadm1031_write_value(struct i2c_client *client, u8 reg, unsigned int value)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	return i2c_smbus_write_byte_data(client, reg, value);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic struct adm1031_data *adm1031_update_device(struct device *dev)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
1108c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
1118c2ecf20Sopenharmony_ci	unsigned long next_update;
1128c2ecf20Sopenharmony_ci	int chan;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	next_update = data->last_updated
1178c2ecf20Sopenharmony_ci	  + msecs_to_jiffies(data->update_interval);
1188c2ecf20Sopenharmony_ci	if (time_after(jiffies, next_update) || !data->valid) {
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		dev_dbg(&client->dev, "Starting adm1031 update\n");
1218c2ecf20Sopenharmony_ci		for (chan = 0;
1228c2ecf20Sopenharmony_ci		     chan < ((data->chip_type == adm1031) ? 3 : 2); chan++) {
1238c2ecf20Sopenharmony_ci			u8 oldh, newh;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci			oldh =
1268c2ecf20Sopenharmony_ci			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
1278c2ecf20Sopenharmony_ci			data->ext_temp[chan] =
1288c2ecf20Sopenharmony_ci			    adm1031_read_value(client, ADM1031_REG_EXT_TEMP);
1298c2ecf20Sopenharmony_ci			newh =
1308c2ecf20Sopenharmony_ci			    adm1031_read_value(client, ADM1031_REG_TEMP(chan));
1318c2ecf20Sopenharmony_ci			if (newh != oldh) {
1328c2ecf20Sopenharmony_ci				data->ext_temp[chan] =
1338c2ecf20Sopenharmony_ci				    adm1031_read_value(client,
1348c2ecf20Sopenharmony_ci						       ADM1031_REG_EXT_TEMP);
1358c2ecf20Sopenharmony_ci#ifdef DEBUG
1368c2ecf20Sopenharmony_ci				oldh =
1378c2ecf20Sopenharmony_ci				    adm1031_read_value(client,
1388c2ecf20Sopenharmony_ci						       ADM1031_REG_TEMP(chan));
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci				/* oldh is actually newer */
1418c2ecf20Sopenharmony_ci				if (newh != oldh)
1428c2ecf20Sopenharmony_ci					dev_warn(&client->dev,
1438c2ecf20Sopenharmony_ci					  "Remote temperature may be wrong.\n");
1448c2ecf20Sopenharmony_ci#endif
1458c2ecf20Sopenharmony_ci			}
1468c2ecf20Sopenharmony_ci			data->temp[chan] = newh;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci			data->temp_offset[chan] =
1498c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1508c2ecf20Sopenharmony_ci					       ADM1031_REG_TEMP_OFFSET(chan));
1518c2ecf20Sopenharmony_ci			data->temp_min[chan] =
1528c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1538c2ecf20Sopenharmony_ci					       ADM1031_REG_TEMP_MIN(chan));
1548c2ecf20Sopenharmony_ci			data->temp_max[chan] =
1558c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1568c2ecf20Sopenharmony_ci					       ADM1031_REG_TEMP_MAX(chan));
1578c2ecf20Sopenharmony_ci			data->temp_crit[chan] =
1588c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1598c2ecf20Sopenharmony_ci					       ADM1031_REG_TEMP_CRIT(chan));
1608c2ecf20Sopenharmony_ci			data->auto_temp[chan] =
1618c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1628c2ecf20Sopenharmony_ci					       ADM1031_REG_AUTO_TEMP(chan));
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci		data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1);
1678c2ecf20Sopenharmony_ci		data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		data->alarm = adm1031_read_value(client, ADM1031_REG_STATUS(0))
1708c2ecf20Sopenharmony_ci		    | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) << 8);
1718c2ecf20Sopenharmony_ci		if (data->chip_type == adm1030)
1728c2ecf20Sopenharmony_ci			data->alarm &= 0xc0ff;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		for (chan = 0; chan < (data->chip_type == adm1030 ? 1 : 2);
1758c2ecf20Sopenharmony_ci		     chan++) {
1768c2ecf20Sopenharmony_ci			data->fan_div[chan] =
1778c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1788c2ecf20Sopenharmony_ci					       ADM1031_REG_FAN_DIV(chan));
1798c2ecf20Sopenharmony_ci			data->fan_min[chan] =
1808c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1818c2ecf20Sopenharmony_ci					       ADM1031_REG_FAN_MIN(chan));
1828c2ecf20Sopenharmony_ci			data->fan[chan] =
1838c2ecf20Sopenharmony_ci			    adm1031_read_value(client,
1848c2ecf20Sopenharmony_ci					       ADM1031_REG_FAN_SPEED(chan));
1858c2ecf20Sopenharmony_ci			data->pwm[chan] =
1868c2ecf20Sopenharmony_ci			  (adm1031_read_value(client,
1878c2ecf20Sopenharmony_ci					ADM1031_REG_PWM) >> (4 * chan)) & 0x0f;
1888c2ecf20Sopenharmony_ci		}
1898c2ecf20Sopenharmony_ci		data->last_updated = jiffies;
1908c2ecf20Sopenharmony_ci		data->valid = 1;
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return data;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci#define TEMP_TO_REG(val)		(((val) < 0 ? ((val - 500) / 1000) : \
1998c2ecf20Sopenharmony_ci					((val + 500) / 1000)))
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci#define TEMP_FROM_REG(val)		((val) * 1000)
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#define TEMP_FROM_REG_EXT(val, ext)	(TEMP_FROM_REG(val) + (ext) * 125)
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#define TEMP_OFFSET_TO_REG(val)		(TEMP_TO_REG(val) & 0x8f)
2068c2ecf20Sopenharmony_ci#define TEMP_OFFSET_FROM_REG(val)	TEMP_FROM_REG((val) < 0 ? \
2078c2ecf20Sopenharmony_ci						      (val) | 0x70 : (val))
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci#define FAN_FROM_REG(reg, div)		((reg) ? \
2108c2ecf20Sopenharmony_ci					 (11250 * 60) / ((reg) * (div)) : 0)
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int FAN_TO_REG(int reg, int div)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	int tmp;
2158c2ecf20Sopenharmony_ci	tmp = FAN_FROM_REG(clamp_val(reg, 0, 65535), div);
2168c2ecf20Sopenharmony_ci	return tmp > 255 ? 255 : tmp;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci#define FAN_DIV_FROM_REG(reg)		(1<<(((reg)&0xc0)>>6))
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci#define PWM_TO_REG(val)			(clamp_val((val), 0, 255) >> 4)
2228c2ecf20Sopenharmony_ci#define PWM_FROM_REG(val)		((val) << 4)
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci#define FAN_CHAN_FROM_REG(reg)		(((reg) >> 5) & 7)
2258c2ecf20Sopenharmony_ci#define FAN_CHAN_TO_REG(val, reg)	\
2268c2ecf20Sopenharmony_ci	(((reg) & 0x1F) | (((val) << 5) & 0xe0))
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci#define AUTO_TEMP_MIN_TO_REG(val, reg)	\
2298c2ecf20Sopenharmony_ci	((((val) / 500) & 0xf8) | ((reg) & 0x7))
2308c2ecf20Sopenharmony_ci#define AUTO_TEMP_RANGE_FROM_REG(reg)	(5000 * (1 << ((reg) & 0x7)))
2318c2ecf20Sopenharmony_ci#define AUTO_TEMP_MIN_FROM_REG(reg)	(1000 * ((((reg) >> 3) & 0x1f) << 2))
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci#define AUTO_TEMP_MIN_FROM_REG_DEG(reg)	((((reg) >> 3) & 0x1f) << 2)
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci#define AUTO_TEMP_OFF_FROM_REG(reg)		\
2368c2ecf20Sopenharmony_ci	(AUTO_TEMP_MIN_FROM_REG(reg) - 5000)
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci#define AUTO_TEMP_MAX_FROM_REG(reg)		\
2398c2ecf20Sopenharmony_ci	(AUTO_TEMP_RANGE_FROM_REG(reg) +	\
2408c2ecf20Sopenharmony_ci	AUTO_TEMP_MIN_FROM_REG(reg))
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int AUTO_TEMP_MAX_TO_REG(int val, int reg, int pwm)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	int ret;
2458c2ecf20Sopenharmony_ci	int range = val - AUTO_TEMP_MIN_FROM_REG(reg);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	range = ((val - AUTO_TEMP_MIN_FROM_REG(reg))*10)/(16 - pwm);
2488c2ecf20Sopenharmony_ci	ret = ((reg & 0xf8) |
2498c2ecf20Sopenharmony_ci	       (range < 10000 ? 0 :
2508c2ecf20Sopenharmony_ci		range < 20000 ? 1 :
2518c2ecf20Sopenharmony_ci		range < 40000 ? 2 : range < 80000 ? 3 : 4));
2528c2ecf20Sopenharmony_ci	return ret;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/* FAN auto control */
2568c2ecf20Sopenharmony_ci#define GET_FAN_AUTO_BITFIELD(data, idx)	\
2578c2ecf20Sopenharmony_ci	(*(data)->chan_select_table)[FAN_CHAN_FROM_REG((data)->conf1)][idx % 2]
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci/*
2608c2ecf20Sopenharmony_ci * The tables below contains the possible values for the auto fan
2618c2ecf20Sopenharmony_ci * control bitfields. the index in the table is the register value.
2628c2ecf20Sopenharmony_ci * MSb is the auto fan control enable bit, so the four first entries
2638c2ecf20Sopenharmony_ci * in the table disables auto fan control when both bitfields are zero.
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_cistatic const auto_chan_table_t auto_channel_select_table_adm1031 = {
2668c2ecf20Sopenharmony_ci	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2678c2ecf20Sopenharmony_ci	{ 2 /* 0b010 */ , 4 /* 0b100 */ },
2688c2ecf20Sopenharmony_ci	{ 2 /* 0b010 */ , 2 /* 0b010 */ },
2698c2ecf20Sopenharmony_ci	{ 4 /* 0b100 */ , 4 /* 0b100 */ },
2708c2ecf20Sopenharmony_ci	{ 7 /* 0b111 */ , 7 /* 0b111 */ },
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic const auto_chan_table_t auto_channel_select_table_adm1030 = {
2748c2ecf20Sopenharmony_ci	{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 },
2758c2ecf20Sopenharmony_ci	{ 2 /* 0b10 */		, 0 },
2768c2ecf20Sopenharmony_ci	{ 0xff /* invalid */	, 0 },
2778c2ecf20Sopenharmony_ci	{ 0xff /* invalid */	, 0 },
2788c2ecf20Sopenharmony_ci	{ 3 /* 0b11 */		, 0 },
2798c2ecf20Sopenharmony_ci};
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci/*
2828c2ecf20Sopenharmony_ci * That function checks if a bitfield is valid and returns the other bitfield
2838c2ecf20Sopenharmony_ci * nearest match if no exact match where found.
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_cistatic int
2868c2ecf20Sopenharmony_ciget_fan_auto_nearest(struct adm1031_data *data, int chan, u8 val, u8 reg)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	int i;
2898c2ecf20Sopenharmony_ci	int first_match = -1, exact_match = -1;
2908c2ecf20Sopenharmony_ci	u8 other_reg_val =
2918c2ecf20Sopenharmony_ci	    (*data->chan_select_table)[FAN_CHAN_FROM_REG(reg)][chan ? 0 : 1];
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	if (val == 0)
2948c2ecf20Sopenharmony_ci		return 0;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
2978c2ecf20Sopenharmony_ci		if ((val == (*data->chan_select_table)[i][chan]) &&
2988c2ecf20Sopenharmony_ci		    ((*data->chan_select_table)[i][chan ? 0 : 1] ==
2998c2ecf20Sopenharmony_ci		     other_reg_val)) {
3008c2ecf20Sopenharmony_ci			/* We found an exact match */
3018c2ecf20Sopenharmony_ci			exact_match = i;
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci		} else if (val == (*data->chan_select_table)[i][chan] &&
3048c2ecf20Sopenharmony_ci			   first_match == -1) {
3058c2ecf20Sopenharmony_ci			/*
3068c2ecf20Sopenharmony_ci			 * Save the first match in case of an exact match has
3078c2ecf20Sopenharmony_ci			 * not been found
3088c2ecf20Sopenharmony_ci			 */
3098c2ecf20Sopenharmony_ci			first_match = i;
3108c2ecf20Sopenharmony_ci		}
3118c2ecf20Sopenharmony_ci	}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (exact_match >= 0)
3148c2ecf20Sopenharmony_ci		return exact_match;
3158c2ecf20Sopenharmony_ci	else if (first_match >= 0)
3168c2ecf20Sopenharmony_ci		return first_match;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return -EINVAL;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic ssize_t fan_auto_channel_show(struct device *dev,
3228c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3258c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
3268c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", GET_FAN_AUTO_BITFIELD(data, nr));
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic ssize_t
3308c2ecf20Sopenharmony_cifan_auto_channel_store(struct device *dev, struct device_attribute *attr,
3318c2ecf20Sopenharmony_ci		       const char *buf, size_t count)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
3348c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
3358c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3368c2ecf20Sopenharmony_ci	long val;
3378c2ecf20Sopenharmony_ci	u8 reg;
3388c2ecf20Sopenharmony_ci	int ret;
3398c2ecf20Sopenharmony_ci	u8 old_fan_mode;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
3428c2ecf20Sopenharmony_ci	if (ret)
3438c2ecf20Sopenharmony_ci		return ret;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	old_fan_mode = data->conf1;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	ret = get_fan_auto_nearest(data, nr, val, data->conf1);
3508c2ecf20Sopenharmony_ci	if (ret < 0) {
3518c2ecf20Sopenharmony_ci		mutex_unlock(&data->update_lock);
3528c2ecf20Sopenharmony_ci		return ret;
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci	reg = ret;
3558c2ecf20Sopenharmony_ci	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3568c2ecf20Sopenharmony_ci	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) ^
3578c2ecf20Sopenharmony_ci	    (old_fan_mode & ADM1031_CONF1_AUTO_MODE)) {
3588c2ecf20Sopenharmony_ci		if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
3598c2ecf20Sopenharmony_ci			/*
3608c2ecf20Sopenharmony_ci			 * Switch to Auto Fan Mode
3618c2ecf20Sopenharmony_ci			 * Save PWM registers
3628c2ecf20Sopenharmony_ci			 * Set PWM registers to 33% Both
3638c2ecf20Sopenharmony_ci			 */
3648c2ecf20Sopenharmony_ci			data->old_pwm[0] = data->pwm[0];
3658c2ecf20Sopenharmony_ci			data->old_pwm[1] = data->pwm[1];
3668c2ecf20Sopenharmony_ci			adm1031_write_value(client, ADM1031_REG_PWM, 0x55);
3678c2ecf20Sopenharmony_ci		} else {
3688c2ecf20Sopenharmony_ci			/* Switch to Manual Mode */
3698c2ecf20Sopenharmony_ci			data->pwm[0] = data->old_pwm[0];
3708c2ecf20Sopenharmony_ci			data->pwm[1] = data->old_pwm[1];
3718c2ecf20Sopenharmony_ci			/* Restore PWM registers */
3728c2ecf20Sopenharmony_ci			adm1031_write_value(client, ADM1031_REG_PWM,
3738c2ecf20Sopenharmony_ci					    data->pwm[0] | (data->pwm[1] << 4));
3748c2ecf20Sopenharmony_ci		}
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci	data->conf1 = FAN_CHAN_TO_REG(reg, data->conf1);
3778c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_CONF1, data->conf1);
3788c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3798c2ecf20Sopenharmony_ci	return count;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan1_channel, fan_auto_channel, 0);
3838c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan2_channel, fan_auto_channel, 1);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci/* Auto Temps */
3868c2ecf20Sopenharmony_cistatic ssize_t auto_temp_off_show(struct device *dev,
3878c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3908c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
3918c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",
3928c2ecf20Sopenharmony_ci		       AUTO_TEMP_OFF_FROM_REG(data->auto_temp[nr]));
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_cistatic ssize_t auto_temp_min_show(struct device *dev,
3958c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
3988c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
3998c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",
4008c2ecf20Sopenharmony_ci		       AUTO_TEMP_MIN_FROM_REG(data->auto_temp[nr]));
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_cistatic ssize_t
4038c2ecf20Sopenharmony_ciauto_temp_min_store(struct device *dev, struct device_attribute *attr,
4048c2ecf20Sopenharmony_ci		    const char *buf, size_t count)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
4078c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
4088c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4098c2ecf20Sopenharmony_ci	long val;
4108c2ecf20Sopenharmony_ci	int ret;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
4138c2ecf20Sopenharmony_ci	if (ret)
4148c2ecf20Sopenharmony_ci		return ret;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	val = clamp_val(val, 0, 127000);
4178c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
4188c2ecf20Sopenharmony_ci	data->auto_temp[nr] = AUTO_TEMP_MIN_TO_REG(val, data->auto_temp[nr]);
4198c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4208c2ecf20Sopenharmony_ci			    data->auto_temp[nr]);
4218c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
4228c2ecf20Sopenharmony_ci	return count;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_cistatic ssize_t auto_temp_max_show(struct device *dev,
4258c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
4268c2ecf20Sopenharmony_ci{
4278c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4288c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
4298c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",
4308c2ecf20Sopenharmony_ci		       AUTO_TEMP_MAX_FROM_REG(data->auto_temp[nr]));
4318c2ecf20Sopenharmony_ci}
4328c2ecf20Sopenharmony_cistatic ssize_t
4338c2ecf20Sopenharmony_ciauto_temp_max_store(struct device *dev, struct device_attribute *attr,
4348c2ecf20Sopenharmony_ci		    const char *buf, size_t count)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
4378c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
4388c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4398c2ecf20Sopenharmony_ci	long val;
4408c2ecf20Sopenharmony_ci	int ret;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
4438c2ecf20Sopenharmony_ci	if (ret)
4448c2ecf20Sopenharmony_ci		return ret;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	val = clamp_val(val, 0, 127000);
4478c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
4488c2ecf20Sopenharmony_ci	data->temp_max[nr] = AUTO_TEMP_MAX_TO_REG(val, data->auto_temp[nr],
4498c2ecf20Sopenharmony_ci						  data->pwm[nr]);
4508c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_AUTO_TEMP(nr),
4518c2ecf20Sopenharmony_ci			    data->temp_max[nr]);
4528c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
4538c2ecf20Sopenharmony_ci	return count;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp1_off, auto_temp_off, 0);
4578c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp1_min, auto_temp_min, 0);
4588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp1_max, auto_temp_max, 0);
4598c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp2_off, auto_temp_off, 1);
4608c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp2_min, auto_temp_min, 1);
4618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp2_max, auto_temp_max, 1);
4628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(auto_temp3_off, auto_temp_off, 2);
4638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp3_min, auto_temp_min, 2);
4648c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_temp3_max, auto_temp_max, 2);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci/* pwm */
4678c2ecf20Sopenharmony_cistatic ssize_t pwm_show(struct device *dev, struct device_attribute *attr,
4688c2ecf20Sopenharmony_ci			char *buf)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4718c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
4728c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_cistatic ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
4758c2ecf20Sopenharmony_ci			 const char *buf, size_t count)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
4788c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
4798c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
4808c2ecf20Sopenharmony_ci	long val;
4818c2ecf20Sopenharmony_ci	int ret, reg;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
4848c2ecf20Sopenharmony_ci	if (ret)
4858c2ecf20Sopenharmony_ci		return ret;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
4888c2ecf20Sopenharmony_ci	if ((data->conf1 & ADM1031_CONF1_AUTO_MODE) &&
4898c2ecf20Sopenharmony_ci	    (((val>>4) & 0xf) != 5)) {
4908c2ecf20Sopenharmony_ci		/* In automatic mode, the only PWM accepted is 33% */
4918c2ecf20Sopenharmony_ci		mutex_unlock(&data->update_lock);
4928c2ecf20Sopenharmony_ci		return -EINVAL;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci	data->pwm[nr] = PWM_TO_REG(val);
4958c2ecf20Sopenharmony_ci	reg = adm1031_read_value(client, ADM1031_REG_PWM);
4968c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_PWM,
4978c2ecf20Sopenharmony_ci			    nr ? ((data->pwm[nr] << 4) & 0xf0) | (reg & 0xf)
4988c2ecf20Sopenharmony_ci			    : (data->pwm[nr] & 0xf) | (reg & 0xf0));
4998c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
5008c2ecf20Sopenharmony_ci	return count;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm1, pwm, 0);
5048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(pwm2, pwm, 1);
5058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan1_min_pwm, pwm, 0);
5068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(auto_fan2_min_pwm, pwm, 1);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci/* Fans */
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/*
5118c2ecf20Sopenharmony_ci * That function checks the cases where the fan reading is not
5128c2ecf20Sopenharmony_ci * relevant.  It is used to provide 0 as fan reading when the fan is
5138c2ecf20Sopenharmony_ci * not supposed to run
5148c2ecf20Sopenharmony_ci */
5158c2ecf20Sopenharmony_cistatic int trust_fan_readings(struct adm1031_data *data, int chan)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	int res = 0;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (data->conf1 & ADM1031_CONF1_AUTO_MODE) {
5208c2ecf20Sopenharmony_ci		switch (data->conf1 & 0x60) {
5218c2ecf20Sopenharmony_ci		case 0x00:
5228c2ecf20Sopenharmony_ci			/*
5238c2ecf20Sopenharmony_ci			 * remote temp1 controls fan1,
5248c2ecf20Sopenharmony_ci			 * remote temp2 controls fan2
5258c2ecf20Sopenharmony_ci			 */
5268c2ecf20Sopenharmony_ci			res = data->temp[chan+1] >=
5278c2ecf20Sopenharmony_ci			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[chan+1]);
5288c2ecf20Sopenharmony_ci			break;
5298c2ecf20Sopenharmony_ci		case 0x20:	/* remote temp1 controls both fans */
5308c2ecf20Sopenharmony_ci			res =
5318c2ecf20Sopenharmony_ci			    data->temp[1] >=
5328c2ecf20Sopenharmony_ci			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1]);
5338c2ecf20Sopenharmony_ci			break;
5348c2ecf20Sopenharmony_ci		case 0x40:	/* remote temp2 controls both fans */
5358c2ecf20Sopenharmony_ci			res =
5368c2ecf20Sopenharmony_ci			    data->temp[2] >=
5378c2ecf20Sopenharmony_ci			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]);
5388c2ecf20Sopenharmony_ci			break;
5398c2ecf20Sopenharmony_ci		case 0x60:	/* max controls both fans */
5408c2ecf20Sopenharmony_ci			res =
5418c2ecf20Sopenharmony_ci			    data->temp[0] >=
5428c2ecf20Sopenharmony_ci			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[0])
5438c2ecf20Sopenharmony_ci			    || data->temp[1] >=
5448c2ecf20Sopenharmony_ci			    AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[1])
5458c2ecf20Sopenharmony_ci			    || (data->chip_type == adm1031
5468c2ecf20Sopenharmony_ci				&& data->temp[2] >=
5478c2ecf20Sopenharmony_ci				AUTO_TEMP_MIN_FROM_REG_DEG(data->auto_temp[2]));
5488c2ecf20Sopenharmony_ci			break;
5498c2ecf20Sopenharmony_ci		}
5508c2ecf20Sopenharmony_ci	} else {
5518c2ecf20Sopenharmony_ci		res = data->pwm[chan] > 0;
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci	return res;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_cistatic ssize_t fan_show(struct device *dev, struct device_attribute *attr,
5578c2ecf20Sopenharmony_ci			char *buf)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5608c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
5618c2ecf20Sopenharmony_ci	int value;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	value = trust_fan_readings(data, nr) ? FAN_FROM_REG(data->fan[nr],
5648c2ecf20Sopenharmony_ci				 FAN_DIV_FROM_REG(data->fan_div[nr])) : 0;
5658c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", value);
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic ssize_t fan_div_show(struct device *dev, struct device_attribute *attr,
5698c2ecf20Sopenharmony_ci			    char *buf)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5728c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
5738c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", FAN_DIV_FROM_REG(data->fan_div[nr]));
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_cistatic ssize_t fan_min_show(struct device *dev, struct device_attribute *attr,
5768c2ecf20Sopenharmony_ci			    char *buf)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5798c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
5808c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",
5818c2ecf20Sopenharmony_ci		       FAN_FROM_REG(data->fan_min[nr],
5828c2ecf20Sopenharmony_ci				    FAN_DIV_FROM_REG(data->fan_div[nr])));
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_cistatic ssize_t fan_min_store(struct device *dev,
5858c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
5868c2ecf20Sopenharmony_ci			     size_t count)
5878c2ecf20Sopenharmony_ci{
5888c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
5898c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
5908c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
5918c2ecf20Sopenharmony_ci	long val;
5928c2ecf20Sopenharmony_ci	int ret;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
5958c2ecf20Sopenharmony_ci	if (ret)
5968c2ecf20Sopenharmony_ci		return ret;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
5998c2ecf20Sopenharmony_ci	if (val) {
6008c2ecf20Sopenharmony_ci		data->fan_min[nr] =
6018c2ecf20Sopenharmony_ci			FAN_TO_REG(val, FAN_DIV_FROM_REG(data->fan_div[nr]));
6028c2ecf20Sopenharmony_ci	} else {
6038c2ecf20Sopenharmony_ci		data->fan_min[nr] = 0xff;
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr), data->fan_min[nr]);
6068c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
6078c2ecf20Sopenharmony_ci	return count;
6088c2ecf20Sopenharmony_ci}
6098c2ecf20Sopenharmony_cistatic ssize_t fan_div_store(struct device *dev,
6108c2ecf20Sopenharmony_ci			     struct device_attribute *attr, const char *buf,
6118c2ecf20Sopenharmony_ci			     size_t count)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
6148c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
6158c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6168c2ecf20Sopenharmony_ci	long val;
6178c2ecf20Sopenharmony_ci	u8 tmp;
6188c2ecf20Sopenharmony_ci	int old_div;
6198c2ecf20Sopenharmony_ci	int new_min;
6208c2ecf20Sopenharmony_ci	int ret;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
6238c2ecf20Sopenharmony_ci	if (ret)
6248c2ecf20Sopenharmony_ci		return ret;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	tmp = val == 8 ? 0xc0 :
6278c2ecf20Sopenharmony_ci	      val == 4 ? 0x80 :
6288c2ecf20Sopenharmony_ci	      val == 2 ? 0x40 :
6298c2ecf20Sopenharmony_ci	      val == 1 ? 0x00 :
6308c2ecf20Sopenharmony_ci	      0xff;
6318c2ecf20Sopenharmony_ci	if (tmp == 0xff)
6328c2ecf20Sopenharmony_ci		return -EINVAL;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
6358c2ecf20Sopenharmony_ci	/* Get fresh readings */
6368c2ecf20Sopenharmony_ci	data->fan_div[nr] = adm1031_read_value(client,
6378c2ecf20Sopenharmony_ci					       ADM1031_REG_FAN_DIV(nr));
6388c2ecf20Sopenharmony_ci	data->fan_min[nr] = adm1031_read_value(client,
6398c2ecf20Sopenharmony_ci					       ADM1031_REG_FAN_MIN(nr));
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	/* Write the new clock divider and fan min */
6428c2ecf20Sopenharmony_ci	old_div = FAN_DIV_FROM_REG(data->fan_div[nr]);
6438c2ecf20Sopenharmony_ci	data->fan_div[nr] = tmp | (0x3f & data->fan_div[nr]);
6448c2ecf20Sopenharmony_ci	new_min = data->fan_min[nr] * old_div / val;
6458c2ecf20Sopenharmony_ci	data->fan_min[nr] = new_min > 0xff ? 0xff : new_min;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_FAN_DIV(nr),
6488c2ecf20Sopenharmony_ci			    data->fan_div[nr]);
6498c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_FAN_MIN(nr),
6508c2ecf20Sopenharmony_ci			    data->fan_min[nr]);
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	/* Invalidate the cache: fan speed is no longer valid */
6538c2ecf20Sopenharmony_ci	data->valid = 0;
6548c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
6558c2ecf20Sopenharmony_ci	return count;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_input, fan, 0);
6598c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_min, fan_min, 0);
6608c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan1_div, fan_div, 0);
6618c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_input, fan, 1);
6628c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_min, fan_min, 1);
6638c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(fan2_div, fan_div, 1);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci/* Temps */
6668c2ecf20Sopenharmony_cistatic ssize_t temp_show(struct device *dev, struct device_attribute *attr,
6678c2ecf20Sopenharmony_ci			 char *buf)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6708c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
6718c2ecf20Sopenharmony_ci	int ext;
6728c2ecf20Sopenharmony_ci	ext = nr == 0 ?
6738c2ecf20Sopenharmony_ci	    ((data->ext_temp[nr] >> 6) & 0x3) * 2 :
6748c2ecf20Sopenharmony_ci	    (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7));
6758c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG_EXT(data->temp[nr], ext));
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_cistatic ssize_t temp_offset_show(struct device *dev,
6788c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6818c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
6828c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n",
6838c2ecf20Sopenharmony_ci		       TEMP_OFFSET_FROM_REG(data->temp_offset[nr]));
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_cistatic ssize_t temp_min_show(struct device *dev,
6868c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
6878c2ecf20Sopenharmony_ci{
6888c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6898c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
6908c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[nr]));
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_cistatic ssize_t temp_max_show(struct device *dev,
6938c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
6968c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
6978c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[nr]));
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_cistatic ssize_t temp_crit_show(struct device *dev,
7008c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
7038c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
7048c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit[nr]));
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_cistatic ssize_t temp_offset_store(struct device *dev,
7078c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
7088c2ecf20Sopenharmony_ci				 const char *buf, size_t count)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
7118c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
7128c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
7138c2ecf20Sopenharmony_ci	long val;
7148c2ecf20Sopenharmony_ci	int ret;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
7178c2ecf20Sopenharmony_ci	if (ret)
7188c2ecf20Sopenharmony_ci		return ret;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	val = clamp_val(val, -15000, 15000);
7218c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
7228c2ecf20Sopenharmony_ci	data->temp_offset[nr] = TEMP_OFFSET_TO_REG(val);
7238c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_TEMP_OFFSET(nr),
7248c2ecf20Sopenharmony_ci			    data->temp_offset[nr]);
7258c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
7268c2ecf20Sopenharmony_ci	return count;
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_cistatic ssize_t temp_min_store(struct device *dev,
7298c2ecf20Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
7308c2ecf20Sopenharmony_ci			      size_t count)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
7338c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
7348c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
7358c2ecf20Sopenharmony_ci	long val;
7368c2ecf20Sopenharmony_ci	int ret;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
7398c2ecf20Sopenharmony_ci	if (ret)
7408c2ecf20Sopenharmony_ci		return ret;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	val = clamp_val(val, -55000, 127000);
7438c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
7448c2ecf20Sopenharmony_ci	data->temp_min[nr] = TEMP_TO_REG(val);
7458c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_TEMP_MIN(nr),
7468c2ecf20Sopenharmony_ci			    data->temp_min[nr]);
7478c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
7488c2ecf20Sopenharmony_ci	return count;
7498c2ecf20Sopenharmony_ci}
7508c2ecf20Sopenharmony_cistatic ssize_t temp_max_store(struct device *dev,
7518c2ecf20Sopenharmony_ci			      struct device_attribute *attr, const char *buf,
7528c2ecf20Sopenharmony_ci			      size_t count)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
7558c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
7568c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
7578c2ecf20Sopenharmony_ci	long val;
7588c2ecf20Sopenharmony_ci	int ret;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
7618c2ecf20Sopenharmony_ci	if (ret)
7628c2ecf20Sopenharmony_ci		return ret;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	val = clamp_val(val, -55000, 127000);
7658c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
7668c2ecf20Sopenharmony_ci	data->temp_max[nr] = TEMP_TO_REG(val);
7678c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_TEMP_MAX(nr),
7688c2ecf20Sopenharmony_ci			    data->temp_max[nr]);
7698c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
7708c2ecf20Sopenharmony_ci	return count;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_cistatic ssize_t temp_crit_store(struct device *dev,
7738c2ecf20Sopenharmony_ci			       struct device_attribute *attr, const char *buf,
7748c2ecf20Sopenharmony_ci			       size_t count)
7758c2ecf20Sopenharmony_ci{
7768c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
7778c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
7788c2ecf20Sopenharmony_ci	int nr = to_sensor_dev_attr(attr)->index;
7798c2ecf20Sopenharmony_ci	long val;
7808c2ecf20Sopenharmony_ci	int ret;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 10, &val);
7838c2ecf20Sopenharmony_ci	if (ret)
7848c2ecf20Sopenharmony_ci		return ret;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	val = clamp_val(val, -55000, 127000);
7878c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
7888c2ecf20Sopenharmony_ci	data->temp_crit[nr] = TEMP_TO_REG(val);
7898c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_TEMP_CRIT(nr),
7908c2ecf20Sopenharmony_ci			    data->temp_crit[nr]);
7918c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
7928c2ecf20Sopenharmony_ci	return count;
7938c2ecf20Sopenharmony_ci}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, temp, 0);
7968c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_offset, temp_offset, 0);
7978c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_min, temp_min, 0);
7988c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_max, temp_max, 0);
7998c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp1_crit, temp_crit, 0);
8008c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_input, temp, 1);
8018c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_offset, temp_offset, 1);
8028c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_min, temp_min, 1);
8038c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_max, temp_max, 1);
8048c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp2_crit, temp_crit, 1);
8058c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_input, temp, 2);
8068c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_offset, temp_offset, 2);
8078c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_min, temp_min, 2);
8088c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_max, temp_max, 2);
8098c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RW(temp3_crit, temp_crit, 2);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci/* Alarms */
8128c2ecf20Sopenharmony_cistatic ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
8138c2ecf20Sopenharmony_ci			   char *buf)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
8168c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", data->alarm);
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(alarms);
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic ssize_t alarm_show(struct device *dev, struct device_attribute *attr,
8228c2ecf20Sopenharmony_ci			  char *buf)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	int bitnr = to_sensor_dev_attr(attr)->index;
8258c2ecf20Sopenharmony_ci	struct adm1031_data *data = adm1031_update_device(dev);
8268c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", (data->alarm >> bitnr) & 1);
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_alarm, alarm, 0);
8308c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan1_fault, alarm, 1);
8318c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_max_alarm, alarm, 2);
8328c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_min_alarm, alarm, 3);
8338c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_crit_alarm, alarm, 4);
8348c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp2_fault, alarm, 5);
8358c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_max_alarm, alarm, 6);
8368c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_min_alarm, alarm, 7);
8378c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_alarm, alarm, 8);
8388c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(fan2_fault, alarm, 9);
8398c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_max_alarm, alarm, 10);
8408c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_min_alarm, alarm, 11);
8418c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_crit_alarm, alarm, 12);
8428c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp3_fault, alarm, 13);
8438c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_crit_alarm, alarm, 14);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci/* Update Interval */
8468c2ecf20Sopenharmony_cistatic const unsigned int update_intervals[] = {
8478c2ecf20Sopenharmony_ci	16000, 8000, 4000, 2000, 1000, 500, 250, 125,
8488c2ecf20Sopenharmony_ci};
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic ssize_t update_interval_show(struct device *dev,
8518c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", data->update_interval);
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic ssize_t update_interval_store(struct device *dev,
8598c2ecf20Sopenharmony_ci				     struct device_attribute *attr,
8608c2ecf20Sopenharmony_ci				     const char *buf, size_t count)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct adm1031_data *data = dev_get_drvdata(dev);
8638c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
8648c2ecf20Sopenharmony_ci	unsigned long val;
8658c2ecf20Sopenharmony_ci	int i, err;
8668c2ecf20Sopenharmony_ci	u8 reg;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	err = kstrtoul(buf, 10, &val);
8698c2ecf20Sopenharmony_ci	if (err)
8708c2ecf20Sopenharmony_ci		return err;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	/*
8738c2ecf20Sopenharmony_ci	 * Find the nearest update interval from the table.
8748c2ecf20Sopenharmony_ci	 * Use it to determine the matching update rate.
8758c2ecf20Sopenharmony_ci	 */
8768c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(update_intervals) - 1; i++) {
8778c2ecf20Sopenharmony_ci		if (val >= update_intervals[i])
8788c2ecf20Sopenharmony_ci			break;
8798c2ecf20Sopenharmony_ci	}
8808c2ecf20Sopenharmony_ci	/* if not found, we point to the last entry (lowest update interval) */
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* set the new update rate while preserving other settings */
8838c2ecf20Sopenharmony_ci	reg = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
8848c2ecf20Sopenharmony_ci	reg &= ~ADM1031_UPDATE_RATE_MASK;
8858c2ecf20Sopenharmony_ci	reg |= i << ADM1031_UPDATE_RATE_SHIFT;
8868c2ecf20Sopenharmony_ci	adm1031_write_value(client, ADM1031_REG_FAN_FILTER, reg);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
8898c2ecf20Sopenharmony_ci	data->update_interval = update_intervals[i];
8908c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	return count;
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(update_interval);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic struct attribute *adm1031_attributes[] = {
8988c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_input.dev_attr.attr,
8998c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_div.dev_attr.attr,
9008c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_min.dev_attr.attr,
9018c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_alarm.dev_attr.attr,
9028c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan1_fault.dev_attr.attr,
9038c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm1.dev_attr.attr,
9048c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_fan1_channel.dev_attr.attr,
9058c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_input.dev_attr.attr,
9068c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_offset.dev_attr.attr,
9078c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_min.dev_attr.attr,
9088c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
9098c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_max.dev_attr.attr,
9108c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
9118c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_crit.dev_attr.attr,
9128c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
9138c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_input.dev_attr.attr,
9148c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_offset.dev_attr.attr,
9158c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_min.dev_attr.attr,
9168c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
9178c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_max.dev_attr.attr,
9188c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
9198c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_crit.dev_attr.attr,
9208c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
9218c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp2_fault.dev_attr.attr,
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp1_off.dev_attr.attr,
9248c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp1_min.dev_attr.attr,
9258c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp1_max.dev_attr.attr,
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp2_off.dev_attr.attr,
9288c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp2_min.dev_attr.attr,
9298c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp2_max.dev_attr.attr,
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_fan1_min_pwm.dev_attr.attr,
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	&dev_attr_update_interval.attr,
9348c2ecf20Sopenharmony_ci	&dev_attr_alarms.attr,
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	NULL
9378c2ecf20Sopenharmony_ci};
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_cistatic const struct attribute_group adm1031_group = {
9408c2ecf20Sopenharmony_ci	.attrs = adm1031_attributes,
9418c2ecf20Sopenharmony_ci};
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_cistatic struct attribute *adm1031_attributes_opt[] = {
9448c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_input.dev_attr.attr,
9458c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_div.dev_attr.attr,
9468c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_min.dev_attr.attr,
9478c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_alarm.dev_attr.attr,
9488c2ecf20Sopenharmony_ci	&sensor_dev_attr_fan2_fault.dev_attr.attr,
9498c2ecf20Sopenharmony_ci	&sensor_dev_attr_pwm2.dev_attr.attr,
9508c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_fan2_channel.dev_attr.attr,
9518c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_input.dev_attr.attr,
9528c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_offset.dev_attr.attr,
9538c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_min.dev_attr.attr,
9548c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
9558c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_max.dev_attr.attr,
9568c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
9578c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_crit.dev_attr.attr,
9588c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
9598c2ecf20Sopenharmony_ci	&sensor_dev_attr_temp3_fault.dev_attr.attr,
9608c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp3_off.dev_attr.attr,
9618c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp3_min.dev_attr.attr,
9628c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_temp3_max.dev_attr.attr,
9638c2ecf20Sopenharmony_ci	&sensor_dev_attr_auto_fan2_min_pwm.dev_attr.attr,
9648c2ecf20Sopenharmony_ci	NULL
9658c2ecf20Sopenharmony_ci};
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_cistatic const struct attribute_group adm1031_group_opt = {
9688c2ecf20Sopenharmony_ci	.attrs = adm1031_attributes_opt,
9698c2ecf20Sopenharmony_ci};
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
9728c2ecf20Sopenharmony_cistatic int adm1031_detect(struct i2c_client *client,
9738c2ecf20Sopenharmony_ci			  struct i2c_board_info *info)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
9768c2ecf20Sopenharmony_ci	const char *name;
9778c2ecf20Sopenharmony_ci	int id, co;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
9808c2ecf20Sopenharmony_ci		return -ENODEV;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	id = i2c_smbus_read_byte_data(client, 0x3d);
9838c2ecf20Sopenharmony_ci	co = i2c_smbus_read_byte_data(client, 0x3e);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	if (!((id == 0x31 || id == 0x30) && co == 0x41))
9868c2ecf20Sopenharmony_ci		return -ENODEV;
9878c2ecf20Sopenharmony_ci	name = (id == 0x30) ? "adm1030" : "adm1031";
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	strlcpy(info->type, name, I2C_NAME_SIZE);
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	return 0;
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_cistatic void adm1031_init_client(struct i2c_client *client)
9958c2ecf20Sopenharmony_ci{
9968c2ecf20Sopenharmony_ci	unsigned int read_val;
9978c2ecf20Sopenharmony_ci	unsigned int mask;
9988c2ecf20Sopenharmony_ci	int i;
9998c2ecf20Sopenharmony_ci	struct adm1031_data *data = i2c_get_clientdata(client);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE);
10028c2ecf20Sopenharmony_ci	if (data->chip_type == adm1031) {
10038c2ecf20Sopenharmony_ci		mask |= (ADM1031_CONF2_PWM2_ENABLE |
10048c2ecf20Sopenharmony_ci			ADM1031_CONF2_TACH2_ENABLE);
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci	/* Initialize the ADM1031 chip (enables fan speed reading ) */
10078c2ecf20Sopenharmony_ci	read_val = adm1031_read_value(client, ADM1031_REG_CONF2);
10088c2ecf20Sopenharmony_ci	if ((read_val | mask) != read_val)
10098c2ecf20Sopenharmony_ci		adm1031_write_value(client, ADM1031_REG_CONF2, read_val | mask);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	read_val = adm1031_read_value(client, ADM1031_REG_CONF1);
10128c2ecf20Sopenharmony_ci	if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) {
10138c2ecf20Sopenharmony_ci		adm1031_write_value(client, ADM1031_REG_CONF1,
10148c2ecf20Sopenharmony_ci				    read_val | ADM1031_CONF1_MONITOR_ENABLE);
10158c2ecf20Sopenharmony_ci	}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	/* Read the chip's update rate */
10188c2ecf20Sopenharmony_ci	mask = ADM1031_UPDATE_RATE_MASK;
10198c2ecf20Sopenharmony_ci	read_val = adm1031_read_value(client, ADM1031_REG_FAN_FILTER);
10208c2ecf20Sopenharmony_ci	i = (read_val & mask) >> ADM1031_UPDATE_RATE_SHIFT;
10218c2ecf20Sopenharmony_ci	/* Save it as update interval */
10228c2ecf20Sopenharmony_ci	data->update_interval = update_intervals[i];
10238c2ecf20Sopenharmony_ci}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic const struct i2c_device_id adm1031_id[];
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cistatic int adm1031_probe(struct i2c_client *client)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
10308c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
10318c2ecf20Sopenharmony_ci	struct adm1031_data *data;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct adm1031_data), GFP_KERNEL);
10348c2ecf20Sopenharmony_ci	if (!data)
10358c2ecf20Sopenharmony_ci		return -ENOMEM;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
10388c2ecf20Sopenharmony_ci	data->client = client;
10398c2ecf20Sopenharmony_ci	data->chip_type = i2c_match_id(adm1031_id, client)->driver_data;
10408c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	if (data->chip_type == adm1030)
10438c2ecf20Sopenharmony_ci		data->chan_select_table = &auto_channel_select_table_adm1030;
10448c2ecf20Sopenharmony_ci	else
10458c2ecf20Sopenharmony_ci		data->chan_select_table = &auto_channel_select_table_adm1031;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	/* Initialize the ADM1031 chip */
10488c2ecf20Sopenharmony_ci	adm1031_init_client(client);
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	/* sysfs hooks */
10518c2ecf20Sopenharmony_ci	data->groups[0] = &adm1031_group;
10528c2ecf20Sopenharmony_ci	if (data->chip_type == adm1031)
10538c2ecf20Sopenharmony_ci		data->groups[1] = &adm1031_group_opt;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
10568c2ecf20Sopenharmony_ci							   data, data->groups);
10578c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic const struct i2c_device_id adm1031_id[] = {
10618c2ecf20Sopenharmony_ci	{ "adm1030", adm1030 },
10628c2ecf20Sopenharmony_ci	{ "adm1031", adm1031 },
10638c2ecf20Sopenharmony_ci	{ }
10648c2ecf20Sopenharmony_ci};
10658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, adm1031_id);
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_cistatic struct i2c_driver adm1031_driver = {
10688c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
10698c2ecf20Sopenharmony_ci	.driver = {
10708c2ecf20Sopenharmony_ci		.name = "adm1031",
10718c2ecf20Sopenharmony_ci	},
10728c2ecf20Sopenharmony_ci	.probe_new	= adm1031_probe,
10738c2ecf20Sopenharmony_ci	.id_table	= adm1031_id,
10748c2ecf20Sopenharmony_ci	.detect		= adm1031_detect,
10758c2ecf20Sopenharmony_ci	.address_list	= normal_i2c,
10768c2ecf20Sopenharmony_ci};
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cimodule_i2c_driver(adm1031_driver);
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>");
10818c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ADM1031/ADM1030 driver");
10828c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1083