18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
48c2ecf20Sopenharmony_ci *          monitoring
58c2ecf20Sopenharmony_ci * Copyright (C) 2003-2010  Jean Delvare <jdelvare@suse.de>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Based on the lm83 driver. The LM90 is a sensor chip made by National
88c2ecf20Sopenharmony_ci * Semiconductor. It reports up to two temperatures (its own plus up to
98c2ecf20Sopenharmony_ci * one external one) with a 0.125 deg resolution (1 deg for local
108c2ecf20Sopenharmony_ci * temperature) and a 3-4 deg accuracy.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This driver also supports the LM89 and LM99, two other sensor chips
138c2ecf20Sopenharmony_ci * made by National Semiconductor. Both have an increased remote
148c2ecf20Sopenharmony_ci * temperature measurement accuracy (1 degree), and the LM99
158c2ecf20Sopenharmony_ci * additionally shifts remote temperatures (measured and limits) by 16
168c2ecf20Sopenharmony_ci * degrees, which allows for higher temperatures measurement.
178c2ecf20Sopenharmony_ci * Note that there is no way to differentiate between both chips.
188c2ecf20Sopenharmony_ci * When device is auto-detected, the driver will assume an LM99.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * This driver also supports the LM86, another sensor chip made by
218c2ecf20Sopenharmony_ci * National Semiconductor. It is exactly similar to the LM90 except it
228c2ecf20Sopenharmony_ci * has a higher accuracy.
238c2ecf20Sopenharmony_ci *
248c2ecf20Sopenharmony_ci * This driver also supports the ADM1032, a sensor chip made by Analog
258c2ecf20Sopenharmony_ci * Devices. That chip is similar to the LM90, with a few differences
268c2ecf20Sopenharmony_ci * that are not handled by this driver. Among others, it has a higher
278c2ecf20Sopenharmony_ci * accuracy than the LM90, much like the LM86 does.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * This driver also supports the MAX6657, MAX6658 and MAX6659 sensor
308c2ecf20Sopenharmony_ci * chips made by Maxim. These chips are similar to the LM86.
318c2ecf20Sopenharmony_ci * Note that there is no easy way to differentiate between the three
328c2ecf20Sopenharmony_ci * variants. We use the device address to detect MAX6659, which will result
338c2ecf20Sopenharmony_ci * in a detection as max6657 if it is on address 0x4c. The extra address
348c2ecf20Sopenharmony_ci * and features of the MAX6659 are only supported if the chip is configured
358c2ecf20Sopenharmony_ci * explicitly as max6659, or if its address is not 0x4c.
368c2ecf20Sopenharmony_ci * These chips lack the remote temperature offset feature.
378c2ecf20Sopenharmony_ci *
388c2ecf20Sopenharmony_ci * This driver also supports the MAX6654 chip made by Maxim. This chip can be
398c2ecf20Sopenharmony_ci * at 9 different addresses, similar to MAX6680/MAX6681. The MAX6654 is similar
408c2ecf20Sopenharmony_ci * to MAX6657/MAX6658/MAX6659, but does not support critical temperature
418c2ecf20Sopenharmony_ci * limits. Extended range is available by setting the configuration register
428c2ecf20Sopenharmony_ci * accordingly, and is done during initialization. Extended precision is only
438c2ecf20Sopenharmony_ci * available at conversion rates of 1 Hz and slower. Note that extended
448c2ecf20Sopenharmony_ci * precision is not enabled by default, as this driver initializes all chips
458c2ecf20Sopenharmony_ci * to 2 Hz by design.
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * This driver also supports the MAX6646, MAX6647, MAX6648, MAX6649 and
488c2ecf20Sopenharmony_ci * MAX6692 chips made by Maxim.  These are again similar to the LM86,
498c2ecf20Sopenharmony_ci * but they use unsigned temperature values and can report temperatures
508c2ecf20Sopenharmony_ci * from 0 to 145 degrees.
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * This driver also supports the MAX6680 and MAX6681, two other sensor
538c2ecf20Sopenharmony_ci * chips made by Maxim. These are quite similar to the other Maxim
548c2ecf20Sopenharmony_ci * chips. The MAX6680 and MAX6681 only differ in the pinout so they can
558c2ecf20Sopenharmony_ci * be treated identically.
568c2ecf20Sopenharmony_ci *
578c2ecf20Sopenharmony_ci * This driver also supports the MAX6695 and MAX6696, two other sensor
588c2ecf20Sopenharmony_ci * chips made by Maxim. These are also quite similar to other Maxim
598c2ecf20Sopenharmony_ci * chips, but support three temperature sensors instead of two. MAX6695
608c2ecf20Sopenharmony_ci * and MAX6696 only differ in the pinout so they can be treated identically.
618c2ecf20Sopenharmony_ci *
628c2ecf20Sopenharmony_ci * This driver also supports ADT7461 and ADT7461A from Analog Devices as well as
638c2ecf20Sopenharmony_ci * NCT1008 from ON Semiconductor. The chips are supported in both compatibility
648c2ecf20Sopenharmony_ci * and extended mode. They are mostly compatible with LM90 except for a data
658c2ecf20Sopenharmony_ci * format difference for the temperature value registers.
668c2ecf20Sopenharmony_ci *
678c2ecf20Sopenharmony_ci * This driver also supports the SA56004 from Philips. This device is
688c2ecf20Sopenharmony_ci * pin-compatible with the LM86, the ED/EDP parts are also address-compatible.
698c2ecf20Sopenharmony_ci *
708c2ecf20Sopenharmony_ci * This driver also supports the G781 from GMT. This device is compatible
718c2ecf20Sopenharmony_ci * with the ADM1032.
728c2ecf20Sopenharmony_ci *
738c2ecf20Sopenharmony_ci * This driver also supports TMP451 and TMP461 from Texas Instruments.
748c2ecf20Sopenharmony_ci * Those devices are supported in both compatibility and extended mode.
758c2ecf20Sopenharmony_ci * They are mostly compatible with ADT7461 except for local temperature
768c2ecf20Sopenharmony_ci * low byte register and max conversion rate.
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * Since the LM90 was the first chipset supported by this driver, most
798c2ecf20Sopenharmony_ci * comments will refer to this chipset, but are actually general and
808c2ecf20Sopenharmony_ci * concern all supported chipsets, unless mentioned otherwise.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#include <linux/module.h>
848c2ecf20Sopenharmony_ci#include <linux/init.h>
858c2ecf20Sopenharmony_ci#include <linux/slab.h>
868c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
878c2ecf20Sopenharmony_ci#include <linux/i2c.h>
888c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
898c2ecf20Sopenharmony_ci#include <linux/err.h>
908c2ecf20Sopenharmony_ci#include <linux/mutex.h>
918c2ecf20Sopenharmony_ci#include <linux/of_device.h>
928c2ecf20Sopenharmony_ci#include <linux/sysfs.h>
938c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
948c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/*
978c2ecf20Sopenharmony_ci * Addresses to scan
988c2ecf20Sopenharmony_ci * Address is fully defined internally and cannot be changed except for
998c2ecf20Sopenharmony_ci * MAX6659, MAX6680 and MAX6681.
1008c2ecf20Sopenharmony_ci * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, ADT7461A, MAX6649,
1018c2ecf20Sopenharmony_ci * MAX6657, MAX6658, NCT1008 and W83L771 have address 0x4c.
1028c2ecf20Sopenharmony_ci * ADM1032-2, ADT7461-2, ADT7461A-2, LM89-1, LM99-1, MAX6646, and NCT1008D
1038c2ecf20Sopenharmony_ci * have address 0x4d.
1048c2ecf20Sopenharmony_ci * MAX6647 has address 0x4e.
1058c2ecf20Sopenharmony_ci * MAX6659 can have address 0x4c, 0x4d or 0x4e.
1068c2ecf20Sopenharmony_ci * MAX6654, MAX6680, and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29,
1078c2ecf20Sopenharmony_ci * 0x2a, 0x2b, 0x4c, 0x4d or 0x4e.
1088c2ecf20Sopenharmony_ci * SA56004 can have address 0x48 through 0x4F.
1098c2ecf20Sopenharmony_ci */
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = {
1128c2ecf20Sopenharmony_ci	0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
1138c2ecf20Sopenharmony_ci	0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cienum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
1168c2ecf20Sopenharmony_ci	max6646, w83l771, max6696, sa56004, g781, tmp451, tmp461, max6654 };
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/*
1198c2ecf20Sopenharmony_ci * The LM90 registers
1208c2ecf20Sopenharmony_ci */
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci#define LM90_REG_R_MAN_ID		0xFE
1238c2ecf20Sopenharmony_ci#define LM90_REG_R_CHIP_ID		0xFF
1248c2ecf20Sopenharmony_ci#define LM90_REG_R_CONFIG1		0x03
1258c2ecf20Sopenharmony_ci#define LM90_REG_W_CONFIG1		0x09
1268c2ecf20Sopenharmony_ci#define LM90_REG_R_CONFIG2		0xBF
1278c2ecf20Sopenharmony_ci#define LM90_REG_W_CONFIG2		0xBF
1288c2ecf20Sopenharmony_ci#define LM90_REG_R_CONVRATE		0x04
1298c2ecf20Sopenharmony_ci#define LM90_REG_W_CONVRATE		0x0A
1308c2ecf20Sopenharmony_ci#define LM90_REG_R_STATUS		0x02
1318c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_TEMP		0x00
1328c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_HIGH		0x05
1338c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_HIGH		0x0B
1348c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_LOW		0x06
1358c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_LOW		0x0C
1368c2ecf20Sopenharmony_ci#define LM90_REG_R_LOCAL_CRIT		0x20
1378c2ecf20Sopenharmony_ci#define LM90_REG_W_LOCAL_CRIT		0x20
1388c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_TEMPH		0x01
1398c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_TEMPL		0x10
1408c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_OFFSH		0x11
1418c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_OFFSH		0x11
1428c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_OFFSL		0x12
1438c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_OFFSL		0x12
1448c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_HIGHH		0x07
1458c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_HIGHH		0x0D
1468c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_HIGHL		0x13
1478c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_HIGHL		0x13
1488c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_LOWH		0x08
1498c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_LOWH		0x0E
1508c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_LOWL		0x14
1518c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_LOWL		0x14
1528c2ecf20Sopenharmony_ci#define LM90_REG_R_REMOTE_CRIT		0x19
1538c2ecf20Sopenharmony_ci#define LM90_REG_W_REMOTE_CRIT		0x19
1548c2ecf20Sopenharmony_ci#define LM90_REG_R_TCRIT_HYST		0x21
1558c2ecf20Sopenharmony_ci#define LM90_REG_W_TCRIT_HYST		0x21
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/* MAX6646/6647/6649/6654/6657/6658/6659/6695/6696 registers */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci#define MAX6657_REG_R_LOCAL_TEMPL	0x11
1608c2ecf20Sopenharmony_ci#define MAX6696_REG_R_STATUS2		0x12
1618c2ecf20Sopenharmony_ci#define MAX6659_REG_R_REMOTE_EMERG	0x16
1628c2ecf20Sopenharmony_ci#define MAX6659_REG_W_REMOTE_EMERG	0x16
1638c2ecf20Sopenharmony_ci#define MAX6659_REG_R_LOCAL_EMERG	0x17
1648c2ecf20Sopenharmony_ci#define MAX6659_REG_W_LOCAL_EMERG	0x17
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci/*  SA56004 registers */
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#define SA56004_REG_R_LOCAL_TEMPL 0x22
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define LM90_MAX_CONVRATE_MS	16000	/* Maximum conversion rate in ms */
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci/* TMP451/TMP461 registers */
1738c2ecf20Sopenharmony_ci#define TMP451_REG_R_LOCAL_TEMPL	0x15
1748c2ecf20Sopenharmony_ci#define TMP451_REG_CONALERT		0x22
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci#define TMP461_REG_CHEN			0x16
1778c2ecf20Sopenharmony_ci#define TMP461_REG_DFC			0x24
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci/*
1808c2ecf20Sopenharmony_ci * Device flags
1818c2ecf20Sopenharmony_ci */
1828c2ecf20Sopenharmony_ci#define LM90_FLAG_ADT7461_EXT	(1 << 0) /* ADT7461 extended mode	*/
1838c2ecf20Sopenharmony_ci/* Device features */
1848c2ecf20Sopenharmony_ci#define LM90_HAVE_OFFSET	(1 << 1) /* temperature offset register	*/
1858c2ecf20Sopenharmony_ci#define LM90_HAVE_REM_LIMIT_EXT	(1 << 3) /* extended remote limit	*/
1868c2ecf20Sopenharmony_ci#define LM90_HAVE_EMERGENCY	(1 << 4) /* 3rd upper (emergency) limit	*/
1878c2ecf20Sopenharmony_ci#define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
1888c2ecf20Sopenharmony_ci#define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
1898c2ecf20Sopenharmony_ci#define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
1908c2ecf20Sopenharmony_ci#define LM90_HAVE_EXTENDED_TEMP	(1 << 8) /* extended temperature support*/
1918c2ecf20Sopenharmony_ci#define LM90_PAUSE_FOR_CONFIG	(1 << 9) /* Pause conversion for config	*/
1928c2ecf20Sopenharmony_ci#define LM90_HAVE_CRIT		(1 << 10)/* Chip supports CRIT/OVERT register	*/
1938c2ecf20Sopenharmony_ci#define LM90_HAVE_CRIT_ALRM_SWP	(1 << 11)/* critical alarm bits swapped	*/
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/* LM90 status */
1968c2ecf20Sopenharmony_ci#define LM90_STATUS_LTHRM	(1 << 0) /* local THERM limit tripped */
1978c2ecf20Sopenharmony_ci#define LM90_STATUS_RTHRM	(1 << 1) /* remote THERM limit tripped */
1988c2ecf20Sopenharmony_ci#define LM90_STATUS_ROPEN	(1 << 2) /* remote is an open circuit */
1998c2ecf20Sopenharmony_ci#define LM90_STATUS_RLOW	(1 << 3) /* remote low temp limit tripped */
2008c2ecf20Sopenharmony_ci#define LM90_STATUS_RHIGH	(1 << 4) /* remote high temp limit tripped */
2018c2ecf20Sopenharmony_ci#define LM90_STATUS_LLOW	(1 << 5) /* local low temp limit tripped */
2028c2ecf20Sopenharmony_ci#define LM90_STATUS_LHIGH	(1 << 6) /* local high temp limit tripped */
2038c2ecf20Sopenharmony_ci#define LM90_STATUS_BUSY	(1 << 7) /* conversion is ongoing */
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2THRM	(1 << 1) /* remote2 THERM limit tripped */
2068c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2OPEN	(1 << 2) /* remote2 is an open circuit */
2078c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2LOW	(1 << 3) /* remote2 low temp limit tripped */
2088c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2HIGH	(1 << 4) /* remote2 high temp limit tripped */
2098c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_ROT2	(1 << 5) /* remote emergency limit tripped */
2108c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_R2OT2	(1 << 6) /* remote2 emergency limit tripped */
2118c2ecf20Sopenharmony_ci#define MAX6696_STATUS2_LOT2	(1 << 7) /* local emergency limit tripped */
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/*
2148c2ecf20Sopenharmony_ci * Driver data (common to all clients)
2158c2ecf20Sopenharmony_ci */
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic const struct i2c_device_id lm90_id[] = {
2188c2ecf20Sopenharmony_ci	{ "adm1032", adm1032 },
2198c2ecf20Sopenharmony_ci	{ "adt7461", adt7461 },
2208c2ecf20Sopenharmony_ci	{ "adt7461a", adt7461 },
2218c2ecf20Sopenharmony_ci	{ "g781", g781 },
2228c2ecf20Sopenharmony_ci	{ "lm90", lm90 },
2238c2ecf20Sopenharmony_ci	{ "lm86", lm86 },
2248c2ecf20Sopenharmony_ci	{ "lm89", lm86 },
2258c2ecf20Sopenharmony_ci	{ "lm99", lm99 },
2268c2ecf20Sopenharmony_ci	{ "max6646", max6646 },
2278c2ecf20Sopenharmony_ci	{ "max6647", max6646 },
2288c2ecf20Sopenharmony_ci	{ "max6649", max6646 },
2298c2ecf20Sopenharmony_ci	{ "max6654", max6654 },
2308c2ecf20Sopenharmony_ci	{ "max6657", max6657 },
2318c2ecf20Sopenharmony_ci	{ "max6658", max6657 },
2328c2ecf20Sopenharmony_ci	{ "max6659", max6659 },
2338c2ecf20Sopenharmony_ci	{ "max6680", max6680 },
2348c2ecf20Sopenharmony_ci	{ "max6681", max6680 },
2358c2ecf20Sopenharmony_ci	{ "max6695", max6696 },
2368c2ecf20Sopenharmony_ci	{ "max6696", max6696 },
2378c2ecf20Sopenharmony_ci	{ "nct1008", adt7461 },
2388c2ecf20Sopenharmony_ci	{ "w83l771", w83l771 },
2398c2ecf20Sopenharmony_ci	{ "sa56004", sa56004 },
2408c2ecf20Sopenharmony_ci	{ "tmp451", tmp451 },
2418c2ecf20Sopenharmony_ci	{ "tmp461", tmp461 },
2428c2ecf20Sopenharmony_ci	{ }
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, lm90_id);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic const struct of_device_id __maybe_unused lm90_of_match[] = {
2478c2ecf20Sopenharmony_ci	{
2488c2ecf20Sopenharmony_ci		.compatible = "adi,adm1032",
2498c2ecf20Sopenharmony_ci		.data = (void *)adm1032
2508c2ecf20Sopenharmony_ci	},
2518c2ecf20Sopenharmony_ci	{
2528c2ecf20Sopenharmony_ci		.compatible = "adi,adt7461",
2538c2ecf20Sopenharmony_ci		.data = (void *)adt7461
2548c2ecf20Sopenharmony_ci	},
2558c2ecf20Sopenharmony_ci	{
2568c2ecf20Sopenharmony_ci		.compatible = "adi,adt7461a",
2578c2ecf20Sopenharmony_ci		.data = (void *)adt7461
2588c2ecf20Sopenharmony_ci	},
2598c2ecf20Sopenharmony_ci	{
2608c2ecf20Sopenharmony_ci		.compatible = "gmt,g781",
2618c2ecf20Sopenharmony_ci		.data = (void *)g781
2628c2ecf20Sopenharmony_ci	},
2638c2ecf20Sopenharmony_ci	{
2648c2ecf20Sopenharmony_ci		.compatible = "national,lm90",
2658c2ecf20Sopenharmony_ci		.data = (void *)lm90
2668c2ecf20Sopenharmony_ci	},
2678c2ecf20Sopenharmony_ci	{
2688c2ecf20Sopenharmony_ci		.compatible = "national,lm86",
2698c2ecf20Sopenharmony_ci		.data = (void *)lm86
2708c2ecf20Sopenharmony_ci	},
2718c2ecf20Sopenharmony_ci	{
2728c2ecf20Sopenharmony_ci		.compatible = "national,lm89",
2738c2ecf20Sopenharmony_ci		.data = (void *)lm86
2748c2ecf20Sopenharmony_ci	},
2758c2ecf20Sopenharmony_ci	{
2768c2ecf20Sopenharmony_ci		.compatible = "national,lm99",
2778c2ecf20Sopenharmony_ci		.data = (void *)lm99
2788c2ecf20Sopenharmony_ci	},
2798c2ecf20Sopenharmony_ci	{
2808c2ecf20Sopenharmony_ci		.compatible = "dallas,max6646",
2818c2ecf20Sopenharmony_ci		.data = (void *)max6646
2828c2ecf20Sopenharmony_ci	},
2838c2ecf20Sopenharmony_ci	{
2848c2ecf20Sopenharmony_ci		.compatible = "dallas,max6647",
2858c2ecf20Sopenharmony_ci		.data = (void *)max6646
2868c2ecf20Sopenharmony_ci	},
2878c2ecf20Sopenharmony_ci	{
2888c2ecf20Sopenharmony_ci		.compatible = "dallas,max6649",
2898c2ecf20Sopenharmony_ci		.data = (void *)max6646
2908c2ecf20Sopenharmony_ci	},
2918c2ecf20Sopenharmony_ci	{
2928c2ecf20Sopenharmony_ci		.compatible = "dallas,max6654",
2938c2ecf20Sopenharmony_ci		.data = (void *)max6654
2948c2ecf20Sopenharmony_ci	},
2958c2ecf20Sopenharmony_ci	{
2968c2ecf20Sopenharmony_ci		.compatible = "dallas,max6657",
2978c2ecf20Sopenharmony_ci		.data = (void *)max6657
2988c2ecf20Sopenharmony_ci	},
2998c2ecf20Sopenharmony_ci	{
3008c2ecf20Sopenharmony_ci		.compatible = "dallas,max6658",
3018c2ecf20Sopenharmony_ci		.data = (void *)max6657
3028c2ecf20Sopenharmony_ci	},
3038c2ecf20Sopenharmony_ci	{
3048c2ecf20Sopenharmony_ci		.compatible = "dallas,max6659",
3058c2ecf20Sopenharmony_ci		.data = (void *)max6659
3068c2ecf20Sopenharmony_ci	},
3078c2ecf20Sopenharmony_ci	{
3088c2ecf20Sopenharmony_ci		.compatible = "dallas,max6680",
3098c2ecf20Sopenharmony_ci		.data = (void *)max6680
3108c2ecf20Sopenharmony_ci	},
3118c2ecf20Sopenharmony_ci	{
3128c2ecf20Sopenharmony_ci		.compatible = "dallas,max6681",
3138c2ecf20Sopenharmony_ci		.data = (void *)max6680
3148c2ecf20Sopenharmony_ci	},
3158c2ecf20Sopenharmony_ci	{
3168c2ecf20Sopenharmony_ci		.compatible = "dallas,max6695",
3178c2ecf20Sopenharmony_ci		.data = (void *)max6696
3188c2ecf20Sopenharmony_ci	},
3198c2ecf20Sopenharmony_ci	{
3208c2ecf20Sopenharmony_ci		.compatible = "dallas,max6696",
3218c2ecf20Sopenharmony_ci		.data = (void *)max6696
3228c2ecf20Sopenharmony_ci	},
3238c2ecf20Sopenharmony_ci	{
3248c2ecf20Sopenharmony_ci		.compatible = "onnn,nct1008",
3258c2ecf20Sopenharmony_ci		.data = (void *)adt7461
3268c2ecf20Sopenharmony_ci	},
3278c2ecf20Sopenharmony_ci	{
3288c2ecf20Sopenharmony_ci		.compatible = "winbond,w83l771",
3298c2ecf20Sopenharmony_ci		.data = (void *)w83l771
3308c2ecf20Sopenharmony_ci	},
3318c2ecf20Sopenharmony_ci	{
3328c2ecf20Sopenharmony_ci		.compatible = "nxp,sa56004",
3338c2ecf20Sopenharmony_ci		.data = (void *)sa56004
3348c2ecf20Sopenharmony_ci	},
3358c2ecf20Sopenharmony_ci	{
3368c2ecf20Sopenharmony_ci		.compatible = "ti,tmp451",
3378c2ecf20Sopenharmony_ci		.data = (void *)tmp451
3388c2ecf20Sopenharmony_ci	},
3398c2ecf20Sopenharmony_ci	{
3408c2ecf20Sopenharmony_ci		.compatible = "ti,tmp461",
3418c2ecf20Sopenharmony_ci		.data = (void *)tmp461
3428c2ecf20Sopenharmony_ci	},
3438c2ecf20Sopenharmony_ci	{ },
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, lm90_of_match);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci/*
3488c2ecf20Sopenharmony_ci * chip type specific parameters
3498c2ecf20Sopenharmony_ci */
3508c2ecf20Sopenharmony_cistruct lm90_params {
3518c2ecf20Sopenharmony_ci	u32 flags;		/* Capabilities */
3528c2ecf20Sopenharmony_ci	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
3538c2ecf20Sopenharmony_ci				/* Upper 8 bits for max6695/96 */
3548c2ecf20Sopenharmony_ci	u8 max_convrate;	/* Maximum conversion rate register value */
3558c2ecf20Sopenharmony_ci	u8 reg_local_ext;	/* Extended local temp register (optional) */
3568c2ecf20Sopenharmony_ci};
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic const struct lm90_params lm90_params[] = {
3598c2ecf20Sopenharmony_ci	[adm1032] = {
3608c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3618c2ecf20Sopenharmony_ci		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
3628c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
3638c2ecf20Sopenharmony_ci		.max_convrate = 10,
3648c2ecf20Sopenharmony_ci	},
3658c2ecf20Sopenharmony_ci	[adt7461] = {
3668c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3678c2ecf20Sopenharmony_ci		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP
3688c2ecf20Sopenharmony_ci		  | LM90_HAVE_CRIT,
3698c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
3708c2ecf20Sopenharmony_ci		.max_convrate = 10,
3718c2ecf20Sopenharmony_ci	},
3728c2ecf20Sopenharmony_ci	[g781] = {
3738c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3748c2ecf20Sopenharmony_ci		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_CRIT,
3758c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
3768c2ecf20Sopenharmony_ci		.max_convrate = 7,
3778c2ecf20Sopenharmony_ci	},
3788c2ecf20Sopenharmony_ci	[lm86] = {
3798c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3808c2ecf20Sopenharmony_ci		  | LM90_HAVE_CRIT,
3818c2ecf20Sopenharmony_ci		.alert_alarms = 0x7b,
3828c2ecf20Sopenharmony_ci		.max_convrate = 9,
3838c2ecf20Sopenharmony_ci	},
3848c2ecf20Sopenharmony_ci	[lm90] = {
3858c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3868c2ecf20Sopenharmony_ci		  | LM90_HAVE_CRIT,
3878c2ecf20Sopenharmony_ci		.alert_alarms = 0x7b,
3888c2ecf20Sopenharmony_ci		.max_convrate = 9,
3898c2ecf20Sopenharmony_ci	},
3908c2ecf20Sopenharmony_ci	[lm99] = {
3918c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
3928c2ecf20Sopenharmony_ci		  | LM90_HAVE_CRIT,
3938c2ecf20Sopenharmony_ci		.alert_alarms = 0x7b,
3948c2ecf20Sopenharmony_ci		.max_convrate = 9,
3958c2ecf20Sopenharmony_ci	},
3968c2ecf20Sopenharmony_ci	[max6646] = {
3978c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_CRIT | LM90_HAVE_BROKEN_ALERT,
3988c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
3998c2ecf20Sopenharmony_ci		.max_convrate = 6,
4008c2ecf20Sopenharmony_ci		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
4018c2ecf20Sopenharmony_ci	},
4028c2ecf20Sopenharmony_ci	[max6654] = {
4038c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_BROKEN_ALERT,
4048c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4058c2ecf20Sopenharmony_ci		.max_convrate = 7,
4068c2ecf20Sopenharmony_ci		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
4078c2ecf20Sopenharmony_ci	},
4088c2ecf20Sopenharmony_ci	[max6657] = {
4098c2ecf20Sopenharmony_ci		.flags = LM90_PAUSE_FOR_CONFIG | LM90_HAVE_CRIT,
4108c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4118c2ecf20Sopenharmony_ci		.max_convrate = 8,
4128c2ecf20Sopenharmony_ci		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
4138c2ecf20Sopenharmony_ci	},
4148c2ecf20Sopenharmony_ci	[max6659] = {
4158c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_EMERGENCY | LM90_HAVE_CRIT,
4168c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4178c2ecf20Sopenharmony_ci		.max_convrate = 8,
4188c2ecf20Sopenharmony_ci		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
4198c2ecf20Sopenharmony_ci	},
4208c2ecf20Sopenharmony_ci	[max6680] = {
4218c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_CRIT
4228c2ecf20Sopenharmony_ci		  | LM90_HAVE_CRIT_ALRM_SWP | LM90_HAVE_BROKEN_ALERT,
4238c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4248c2ecf20Sopenharmony_ci		.max_convrate = 7,
4258c2ecf20Sopenharmony_ci	},
4268c2ecf20Sopenharmony_ci	[max6696] = {
4278c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_EMERGENCY
4288c2ecf20Sopenharmony_ci		  | LM90_HAVE_EMERGENCY_ALARM | LM90_HAVE_TEMP3 | LM90_HAVE_CRIT,
4298c2ecf20Sopenharmony_ci		.alert_alarms = 0x1c7c,
4308c2ecf20Sopenharmony_ci		.max_convrate = 6,
4318c2ecf20Sopenharmony_ci		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
4328c2ecf20Sopenharmony_ci	},
4338c2ecf20Sopenharmony_ci	[w83l771] = {
4348c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
4358c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4368c2ecf20Sopenharmony_ci		.max_convrate = 8,
4378c2ecf20Sopenharmony_ci	},
4388c2ecf20Sopenharmony_ci	[sa56004] = {
4398c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT | LM90_HAVE_CRIT,
4408c2ecf20Sopenharmony_ci		.alert_alarms = 0x7b,
4418c2ecf20Sopenharmony_ci		.max_convrate = 9,
4428c2ecf20Sopenharmony_ci		.reg_local_ext = SA56004_REG_R_LOCAL_TEMPL,
4438c2ecf20Sopenharmony_ci	},
4448c2ecf20Sopenharmony_ci	[tmp451] = {
4458c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
4468c2ecf20Sopenharmony_ci		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
4478c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4488c2ecf20Sopenharmony_ci		.max_convrate = 9,
4498c2ecf20Sopenharmony_ci		.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
4508c2ecf20Sopenharmony_ci	},
4518c2ecf20Sopenharmony_ci	[tmp461] = {
4528c2ecf20Sopenharmony_ci		.flags = LM90_HAVE_OFFSET | LM90_HAVE_REM_LIMIT_EXT
4538c2ecf20Sopenharmony_ci		  | LM90_HAVE_BROKEN_ALERT | LM90_HAVE_EXTENDED_TEMP | LM90_HAVE_CRIT,
4548c2ecf20Sopenharmony_ci		.alert_alarms = 0x7c,
4558c2ecf20Sopenharmony_ci		.max_convrate = 9,
4568c2ecf20Sopenharmony_ci		.reg_local_ext = TMP451_REG_R_LOCAL_TEMPL,
4578c2ecf20Sopenharmony_ci	},
4588c2ecf20Sopenharmony_ci};
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/*
4618c2ecf20Sopenharmony_ci * TEMP8 register index
4628c2ecf20Sopenharmony_ci */
4638c2ecf20Sopenharmony_cienum lm90_temp8_reg_index {
4648c2ecf20Sopenharmony_ci	LOCAL_LOW = 0,
4658c2ecf20Sopenharmony_ci	LOCAL_HIGH,
4668c2ecf20Sopenharmony_ci	LOCAL_CRIT,
4678c2ecf20Sopenharmony_ci	REMOTE_CRIT,
4688c2ecf20Sopenharmony_ci	LOCAL_EMERG,	/* max6659 and max6695/96 */
4698c2ecf20Sopenharmony_ci	REMOTE_EMERG,	/* max6659 and max6695/96 */
4708c2ecf20Sopenharmony_ci	REMOTE2_CRIT,	/* max6695/96 only */
4718c2ecf20Sopenharmony_ci	REMOTE2_EMERG,	/* max6695/96 only */
4728c2ecf20Sopenharmony_ci	TEMP8_REG_NUM
4738c2ecf20Sopenharmony_ci};
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci/*
4768c2ecf20Sopenharmony_ci * TEMP11 register index
4778c2ecf20Sopenharmony_ci */
4788c2ecf20Sopenharmony_cienum lm90_temp11_reg_index {
4798c2ecf20Sopenharmony_ci	REMOTE_TEMP = 0,
4808c2ecf20Sopenharmony_ci	REMOTE_LOW,
4818c2ecf20Sopenharmony_ci	REMOTE_HIGH,
4828c2ecf20Sopenharmony_ci	REMOTE_OFFSET,	/* except max6646, max6657/58/59, and max6695/96 */
4838c2ecf20Sopenharmony_ci	LOCAL_TEMP,
4848c2ecf20Sopenharmony_ci	REMOTE2_TEMP,	/* max6695/96 only */
4858c2ecf20Sopenharmony_ci	REMOTE2_LOW,	/* max6695/96 only */
4868c2ecf20Sopenharmony_ci	REMOTE2_HIGH,	/* max6695/96 only */
4878c2ecf20Sopenharmony_ci	TEMP11_REG_NUM
4888c2ecf20Sopenharmony_ci};
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci/*
4918c2ecf20Sopenharmony_ci * Client data (each client gets its own)
4928c2ecf20Sopenharmony_ci */
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistruct lm90_data {
4958c2ecf20Sopenharmony_ci	struct i2c_client *client;
4968c2ecf20Sopenharmony_ci	u32 channel_config[4];
4978c2ecf20Sopenharmony_ci	struct hwmon_channel_info temp_info;
4988c2ecf20Sopenharmony_ci	const struct hwmon_channel_info *info[3];
4998c2ecf20Sopenharmony_ci	struct hwmon_chip_info chip;
5008c2ecf20Sopenharmony_ci	struct mutex update_lock;
5018c2ecf20Sopenharmony_ci	bool valid;		/* true if register values are valid */
5028c2ecf20Sopenharmony_ci	unsigned long last_updated; /* in jiffies */
5038c2ecf20Sopenharmony_ci	int kind;
5048c2ecf20Sopenharmony_ci	u32 flags;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	unsigned int update_interval; /* in milliseconds */
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	u8 config;		/* Current configuration register value */
5098c2ecf20Sopenharmony_ci	u8 config_orig;		/* Original configuration register value */
5108c2ecf20Sopenharmony_ci	u8 convrate_orig;	/* Original conversion rate register value */
5118c2ecf20Sopenharmony_ci	u16 alert_alarms;	/* Which alarm bits trigger ALERT# */
5128c2ecf20Sopenharmony_ci				/* Upper 8 bits for max6695/96 */
5138c2ecf20Sopenharmony_ci	u8 max_convrate;	/* Maximum conversion rate */
5148c2ecf20Sopenharmony_ci	u8 reg_local_ext;	/* local extension register offset */
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	/* registers values */
5178c2ecf20Sopenharmony_ci	s8 temp8[TEMP8_REG_NUM];
5188c2ecf20Sopenharmony_ci	s16 temp11[TEMP11_REG_NUM];
5198c2ecf20Sopenharmony_ci	u8 temp_hyst;
5208c2ecf20Sopenharmony_ci	u16 alarms; /* bitvector (upper 8 bits for max6695/96) */
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/*
5248c2ecf20Sopenharmony_ci * Support functions
5258c2ecf20Sopenharmony_ci */
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci/*
5288c2ecf20Sopenharmony_ci * The ADM1032 supports PEC but not on write byte transactions, so we need
5298c2ecf20Sopenharmony_ci * to explicitly ask for a transaction without PEC.
5308c2ecf20Sopenharmony_ci */
5318c2ecf20Sopenharmony_cistatic inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	return i2c_smbus_xfer(client->adapter, client->addr,
5348c2ecf20Sopenharmony_ci			      client->flags & ~I2C_CLIENT_PEC,
5358c2ecf20Sopenharmony_ci			      I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci/*
5398c2ecf20Sopenharmony_ci * It is assumed that client->update_lock is held (unless we are in
5408c2ecf20Sopenharmony_ci * detection or initialization steps). This matters when PEC is enabled,
5418c2ecf20Sopenharmony_ci * because we don't want the address pointer to change between the write
5428c2ecf20Sopenharmony_ci * byte and the read byte transactions.
5438c2ecf20Sopenharmony_ci */
5448c2ecf20Sopenharmony_cistatic int lm90_read_reg(struct i2c_client *client, u8 reg)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	int err;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (client->flags & I2C_CLIENT_PEC) {
5498c2ecf20Sopenharmony_ci		err = adm1032_write_byte(client, reg);
5508c2ecf20Sopenharmony_ci		if (err >= 0)
5518c2ecf20Sopenharmony_ci			err = i2c_smbus_read_byte(client);
5528c2ecf20Sopenharmony_ci	} else
5538c2ecf20Sopenharmony_ci		err = i2c_smbus_read_byte_data(client, reg);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return err;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic int lm90_read16(struct i2c_client *client, u8 regh, u8 regl)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	int oldh, newh, l;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/*
5638c2ecf20Sopenharmony_ci	 * There is a trick here. We have to read two registers to have the
5648c2ecf20Sopenharmony_ci	 * sensor temperature, but we have to beware a conversion could occur
5658c2ecf20Sopenharmony_ci	 * between the readings. The datasheet says we should either use
5668c2ecf20Sopenharmony_ci	 * the one-shot conversion register, which we don't want to do
5678c2ecf20Sopenharmony_ci	 * (disables hardware monitoring) or monitor the busy bit, which is
5688c2ecf20Sopenharmony_ci	 * impossible (we can't read the values and monitor that bit at the
5698c2ecf20Sopenharmony_ci	 * exact same time). So the solution used here is to read the high
5708c2ecf20Sopenharmony_ci	 * byte once, then the low byte, then the high byte again. If the new
5718c2ecf20Sopenharmony_ci	 * high byte matches the old one, then we have a valid reading. Else
5728c2ecf20Sopenharmony_ci	 * we have to read the low byte again, and now we believe we have a
5738c2ecf20Sopenharmony_ci	 * correct reading.
5748c2ecf20Sopenharmony_ci	 */
5758c2ecf20Sopenharmony_ci	oldh = lm90_read_reg(client, regh);
5768c2ecf20Sopenharmony_ci	if (oldh < 0)
5778c2ecf20Sopenharmony_ci		return oldh;
5788c2ecf20Sopenharmony_ci	l = lm90_read_reg(client, regl);
5798c2ecf20Sopenharmony_ci	if (l < 0)
5808c2ecf20Sopenharmony_ci		return l;
5818c2ecf20Sopenharmony_ci	newh = lm90_read_reg(client, regh);
5828c2ecf20Sopenharmony_ci	if (newh < 0)
5838c2ecf20Sopenharmony_ci		return newh;
5848c2ecf20Sopenharmony_ci	if (oldh != newh) {
5858c2ecf20Sopenharmony_ci		l = lm90_read_reg(client, regl);
5868c2ecf20Sopenharmony_ci		if (l < 0)
5878c2ecf20Sopenharmony_ci			return l;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	return (newh << 8) | l;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic int lm90_update_confreg(struct lm90_data *data, u8 config)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	if (data->config != config) {
5958c2ecf20Sopenharmony_ci		int err;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte_data(data->client,
5988c2ecf20Sopenharmony_ci						LM90_REG_W_CONFIG1,
5998c2ecf20Sopenharmony_ci						config);
6008c2ecf20Sopenharmony_ci		if (err)
6018c2ecf20Sopenharmony_ci			return err;
6028c2ecf20Sopenharmony_ci		data->config = config;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci	return 0;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci/*
6088c2ecf20Sopenharmony_ci * client->update_lock must be held when calling this function (unless we are
6098c2ecf20Sopenharmony_ci * in detection or initialization steps), and while a remote channel other
6108c2ecf20Sopenharmony_ci * than channel 0 is selected. Also, calling code must make sure to re-select
6118c2ecf20Sopenharmony_ci * external channel 0 before releasing the lock. This is necessary because
6128c2ecf20Sopenharmony_ci * various registers have different meanings as a result of selecting a
6138c2ecf20Sopenharmony_ci * non-default remote channel.
6148c2ecf20Sopenharmony_ci */
6158c2ecf20Sopenharmony_cistatic int lm90_select_remote_channel(struct lm90_data *data, int channel)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	int err = 0;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	if (data->kind == max6696) {
6208c2ecf20Sopenharmony_ci		u8 config = data->config & ~0x08;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		if (channel)
6238c2ecf20Sopenharmony_ci			config |= 0x08;
6248c2ecf20Sopenharmony_ci		err = lm90_update_confreg(data, config);
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci	return err;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int lm90_write_convrate(struct lm90_data *data, int val)
6308c2ecf20Sopenharmony_ci{
6318c2ecf20Sopenharmony_ci	u8 config = data->config;
6328c2ecf20Sopenharmony_ci	int err;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* Save config and pause conversion */
6358c2ecf20Sopenharmony_ci	if (data->flags & LM90_PAUSE_FOR_CONFIG) {
6368c2ecf20Sopenharmony_ci		err = lm90_update_confreg(data, config | 0x40);
6378c2ecf20Sopenharmony_ci		if (err < 0)
6388c2ecf20Sopenharmony_ci			return err;
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	/* Set conv rate */
6428c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte_data(data->client, LM90_REG_W_CONVRATE, val);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	/* Revert change to config */
6458c2ecf20Sopenharmony_ci	lm90_update_confreg(data, config);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return err;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci/*
6518c2ecf20Sopenharmony_ci * Set conversion rate.
6528c2ecf20Sopenharmony_ci * client->update_lock must be held when calling this function (unless we are
6538c2ecf20Sopenharmony_ci * in detection or initialization steps).
6548c2ecf20Sopenharmony_ci */
6558c2ecf20Sopenharmony_cistatic int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
6568c2ecf20Sopenharmony_ci			     unsigned int interval)
6578c2ecf20Sopenharmony_ci{
6588c2ecf20Sopenharmony_ci	unsigned int update_interval;
6598c2ecf20Sopenharmony_ci	int i, err;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci	/* Shift calculations to avoid rounding errors */
6628c2ecf20Sopenharmony_ci	interval <<= 6;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* find the nearest update rate */
6658c2ecf20Sopenharmony_ci	for (i = 0, update_interval = LM90_MAX_CONVRATE_MS << 6;
6668c2ecf20Sopenharmony_ci	     i < data->max_convrate; i++, update_interval >>= 1)
6678c2ecf20Sopenharmony_ci		if (interval >= update_interval * 3 / 4)
6688c2ecf20Sopenharmony_ci			break;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	err = lm90_write_convrate(data, i);
6718c2ecf20Sopenharmony_ci	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
6728c2ecf20Sopenharmony_ci	return err;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_cistatic int lm90_update_limits(struct device *dev)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
6788c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
6798c2ecf20Sopenharmony_ci	int val;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_CRIT) {
6828c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_LOCAL_CRIT);
6838c2ecf20Sopenharmony_ci		if (val < 0)
6848c2ecf20Sopenharmony_ci			return val;
6858c2ecf20Sopenharmony_ci		data->temp8[LOCAL_CRIT] = val;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
6888c2ecf20Sopenharmony_ci		if (val < 0)
6898c2ecf20Sopenharmony_ci			return val;
6908c2ecf20Sopenharmony_ci		data->temp8[REMOTE_CRIT] = val;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_TCRIT_HYST);
6938c2ecf20Sopenharmony_ci		if (val < 0)
6948c2ecf20Sopenharmony_ci			return val;
6958c2ecf20Sopenharmony_ci		data->temp_hyst = val;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
6998c2ecf20Sopenharmony_ci	if (val < 0)
7008c2ecf20Sopenharmony_ci		return val;
7018c2ecf20Sopenharmony_ci	data->temp11[REMOTE_LOW] = val << 8;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
7048c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWL);
7058c2ecf20Sopenharmony_ci		if (val < 0)
7068c2ecf20Sopenharmony_ci			return val;
7078c2ecf20Sopenharmony_ci		data->temp11[REMOTE_LOW] |= val;
7088c2ecf20Sopenharmony_ci	}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH);
7118c2ecf20Sopenharmony_ci	if (val < 0)
7128c2ecf20Sopenharmony_ci		return val;
7138c2ecf20Sopenharmony_ci	data->temp11[REMOTE_HIGH] = val << 8;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_REM_LIMIT_EXT) {
7168c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHL);
7178c2ecf20Sopenharmony_ci		if (val < 0)
7188c2ecf20Sopenharmony_ci			return val;
7198c2ecf20Sopenharmony_ci		data->temp11[REMOTE_HIGH] |= val;
7208c2ecf20Sopenharmony_ci	}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_OFFSET) {
7238c2ecf20Sopenharmony_ci		val = lm90_read16(client, LM90_REG_R_REMOTE_OFFSH,
7248c2ecf20Sopenharmony_ci				  LM90_REG_R_REMOTE_OFFSL);
7258c2ecf20Sopenharmony_ci		if (val < 0)
7268c2ecf20Sopenharmony_ci			return val;
7278c2ecf20Sopenharmony_ci		data->temp11[REMOTE_OFFSET] = val;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EMERGENCY) {
7318c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, MAX6659_REG_R_LOCAL_EMERG);
7328c2ecf20Sopenharmony_ci		if (val < 0)
7338c2ecf20Sopenharmony_ci			return val;
7348c2ecf20Sopenharmony_ci		data->temp8[LOCAL_EMERG] = val;
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG);
7378c2ecf20Sopenharmony_ci		if (val < 0)
7388c2ecf20Sopenharmony_ci			return val;
7398c2ecf20Sopenharmony_ci		data->temp8[REMOTE_EMERG] = val;
7408c2ecf20Sopenharmony_ci	}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	if (data->kind == max6696) {
7438c2ecf20Sopenharmony_ci		val = lm90_select_remote_channel(data, 1);
7448c2ecf20Sopenharmony_ci		if (val < 0)
7458c2ecf20Sopenharmony_ci			return val;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_CRIT);
7488c2ecf20Sopenharmony_ci		if (val < 0)
7498c2ecf20Sopenharmony_ci			return val;
7508c2ecf20Sopenharmony_ci		data->temp8[REMOTE2_CRIT] = val;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, MAX6659_REG_R_REMOTE_EMERG);
7538c2ecf20Sopenharmony_ci		if (val < 0)
7548c2ecf20Sopenharmony_ci			return val;
7558c2ecf20Sopenharmony_ci		data->temp8[REMOTE2_EMERG] = val;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_LOWH);
7588c2ecf20Sopenharmony_ci		if (val < 0)
7598c2ecf20Sopenharmony_ci			return val;
7608c2ecf20Sopenharmony_ci		data->temp11[REMOTE2_LOW] = val << 8;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_REMOTE_HIGHH);
7638c2ecf20Sopenharmony_ci		if (val < 0)
7648c2ecf20Sopenharmony_ci			return val;
7658c2ecf20Sopenharmony_ci		data->temp11[REMOTE2_HIGH] = val << 8;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci		lm90_select_remote_channel(data, 0);
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	return 0;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_cistatic int lm90_update_device(struct device *dev)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
7768c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
7778c2ecf20Sopenharmony_ci	unsigned long next_update;
7788c2ecf20Sopenharmony_ci	int val;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (!data->valid) {
7818c2ecf20Sopenharmony_ci		val = lm90_update_limits(dev);
7828c2ecf20Sopenharmony_ci		if (val < 0)
7838c2ecf20Sopenharmony_ci			return val;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	next_update = data->last_updated +
7878c2ecf20Sopenharmony_ci		      msecs_to_jiffies(data->update_interval);
7888c2ecf20Sopenharmony_ci	if (time_after(jiffies, next_update) || !data->valid) {
7898c2ecf20Sopenharmony_ci		dev_dbg(&client->dev, "Updating lm90 data.\n");
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci		data->valid = false;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_LOCAL_LOW);
7948c2ecf20Sopenharmony_ci		if (val < 0)
7958c2ecf20Sopenharmony_ci			return val;
7968c2ecf20Sopenharmony_ci		data->temp8[LOCAL_LOW] = val;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_LOCAL_HIGH);
7998c2ecf20Sopenharmony_ci		if (val < 0)
8008c2ecf20Sopenharmony_ci			return val;
8018c2ecf20Sopenharmony_ci		data->temp8[LOCAL_HIGH] = val;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci		if (data->reg_local_ext) {
8048c2ecf20Sopenharmony_ci			val = lm90_read16(client, LM90_REG_R_LOCAL_TEMP,
8058c2ecf20Sopenharmony_ci					  data->reg_local_ext);
8068c2ecf20Sopenharmony_ci			if (val < 0)
8078c2ecf20Sopenharmony_ci				return val;
8088c2ecf20Sopenharmony_ci			data->temp11[LOCAL_TEMP] = val;
8098c2ecf20Sopenharmony_ci		} else {
8108c2ecf20Sopenharmony_ci			val = lm90_read_reg(client, LM90_REG_R_LOCAL_TEMP);
8118c2ecf20Sopenharmony_ci			if (val < 0)
8128c2ecf20Sopenharmony_ci				return val;
8138c2ecf20Sopenharmony_ci			data->temp11[LOCAL_TEMP] = val << 8;
8148c2ecf20Sopenharmony_ci		}
8158c2ecf20Sopenharmony_ci		val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
8168c2ecf20Sopenharmony_ci				  LM90_REG_R_REMOTE_TEMPL);
8178c2ecf20Sopenharmony_ci		if (val < 0)
8188c2ecf20Sopenharmony_ci			return val;
8198c2ecf20Sopenharmony_ci		data->temp11[REMOTE_TEMP] = val;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		val = lm90_read_reg(client, LM90_REG_R_STATUS);
8228c2ecf20Sopenharmony_ci		if (val < 0)
8238c2ecf20Sopenharmony_ci			return val;
8248c2ecf20Sopenharmony_ci		data->alarms = val & ~LM90_STATUS_BUSY;
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		if (data->kind == max6696) {
8278c2ecf20Sopenharmony_ci			val = lm90_select_remote_channel(data, 1);
8288c2ecf20Sopenharmony_ci			if (val < 0)
8298c2ecf20Sopenharmony_ci				return val;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci			val = lm90_read16(client, LM90_REG_R_REMOTE_TEMPH,
8328c2ecf20Sopenharmony_ci					  LM90_REG_R_REMOTE_TEMPL);
8338c2ecf20Sopenharmony_ci			if (val < 0) {
8348c2ecf20Sopenharmony_ci				lm90_select_remote_channel(data, 0);
8358c2ecf20Sopenharmony_ci				return val;
8368c2ecf20Sopenharmony_ci			}
8378c2ecf20Sopenharmony_ci			data->temp11[REMOTE2_TEMP] = val;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci			lm90_select_remote_channel(data, 0);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci			val = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
8428c2ecf20Sopenharmony_ci			if (val < 0)
8438c2ecf20Sopenharmony_ci				return val;
8448c2ecf20Sopenharmony_ci			data->alarms |= val << 8;
8458c2ecf20Sopenharmony_ci		}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		/*
8488c2ecf20Sopenharmony_ci		 * Re-enable ALERT# output if it was originally enabled and
8498c2ecf20Sopenharmony_ci		 * relevant alarms are all clear
8508c2ecf20Sopenharmony_ci		 */
8518c2ecf20Sopenharmony_ci		if (!(data->config_orig & 0x80) &&
8528c2ecf20Sopenharmony_ci		    !(data->alarms & data->alert_alarms)) {
8538c2ecf20Sopenharmony_ci			if (data->config & 0x80) {
8548c2ecf20Sopenharmony_ci				dev_dbg(&client->dev, "Re-enabling ALERT#\n");
8558c2ecf20Sopenharmony_ci				lm90_update_confreg(data, data->config & ~0x80);
8568c2ecf20Sopenharmony_ci			}
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci		data->last_updated = jiffies;
8608c2ecf20Sopenharmony_ci		data->valid = true;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return 0;
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci/*
8678c2ecf20Sopenharmony_ci * Conversions
8688c2ecf20Sopenharmony_ci * For local temperatures and limits, critical limits and the hysteresis
8698c2ecf20Sopenharmony_ci * value, the LM90 uses signed 8-bit values with LSB = 1 degree Celsius.
8708c2ecf20Sopenharmony_ci * For remote temperatures and limits, it uses signed 11-bit values with
8718c2ecf20Sopenharmony_ci * LSB = 0.125 degree Celsius, left-justified in 16-bit registers.  Some
8728c2ecf20Sopenharmony_ci * Maxim chips use unsigned values.
8738c2ecf20Sopenharmony_ci */
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic inline int temp_from_s8(s8 val)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	return val * 1000;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_cistatic inline int temp_from_u8(u8 val)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	return val * 1000;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic inline int temp_from_s16(s16 val)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	return val / 32 * 125;
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic inline int temp_from_u16(u16 val)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	return val / 32 * 125;
8938c2ecf20Sopenharmony_ci}
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_cistatic s8 temp_to_s8(long val)
8968c2ecf20Sopenharmony_ci{
8978c2ecf20Sopenharmony_ci	if (val <= -128000)
8988c2ecf20Sopenharmony_ci		return -128;
8998c2ecf20Sopenharmony_ci	if (val >= 127000)
9008c2ecf20Sopenharmony_ci		return 127;
9018c2ecf20Sopenharmony_ci	if (val < 0)
9028c2ecf20Sopenharmony_ci		return (val - 500) / 1000;
9038c2ecf20Sopenharmony_ci	return (val + 500) / 1000;
9048c2ecf20Sopenharmony_ci}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_cistatic u8 temp_to_u8(long val)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	if (val <= 0)
9098c2ecf20Sopenharmony_ci		return 0;
9108c2ecf20Sopenharmony_ci	if (val >= 255000)
9118c2ecf20Sopenharmony_ci		return 255;
9128c2ecf20Sopenharmony_ci	return (val + 500) / 1000;
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic s16 temp_to_s16(long val)
9168c2ecf20Sopenharmony_ci{
9178c2ecf20Sopenharmony_ci	if (val <= -128000)
9188c2ecf20Sopenharmony_ci		return 0x8000;
9198c2ecf20Sopenharmony_ci	if (val >= 127875)
9208c2ecf20Sopenharmony_ci		return 0x7FE0;
9218c2ecf20Sopenharmony_ci	if (val < 0)
9228c2ecf20Sopenharmony_ci		return (val - 62) / 125 * 32;
9238c2ecf20Sopenharmony_ci	return (val + 62) / 125 * 32;
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_cistatic u8 hyst_to_reg(long val)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	if (val <= 0)
9298c2ecf20Sopenharmony_ci		return 0;
9308c2ecf20Sopenharmony_ci	if (val >= 30500)
9318c2ecf20Sopenharmony_ci		return 31;
9328c2ecf20Sopenharmony_ci	return (val + 500) / 1000;
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci/*
9368c2ecf20Sopenharmony_ci * ADT7461 in compatibility mode is almost identical to LM90 except that
9378c2ecf20Sopenharmony_ci * attempts to write values that are outside the range 0 < temp < 127 are
9388c2ecf20Sopenharmony_ci * treated as the boundary value.
9398c2ecf20Sopenharmony_ci *
9408c2ecf20Sopenharmony_ci * ADT7461 in "extended mode" operation uses unsigned integers offset by
9418c2ecf20Sopenharmony_ci * 64 (e.g., 0 -> -64 degC).  The range is restricted to -64..191 degC.
9428c2ecf20Sopenharmony_ci */
9438c2ecf20Sopenharmony_cistatic inline int temp_from_u8_adt7461(struct lm90_data *data, u8 val)
9448c2ecf20Sopenharmony_ci{
9458c2ecf20Sopenharmony_ci	if (data->flags & LM90_FLAG_ADT7461_EXT)
9468c2ecf20Sopenharmony_ci		return (val - 64) * 1000;
9478c2ecf20Sopenharmony_ci	return temp_from_s8(val);
9488c2ecf20Sopenharmony_ci}
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_cistatic inline int temp_from_u16_adt7461(struct lm90_data *data, u16 val)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	if (data->flags & LM90_FLAG_ADT7461_EXT)
9538c2ecf20Sopenharmony_ci		return (val - 0x4000) / 64 * 250;
9548c2ecf20Sopenharmony_ci	return temp_from_s16(val);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic u8 temp_to_u8_adt7461(struct lm90_data *data, long val)
9588c2ecf20Sopenharmony_ci{
9598c2ecf20Sopenharmony_ci	if (data->flags & LM90_FLAG_ADT7461_EXT) {
9608c2ecf20Sopenharmony_ci		if (val <= -64000)
9618c2ecf20Sopenharmony_ci			return 0;
9628c2ecf20Sopenharmony_ci		if (val >= 191000)
9638c2ecf20Sopenharmony_ci			return 0xFF;
9648c2ecf20Sopenharmony_ci		return (val + 500 + 64000) / 1000;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci	if (val <= 0)
9678c2ecf20Sopenharmony_ci		return 0;
9688c2ecf20Sopenharmony_ci	if (val >= 127000)
9698c2ecf20Sopenharmony_ci		return 127;
9708c2ecf20Sopenharmony_ci	return (val + 500) / 1000;
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_cistatic u16 temp_to_u16_adt7461(struct lm90_data *data, long val)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	if (data->flags & LM90_FLAG_ADT7461_EXT) {
9768c2ecf20Sopenharmony_ci		if (val <= -64000)
9778c2ecf20Sopenharmony_ci			return 0;
9788c2ecf20Sopenharmony_ci		if (val >= 191750)
9798c2ecf20Sopenharmony_ci			return 0xFFC0;
9808c2ecf20Sopenharmony_ci		return (val + 64000 + 125) / 250 * 64;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci	if (val <= 0)
9838c2ecf20Sopenharmony_ci		return 0;
9848c2ecf20Sopenharmony_ci	if (val >= 127750)
9858c2ecf20Sopenharmony_ci		return 0x7FC0;
9868c2ecf20Sopenharmony_ci	return (val + 125) / 250 * 64;
9878c2ecf20Sopenharmony_ci}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci/* pec used for ADM1032 only */
9908c2ecf20Sopenharmony_cistatic ssize_t pec_show(struct device *dev, struct device_attribute *dummy,
9918c2ecf20Sopenharmony_ci			char *buf)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC));
9968c2ecf20Sopenharmony_ci}
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic ssize_t pec_store(struct device *dev, struct device_attribute *dummy,
9998c2ecf20Sopenharmony_ci			 const char *buf, size_t count)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
10028c2ecf20Sopenharmony_ci	long val;
10038c2ecf20Sopenharmony_ci	int err;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	err = kstrtol(buf, 10, &val);
10068c2ecf20Sopenharmony_ci	if (err < 0)
10078c2ecf20Sopenharmony_ci		return err;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	switch (val) {
10108c2ecf20Sopenharmony_ci	case 0:
10118c2ecf20Sopenharmony_ci		client->flags &= ~I2C_CLIENT_PEC;
10128c2ecf20Sopenharmony_ci		break;
10138c2ecf20Sopenharmony_ci	case 1:
10148c2ecf20Sopenharmony_ci		client->flags |= I2C_CLIENT_PEC;
10158c2ecf20Sopenharmony_ci		break;
10168c2ecf20Sopenharmony_ci	default:
10178c2ecf20Sopenharmony_ci		return -EINVAL;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	return count;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(pec);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_cistatic int lm90_get_temp11(struct lm90_data *data, int index)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	s16 temp11 = data->temp11[index];
10288c2ecf20Sopenharmony_ci	int temp;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
10318c2ecf20Sopenharmony_ci		temp = temp_from_u16_adt7461(data, temp11);
10328c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
10338c2ecf20Sopenharmony_ci		temp = temp_from_u16(temp11);
10348c2ecf20Sopenharmony_ci	else
10358c2ecf20Sopenharmony_ci		temp = temp_from_s16(temp11);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	/* +16 degrees offset for temp2 for the LM99 */
10388c2ecf20Sopenharmony_ci	if (data->kind == lm99 && index <= 2)
10398c2ecf20Sopenharmony_ci		temp += 16000;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	return temp;
10428c2ecf20Sopenharmony_ci}
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_cistatic int lm90_set_temp11(struct lm90_data *data, int index, long val)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	static struct reg {
10478c2ecf20Sopenharmony_ci		u8 high;
10488c2ecf20Sopenharmony_ci		u8 low;
10498c2ecf20Sopenharmony_ci	} reg[] = {
10508c2ecf20Sopenharmony_ci	[REMOTE_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL },
10518c2ecf20Sopenharmony_ci	[REMOTE_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL },
10528c2ecf20Sopenharmony_ci	[REMOTE_OFFSET] = { LM90_REG_W_REMOTE_OFFSH, LM90_REG_W_REMOTE_OFFSL },
10538c2ecf20Sopenharmony_ci	[REMOTE2_LOW] = { LM90_REG_W_REMOTE_LOWH, LM90_REG_W_REMOTE_LOWL },
10548c2ecf20Sopenharmony_ci	[REMOTE2_HIGH] = { LM90_REG_W_REMOTE_HIGHH, LM90_REG_W_REMOTE_HIGHL }
10558c2ecf20Sopenharmony_ci	};
10568c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
10578c2ecf20Sopenharmony_ci	struct reg *regp = &reg[index];
10588c2ecf20Sopenharmony_ci	int err;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	/* +16 degrees offset for temp2 for the LM99 */
10618c2ecf20Sopenharmony_ci	if (data->kind == lm99 && index <= 2)
10628c2ecf20Sopenharmony_ci		val -= 16000;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
10658c2ecf20Sopenharmony_ci		data->temp11[index] = temp_to_u16_adt7461(data, val);
10668c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
10678c2ecf20Sopenharmony_ci		data->temp11[index] = temp_to_u8(val) << 8;
10688c2ecf20Sopenharmony_ci	else if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
10698c2ecf20Sopenharmony_ci		data->temp11[index] = temp_to_s16(val);
10708c2ecf20Sopenharmony_ci	else
10718c2ecf20Sopenharmony_ci		data->temp11[index] = temp_to_s8(val) << 8;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	lm90_select_remote_channel(data, index >= 3);
10748c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, regp->high,
10758c2ecf20Sopenharmony_ci				  data->temp11[index] >> 8);
10768c2ecf20Sopenharmony_ci	if (err < 0)
10778c2ecf20Sopenharmony_ci		return err;
10788c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_REM_LIMIT_EXT)
10798c2ecf20Sopenharmony_ci		err = i2c_smbus_write_byte_data(client, regp->low,
10808c2ecf20Sopenharmony_ci						data->temp11[index] & 0xff);
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	lm90_select_remote_channel(data, 0);
10838c2ecf20Sopenharmony_ci	return err;
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cistatic int lm90_get_temp8(struct lm90_data *data, int index)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	s8 temp8 = data->temp8[index];
10898c2ecf20Sopenharmony_ci	int temp;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
10928c2ecf20Sopenharmony_ci		temp = temp_from_u8_adt7461(data, temp8);
10938c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
10948c2ecf20Sopenharmony_ci		temp = temp_from_u8(temp8);
10958c2ecf20Sopenharmony_ci	else
10968c2ecf20Sopenharmony_ci		temp = temp_from_s8(temp8);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	/* +16 degrees offset for temp2 for the LM99 */
10998c2ecf20Sopenharmony_ci	if (data->kind == lm99 && index == 3)
11008c2ecf20Sopenharmony_ci		temp += 16000;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	return temp;
11038c2ecf20Sopenharmony_ci}
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_cistatic int lm90_set_temp8(struct lm90_data *data, int index, long val)
11068c2ecf20Sopenharmony_ci{
11078c2ecf20Sopenharmony_ci	static const u8 reg[TEMP8_REG_NUM] = {
11088c2ecf20Sopenharmony_ci		LM90_REG_W_LOCAL_LOW,
11098c2ecf20Sopenharmony_ci		LM90_REG_W_LOCAL_HIGH,
11108c2ecf20Sopenharmony_ci		LM90_REG_W_LOCAL_CRIT,
11118c2ecf20Sopenharmony_ci		LM90_REG_W_REMOTE_CRIT,
11128c2ecf20Sopenharmony_ci		MAX6659_REG_W_LOCAL_EMERG,
11138c2ecf20Sopenharmony_ci		MAX6659_REG_W_REMOTE_EMERG,
11148c2ecf20Sopenharmony_ci		LM90_REG_W_REMOTE_CRIT,
11158c2ecf20Sopenharmony_ci		MAX6659_REG_W_REMOTE_EMERG,
11168c2ecf20Sopenharmony_ci	};
11178c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
11188c2ecf20Sopenharmony_ci	int err;
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci	/* +16 degrees offset for temp2 for the LM99 */
11218c2ecf20Sopenharmony_ci	if (data->kind == lm99 && index == 3)
11228c2ecf20Sopenharmony_ci		val -= 16000;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
11258c2ecf20Sopenharmony_ci		data->temp8[index] = temp_to_u8_adt7461(data, val);
11268c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
11278c2ecf20Sopenharmony_ci		data->temp8[index] = temp_to_u8(val);
11288c2ecf20Sopenharmony_ci	else
11298c2ecf20Sopenharmony_ci		data->temp8[index] = temp_to_s8(val);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	lm90_select_remote_channel(data, index >= 6);
11328c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, reg[index], data->temp8[index]);
11338c2ecf20Sopenharmony_ci	lm90_select_remote_channel(data, 0);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	return err;
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic int lm90_get_temphyst(struct lm90_data *data, int index)
11398c2ecf20Sopenharmony_ci{
11408c2ecf20Sopenharmony_ci	int temp;
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
11438c2ecf20Sopenharmony_ci		temp = temp_from_u8_adt7461(data, data->temp8[index]);
11448c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
11458c2ecf20Sopenharmony_ci		temp = temp_from_u8(data->temp8[index]);
11468c2ecf20Sopenharmony_ci	else
11478c2ecf20Sopenharmony_ci		temp = temp_from_s8(data->temp8[index]);
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	/* +16 degrees offset for temp2 for the LM99 */
11508c2ecf20Sopenharmony_ci	if (data->kind == lm99 && index == 3)
11518c2ecf20Sopenharmony_ci		temp += 16000;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	return temp - temp_from_s8(data->temp_hyst);
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_cistatic int lm90_set_temphyst(struct lm90_data *data, long val)
11578c2ecf20Sopenharmony_ci{
11588c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
11598c2ecf20Sopenharmony_ci	int temp;
11608c2ecf20Sopenharmony_ci	int err;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP)
11638c2ecf20Sopenharmony_ci		temp = temp_from_u8_adt7461(data, data->temp8[LOCAL_CRIT]);
11648c2ecf20Sopenharmony_ci	else if (data->kind == max6646)
11658c2ecf20Sopenharmony_ci		temp = temp_from_u8(data->temp8[LOCAL_CRIT]);
11668c2ecf20Sopenharmony_ci	else
11678c2ecf20Sopenharmony_ci		temp = temp_from_s8(data->temp8[LOCAL_CRIT]);
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	data->temp_hyst = hyst_to_reg(temp - val);
11708c2ecf20Sopenharmony_ci	err = i2c_smbus_write_byte_data(client, LM90_REG_W_TCRIT_HYST,
11718c2ecf20Sopenharmony_ci					data->temp_hyst);
11728c2ecf20Sopenharmony_ci	return err;
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_cistatic const u8 lm90_temp_index[3] = {
11768c2ecf20Sopenharmony_ci	LOCAL_TEMP, REMOTE_TEMP, REMOTE2_TEMP
11778c2ecf20Sopenharmony_ci};
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic const u8 lm90_temp_min_index[3] = {
11808c2ecf20Sopenharmony_ci	LOCAL_LOW, REMOTE_LOW, REMOTE2_LOW
11818c2ecf20Sopenharmony_ci};
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic const u8 lm90_temp_max_index[3] = {
11848c2ecf20Sopenharmony_ci	LOCAL_HIGH, REMOTE_HIGH, REMOTE2_HIGH
11858c2ecf20Sopenharmony_ci};
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cistatic const u8 lm90_temp_crit_index[3] = {
11888c2ecf20Sopenharmony_ci	LOCAL_CRIT, REMOTE_CRIT, REMOTE2_CRIT
11898c2ecf20Sopenharmony_ci};
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic const u8 lm90_temp_emerg_index[3] = {
11928c2ecf20Sopenharmony_ci	LOCAL_EMERG, REMOTE_EMERG, REMOTE2_EMERG
11938c2ecf20Sopenharmony_ci};
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_cistatic const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 };
11968c2ecf20Sopenharmony_cistatic const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 };
11978c2ecf20Sopenharmony_cistatic const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 };
11988c2ecf20Sopenharmony_cistatic const u8 lm90_crit_alarm_bits_swapped[3] = { 1, 0, 9 };
11998c2ecf20Sopenharmony_cistatic const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 };
12008c2ecf20Sopenharmony_cistatic const u8 lm90_fault_bits[3] = { 0, 2, 10 };
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_cistatic int lm90_temp_read(struct device *dev, u32 attr, int channel, long *val)
12038c2ecf20Sopenharmony_ci{
12048c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
12058c2ecf20Sopenharmony_ci	int err;
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
12088c2ecf20Sopenharmony_ci	err = lm90_update_device(dev);
12098c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
12108c2ecf20Sopenharmony_ci	if (err)
12118c2ecf20Sopenharmony_ci		return err;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	switch (attr) {
12148c2ecf20Sopenharmony_ci	case hwmon_temp_input:
12158c2ecf20Sopenharmony_ci		*val = lm90_get_temp11(data, lm90_temp_index[channel]);
12168c2ecf20Sopenharmony_ci		break;
12178c2ecf20Sopenharmony_ci	case hwmon_temp_min_alarm:
12188c2ecf20Sopenharmony_ci		*val = (data->alarms >> lm90_min_alarm_bits[channel]) & 1;
12198c2ecf20Sopenharmony_ci		break;
12208c2ecf20Sopenharmony_ci	case hwmon_temp_max_alarm:
12218c2ecf20Sopenharmony_ci		*val = (data->alarms >> lm90_max_alarm_bits[channel]) & 1;
12228c2ecf20Sopenharmony_ci		break;
12238c2ecf20Sopenharmony_ci	case hwmon_temp_crit_alarm:
12248c2ecf20Sopenharmony_ci		if (data->flags & LM90_HAVE_CRIT_ALRM_SWP)
12258c2ecf20Sopenharmony_ci			*val = (data->alarms >> lm90_crit_alarm_bits_swapped[channel]) & 1;
12268c2ecf20Sopenharmony_ci		else
12278c2ecf20Sopenharmony_ci			*val = (data->alarms >> lm90_crit_alarm_bits[channel]) & 1;
12288c2ecf20Sopenharmony_ci		break;
12298c2ecf20Sopenharmony_ci	case hwmon_temp_emergency_alarm:
12308c2ecf20Sopenharmony_ci		*val = (data->alarms >> lm90_emergency_alarm_bits[channel]) & 1;
12318c2ecf20Sopenharmony_ci		break;
12328c2ecf20Sopenharmony_ci	case hwmon_temp_fault:
12338c2ecf20Sopenharmony_ci		*val = (data->alarms >> lm90_fault_bits[channel]) & 1;
12348c2ecf20Sopenharmony_ci		break;
12358c2ecf20Sopenharmony_ci	case hwmon_temp_min:
12368c2ecf20Sopenharmony_ci		if (channel == 0)
12378c2ecf20Sopenharmony_ci			*val = lm90_get_temp8(data,
12388c2ecf20Sopenharmony_ci					      lm90_temp_min_index[channel]);
12398c2ecf20Sopenharmony_ci		else
12408c2ecf20Sopenharmony_ci			*val = lm90_get_temp11(data,
12418c2ecf20Sopenharmony_ci					       lm90_temp_min_index[channel]);
12428c2ecf20Sopenharmony_ci		break;
12438c2ecf20Sopenharmony_ci	case hwmon_temp_max:
12448c2ecf20Sopenharmony_ci		if (channel == 0)
12458c2ecf20Sopenharmony_ci			*val = lm90_get_temp8(data,
12468c2ecf20Sopenharmony_ci					      lm90_temp_max_index[channel]);
12478c2ecf20Sopenharmony_ci		else
12488c2ecf20Sopenharmony_ci			*val = lm90_get_temp11(data,
12498c2ecf20Sopenharmony_ci					       lm90_temp_max_index[channel]);
12508c2ecf20Sopenharmony_ci		break;
12518c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
12528c2ecf20Sopenharmony_ci		*val = lm90_get_temp8(data, lm90_temp_crit_index[channel]);
12538c2ecf20Sopenharmony_ci		break;
12548c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
12558c2ecf20Sopenharmony_ci		*val = lm90_get_temphyst(data, lm90_temp_crit_index[channel]);
12568c2ecf20Sopenharmony_ci		break;
12578c2ecf20Sopenharmony_ci	case hwmon_temp_emergency:
12588c2ecf20Sopenharmony_ci		*val = lm90_get_temp8(data, lm90_temp_emerg_index[channel]);
12598c2ecf20Sopenharmony_ci		break;
12608c2ecf20Sopenharmony_ci	case hwmon_temp_emergency_hyst:
12618c2ecf20Sopenharmony_ci		*val = lm90_get_temphyst(data, lm90_temp_emerg_index[channel]);
12628c2ecf20Sopenharmony_ci		break;
12638c2ecf20Sopenharmony_ci	case hwmon_temp_offset:
12648c2ecf20Sopenharmony_ci		*val = lm90_get_temp11(data, REMOTE_OFFSET);
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci	default:
12678c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
12688c2ecf20Sopenharmony_ci	}
12698c2ecf20Sopenharmony_ci	return 0;
12708c2ecf20Sopenharmony_ci}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_cistatic int lm90_temp_write(struct device *dev, u32 attr, int channel, long val)
12738c2ecf20Sopenharmony_ci{
12748c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
12758c2ecf20Sopenharmony_ci	int err;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	err = lm90_update_device(dev);
12808c2ecf20Sopenharmony_ci	if (err)
12818c2ecf20Sopenharmony_ci		goto error;
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	switch (attr) {
12848c2ecf20Sopenharmony_ci	case hwmon_temp_min:
12858c2ecf20Sopenharmony_ci		if (channel == 0)
12868c2ecf20Sopenharmony_ci			err = lm90_set_temp8(data,
12878c2ecf20Sopenharmony_ci					      lm90_temp_min_index[channel],
12888c2ecf20Sopenharmony_ci					      val);
12898c2ecf20Sopenharmony_ci		else
12908c2ecf20Sopenharmony_ci			err = lm90_set_temp11(data,
12918c2ecf20Sopenharmony_ci					      lm90_temp_min_index[channel],
12928c2ecf20Sopenharmony_ci					      val);
12938c2ecf20Sopenharmony_ci		break;
12948c2ecf20Sopenharmony_ci	case hwmon_temp_max:
12958c2ecf20Sopenharmony_ci		if (channel == 0)
12968c2ecf20Sopenharmony_ci			err = lm90_set_temp8(data,
12978c2ecf20Sopenharmony_ci					     lm90_temp_max_index[channel],
12988c2ecf20Sopenharmony_ci					     val);
12998c2ecf20Sopenharmony_ci		else
13008c2ecf20Sopenharmony_ci			err = lm90_set_temp11(data,
13018c2ecf20Sopenharmony_ci					      lm90_temp_max_index[channel],
13028c2ecf20Sopenharmony_ci					      val);
13038c2ecf20Sopenharmony_ci		break;
13048c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
13058c2ecf20Sopenharmony_ci		err = lm90_set_temp8(data, lm90_temp_crit_index[channel], val);
13068c2ecf20Sopenharmony_ci		break;
13078c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
13088c2ecf20Sopenharmony_ci		err = lm90_set_temphyst(data, val);
13098c2ecf20Sopenharmony_ci		break;
13108c2ecf20Sopenharmony_ci	case hwmon_temp_emergency:
13118c2ecf20Sopenharmony_ci		err = lm90_set_temp8(data, lm90_temp_emerg_index[channel], val);
13128c2ecf20Sopenharmony_ci		break;
13138c2ecf20Sopenharmony_ci	case hwmon_temp_offset:
13148c2ecf20Sopenharmony_ci		err = lm90_set_temp11(data, REMOTE_OFFSET, val);
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci	default:
13178c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
13188c2ecf20Sopenharmony_ci		break;
13198c2ecf20Sopenharmony_ci	}
13208c2ecf20Sopenharmony_cierror:
13218c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	return err;
13248c2ecf20Sopenharmony_ci}
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_cistatic umode_t lm90_temp_is_visible(const void *data, u32 attr, int channel)
13278c2ecf20Sopenharmony_ci{
13288c2ecf20Sopenharmony_ci	switch (attr) {
13298c2ecf20Sopenharmony_ci	case hwmon_temp_input:
13308c2ecf20Sopenharmony_ci	case hwmon_temp_min_alarm:
13318c2ecf20Sopenharmony_ci	case hwmon_temp_max_alarm:
13328c2ecf20Sopenharmony_ci	case hwmon_temp_crit_alarm:
13338c2ecf20Sopenharmony_ci	case hwmon_temp_emergency_alarm:
13348c2ecf20Sopenharmony_ci	case hwmon_temp_emergency_hyst:
13358c2ecf20Sopenharmony_ci	case hwmon_temp_fault:
13368c2ecf20Sopenharmony_ci		return 0444;
13378c2ecf20Sopenharmony_ci	case hwmon_temp_min:
13388c2ecf20Sopenharmony_ci	case hwmon_temp_max:
13398c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
13408c2ecf20Sopenharmony_ci	case hwmon_temp_emergency:
13418c2ecf20Sopenharmony_ci	case hwmon_temp_offset:
13428c2ecf20Sopenharmony_ci		return 0644;
13438c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
13448c2ecf20Sopenharmony_ci		if (channel == 0)
13458c2ecf20Sopenharmony_ci			return 0644;
13468c2ecf20Sopenharmony_ci		return 0444;
13478c2ecf20Sopenharmony_ci	default:
13488c2ecf20Sopenharmony_ci		return 0;
13498c2ecf20Sopenharmony_ci	}
13508c2ecf20Sopenharmony_ci}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic int lm90_chip_read(struct device *dev, u32 attr, int channel, long *val)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
13558c2ecf20Sopenharmony_ci	int err;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
13588c2ecf20Sopenharmony_ci	err = lm90_update_device(dev);
13598c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
13608c2ecf20Sopenharmony_ci	if (err)
13618c2ecf20Sopenharmony_ci		return err;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	switch (attr) {
13648c2ecf20Sopenharmony_ci	case hwmon_chip_update_interval:
13658c2ecf20Sopenharmony_ci		*val = data->update_interval;
13668c2ecf20Sopenharmony_ci		break;
13678c2ecf20Sopenharmony_ci	case hwmon_chip_alarms:
13688c2ecf20Sopenharmony_ci		*val = data->alarms;
13698c2ecf20Sopenharmony_ci		break;
13708c2ecf20Sopenharmony_ci	default:
13718c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	return 0;
13758c2ecf20Sopenharmony_ci}
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_cistatic int lm90_chip_write(struct device *dev, u32 attr, int channel, long val)
13788c2ecf20Sopenharmony_ci{
13798c2ecf20Sopenharmony_ci	struct lm90_data *data = dev_get_drvdata(dev);
13808c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
13818c2ecf20Sopenharmony_ci	int err;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	err = lm90_update_device(dev);
13868c2ecf20Sopenharmony_ci	if (err)
13878c2ecf20Sopenharmony_ci		goto error;
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	switch (attr) {
13908c2ecf20Sopenharmony_ci	case hwmon_chip_update_interval:
13918c2ecf20Sopenharmony_ci		err = lm90_set_convrate(client, data,
13928c2ecf20Sopenharmony_ci					clamp_val(val, 0, 100000));
13938c2ecf20Sopenharmony_ci		break;
13948c2ecf20Sopenharmony_ci	default:
13958c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
13968c2ecf20Sopenharmony_ci		break;
13978c2ecf20Sopenharmony_ci	}
13988c2ecf20Sopenharmony_cierror:
13998c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci	return err;
14028c2ecf20Sopenharmony_ci}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_cistatic umode_t lm90_chip_is_visible(const void *data, u32 attr, int channel)
14058c2ecf20Sopenharmony_ci{
14068c2ecf20Sopenharmony_ci	switch (attr) {
14078c2ecf20Sopenharmony_ci	case hwmon_chip_update_interval:
14088c2ecf20Sopenharmony_ci		return 0644;
14098c2ecf20Sopenharmony_ci	case hwmon_chip_alarms:
14108c2ecf20Sopenharmony_ci		return 0444;
14118c2ecf20Sopenharmony_ci	default:
14128c2ecf20Sopenharmony_ci		return 0;
14138c2ecf20Sopenharmony_ci	}
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int lm90_read(struct device *dev, enum hwmon_sensor_types type,
14178c2ecf20Sopenharmony_ci		     u32 attr, int channel, long *val)
14188c2ecf20Sopenharmony_ci{
14198c2ecf20Sopenharmony_ci	switch (type) {
14208c2ecf20Sopenharmony_ci	case hwmon_chip:
14218c2ecf20Sopenharmony_ci		return lm90_chip_read(dev, attr, channel, val);
14228c2ecf20Sopenharmony_ci	case hwmon_temp:
14238c2ecf20Sopenharmony_ci		return lm90_temp_read(dev, attr, channel, val);
14248c2ecf20Sopenharmony_ci	default:
14258c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14268c2ecf20Sopenharmony_ci	}
14278c2ecf20Sopenharmony_ci}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_cistatic int lm90_write(struct device *dev, enum hwmon_sensor_types type,
14308c2ecf20Sopenharmony_ci		      u32 attr, int channel, long val)
14318c2ecf20Sopenharmony_ci{
14328c2ecf20Sopenharmony_ci	switch (type) {
14338c2ecf20Sopenharmony_ci	case hwmon_chip:
14348c2ecf20Sopenharmony_ci		return lm90_chip_write(dev, attr, channel, val);
14358c2ecf20Sopenharmony_ci	case hwmon_temp:
14368c2ecf20Sopenharmony_ci		return lm90_temp_write(dev, attr, channel, val);
14378c2ecf20Sopenharmony_ci	default:
14388c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
14398c2ecf20Sopenharmony_ci	}
14408c2ecf20Sopenharmony_ci}
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_cistatic umode_t lm90_is_visible(const void *data, enum hwmon_sensor_types type,
14438c2ecf20Sopenharmony_ci			       u32 attr, int channel)
14448c2ecf20Sopenharmony_ci{
14458c2ecf20Sopenharmony_ci	switch (type) {
14468c2ecf20Sopenharmony_ci	case hwmon_chip:
14478c2ecf20Sopenharmony_ci		return lm90_chip_is_visible(data, attr, channel);
14488c2ecf20Sopenharmony_ci	case hwmon_temp:
14498c2ecf20Sopenharmony_ci		return lm90_temp_is_visible(data, attr, channel);
14508c2ecf20Sopenharmony_ci	default:
14518c2ecf20Sopenharmony_ci		return 0;
14528c2ecf20Sopenharmony_ci	}
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
14568c2ecf20Sopenharmony_cistatic int lm90_detect(struct i2c_client *client,
14578c2ecf20Sopenharmony_ci		       struct i2c_board_info *info)
14588c2ecf20Sopenharmony_ci{
14598c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
14608c2ecf20Sopenharmony_ci	int address = client->addr;
14618c2ecf20Sopenharmony_ci	const char *name = NULL;
14628c2ecf20Sopenharmony_ci	int man_id, chip_id, config1, config2, convrate;
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
14658c2ecf20Sopenharmony_ci		return -ENODEV;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	/* detection and identification */
14688c2ecf20Sopenharmony_ci	man_id = i2c_smbus_read_byte_data(client, LM90_REG_R_MAN_ID);
14698c2ecf20Sopenharmony_ci	chip_id = i2c_smbus_read_byte_data(client, LM90_REG_R_CHIP_ID);
14708c2ecf20Sopenharmony_ci	config1 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG1);
14718c2ecf20Sopenharmony_ci	convrate = i2c_smbus_read_byte_data(client, LM90_REG_R_CONVRATE);
14728c2ecf20Sopenharmony_ci	if (man_id < 0 || chip_id < 0 || config1 < 0 || convrate < 0)
14738c2ecf20Sopenharmony_ci		return -ENODEV;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	if (man_id == 0x01 || man_id == 0x5C || man_id == 0xA1) {
14768c2ecf20Sopenharmony_ci		config2 = i2c_smbus_read_byte_data(client, LM90_REG_R_CONFIG2);
14778c2ecf20Sopenharmony_ci		if (config2 < 0)
14788c2ecf20Sopenharmony_ci			return -ENODEV;
14798c2ecf20Sopenharmony_ci	}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	if ((address == 0x4C || address == 0x4D)
14828c2ecf20Sopenharmony_ci	 && man_id == 0x01) { /* National Semiconductor */
14838c2ecf20Sopenharmony_ci		if ((config1 & 0x2A) == 0x00
14848c2ecf20Sopenharmony_ci		 && (config2 & 0xF8) == 0x00
14858c2ecf20Sopenharmony_ci		 && convrate <= 0x09) {
14868c2ecf20Sopenharmony_ci			if (address == 0x4C
14878c2ecf20Sopenharmony_ci			 && (chip_id & 0xF0) == 0x20) { /* LM90 */
14888c2ecf20Sopenharmony_ci				name = "lm90";
14898c2ecf20Sopenharmony_ci			} else
14908c2ecf20Sopenharmony_ci			if ((chip_id & 0xF0) == 0x30) { /* LM89/LM99 */
14918c2ecf20Sopenharmony_ci				name = "lm99";
14928c2ecf20Sopenharmony_ci				dev_info(&adapter->dev,
14938c2ecf20Sopenharmony_ci					 "Assuming LM99 chip at 0x%02x\n",
14948c2ecf20Sopenharmony_ci					 address);
14958c2ecf20Sopenharmony_ci				dev_info(&adapter->dev,
14968c2ecf20Sopenharmony_ci					 "If it is an LM89, instantiate it "
14978c2ecf20Sopenharmony_ci					 "with the new_device sysfs "
14988c2ecf20Sopenharmony_ci					 "interface\n");
14998c2ecf20Sopenharmony_ci			} else
15008c2ecf20Sopenharmony_ci			if (address == 0x4C
15018c2ecf20Sopenharmony_ci			 && (chip_id & 0xF0) == 0x10) { /* LM86 */
15028c2ecf20Sopenharmony_ci				name = "lm86";
15038c2ecf20Sopenharmony_ci			}
15048c2ecf20Sopenharmony_ci		}
15058c2ecf20Sopenharmony_ci	} else
15068c2ecf20Sopenharmony_ci	if ((address == 0x4C || address == 0x4D)
15078c2ecf20Sopenharmony_ci	 && man_id == 0x41) { /* Analog Devices */
15088c2ecf20Sopenharmony_ci		if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
15098c2ecf20Sopenharmony_ci		 && (config1 & 0x3F) == 0x00
15108c2ecf20Sopenharmony_ci		 && convrate <= 0x0A) {
15118c2ecf20Sopenharmony_ci			name = "adm1032";
15128c2ecf20Sopenharmony_ci			/*
15138c2ecf20Sopenharmony_ci			 * The ADM1032 supports PEC, but only if combined
15148c2ecf20Sopenharmony_ci			 * transactions are not used.
15158c2ecf20Sopenharmony_ci			 */
15168c2ecf20Sopenharmony_ci			if (i2c_check_functionality(adapter,
15178c2ecf20Sopenharmony_ci						    I2C_FUNC_SMBUS_BYTE))
15188c2ecf20Sopenharmony_ci				info->flags |= I2C_CLIENT_PEC;
15198c2ecf20Sopenharmony_ci		} else
15208c2ecf20Sopenharmony_ci		if (chip_id == 0x51 /* ADT7461 */
15218c2ecf20Sopenharmony_ci		 && (config1 & 0x1B) == 0x00
15228c2ecf20Sopenharmony_ci		 && convrate <= 0x0A) {
15238c2ecf20Sopenharmony_ci			name = "adt7461";
15248c2ecf20Sopenharmony_ci		} else
15258c2ecf20Sopenharmony_ci		if (chip_id == 0x57 /* ADT7461A, NCT1008 */
15268c2ecf20Sopenharmony_ci		 && (config1 & 0x1B) == 0x00
15278c2ecf20Sopenharmony_ci		 && convrate <= 0x0A) {
15288c2ecf20Sopenharmony_ci			name = "adt7461a";
15298c2ecf20Sopenharmony_ci		}
15308c2ecf20Sopenharmony_ci	} else
15318c2ecf20Sopenharmony_ci	if (man_id == 0x4D) { /* Maxim */
15328c2ecf20Sopenharmony_ci		int emerg, emerg2, status2;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci		/*
15358c2ecf20Sopenharmony_ci		 * We read MAX6659_REG_R_REMOTE_EMERG twice, and re-read
15368c2ecf20Sopenharmony_ci		 * LM90_REG_R_MAN_ID in between. If MAX6659_REG_R_REMOTE_EMERG
15378c2ecf20Sopenharmony_ci		 * exists, both readings will reflect the same value. Otherwise,
15388c2ecf20Sopenharmony_ci		 * the readings will be different.
15398c2ecf20Sopenharmony_ci		 */
15408c2ecf20Sopenharmony_ci		emerg = i2c_smbus_read_byte_data(client,
15418c2ecf20Sopenharmony_ci						 MAX6659_REG_R_REMOTE_EMERG);
15428c2ecf20Sopenharmony_ci		man_id = i2c_smbus_read_byte_data(client,
15438c2ecf20Sopenharmony_ci						  LM90_REG_R_MAN_ID);
15448c2ecf20Sopenharmony_ci		emerg2 = i2c_smbus_read_byte_data(client,
15458c2ecf20Sopenharmony_ci						  MAX6659_REG_R_REMOTE_EMERG);
15468c2ecf20Sopenharmony_ci		status2 = i2c_smbus_read_byte_data(client,
15478c2ecf20Sopenharmony_ci						   MAX6696_REG_R_STATUS2);
15488c2ecf20Sopenharmony_ci		if (emerg < 0 || man_id < 0 || emerg2 < 0 || status2 < 0)
15498c2ecf20Sopenharmony_ci			return -ENODEV;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci		/*
15528c2ecf20Sopenharmony_ci		 * The MAX6657, MAX6658 and MAX6659 do NOT have a chip_id
15538c2ecf20Sopenharmony_ci		 * register. Reading from that address will return the last
15548c2ecf20Sopenharmony_ci		 * read value, which in our case is those of the man_id
15558c2ecf20Sopenharmony_ci		 * register. Likewise, the config1 register seems to lack a
15568c2ecf20Sopenharmony_ci		 * low nibble, so the value will be those of the previous
15578c2ecf20Sopenharmony_ci		 * read, so in our case those of the man_id register.
15588c2ecf20Sopenharmony_ci		 * MAX6659 has a third set of upper temperature limit registers.
15598c2ecf20Sopenharmony_ci		 * Those registers also return values on MAX6657 and MAX6658,
15608c2ecf20Sopenharmony_ci		 * thus the only way to detect MAX6659 is by its address.
15618c2ecf20Sopenharmony_ci		 * For this reason it will be mis-detected as MAX6657 if its
15628c2ecf20Sopenharmony_ci		 * address is 0x4C.
15638c2ecf20Sopenharmony_ci		 */
15648c2ecf20Sopenharmony_ci		if (chip_id == man_id
15658c2ecf20Sopenharmony_ci		 && (address == 0x4C || address == 0x4D || address == 0x4E)
15668c2ecf20Sopenharmony_ci		 && (config1 & 0x1F) == (man_id & 0x0F)
15678c2ecf20Sopenharmony_ci		 && convrate <= 0x09) {
15688c2ecf20Sopenharmony_ci			if (address == 0x4C)
15698c2ecf20Sopenharmony_ci				name = "max6657";
15708c2ecf20Sopenharmony_ci			else
15718c2ecf20Sopenharmony_ci				name = "max6659";
15728c2ecf20Sopenharmony_ci		} else
15738c2ecf20Sopenharmony_ci		/*
15748c2ecf20Sopenharmony_ci		 * Even though MAX6695 and MAX6696 do not have a chip ID
15758c2ecf20Sopenharmony_ci		 * register, reading it returns 0x01. Bit 4 of the config1
15768c2ecf20Sopenharmony_ci		 * register is unused and should return zero when read. Bit 0 of
15778c2ecf20Sopenharmony_ci		 * the status2 register is unused and should return zero when
15788c2ecf20Sopenharmony_ci		 * read.
15798c2ecf20Sopenharmony_ci		 *
15808c2ecf20Sopenharmony_ci		 * MAX6695 and MAX6696 have an additional set of temperature
15818c2ecf20Sopenharmony_ci		 * limit registers. We can detect those chips by checking if
15828c2ecf20Sopenharmony_ci		 * one of those registers exists.
15838c2ecf20Sopenharmony_ci		 */
15848c2ecf20Sopenharmony_ci		if (chip_id == 0x01
15858c2ecf20Sopenharmony_ci		 && (config1 & 0x10) == 0x00
15868c2ecf20Sopenharmony_ci		 && (status2 & 0x01) == 0x00
15878c2ecf20Sopenharmony_ci		 && emerg == emerg2
15888c2ecf20Sopenharmony_ci		 && convrate <= 0x07) {
15898c2ecf20Sopenharmony_ci			name = "max6696";
15908c2ecf20Sopenharmony_ci		} else
15918c2ecf20Sopenharmony_ci		/*
15928c2ecf20Sopenharmony_ci		 * The chip_id register of the MAX6680 and MAX6681 holds the
15938c2ecf20Sopenharmony_ci		 * revision of the chip. The lowest bit of the config1 register
15948c2ecf20Sopenharmony_ci		 * is unused and should return zero when read, so should the
15958c2ecf20Sopenharmony_ci		 * second to last bit of config1 (software reset).
15968c2ecf20Sopenharmony_ci		 */
15978c2ecf20Sopenharmony_ci		if (chip_id == 0x01
15988c2ecf20Sopenharmony_ci		 && (config1 & 0x03) == 0x00
15998c2ecf20Sopenharmony_ci		 && convrate <= 0x07) {
16008c2ecf20Sopenharmony_ci			name = "max6680";
16018c2ecf20Sopenharmony_ci		} else
16028c2ecf20Sopenharmony_ci		/*
16038c2ecf20Sopenharmony_ci		 * The chip_id register of the MAX6646/6647/6649 holds the
16048c2ecf20Sopenharmony_ci		 * revision of the chip. The lowest 6 bits of the config1
16058c2ecf20Sopenharmony_ci		 * register are unused and should return zero when read.
16068c2ecf20Sopenharmony_ci		 */
16078c2ecf20Sopenharmony_ci		if (chip_id == 0x59
16088c2ecf20Sopenharmony_ci		 && (config1 & 0x3f) == 0x00
16098c2ecf20Sopenharmony_ci		 && convrate <= 0x07) {
16108c2ecf20Sopenharmony_ci			name = "max6646";
16118c2ecf20Sopenharmony_ci		} else
16128c2ecf20Sopenharmony_ci		/*
16138c2ecf20Sopenharmony_ci		 * The chip_id of the MAX6654 holds the revision of the chip.
16148c2ecf20Sopenharmony_ci		 * The lowest 3 bits of the config1 register are unused and
16158c2ecf20Sopenharmony_ci		 * should return zero when read.
16168c2ecf20Sopenharmony_ci		 */
16178c2ecf20Sopenharmony_ci		if (chip_id == 0x08
16188c2ecf20Sopenharmony_ci		 && (config1 & 0x07) == 0x00
16198c2ecf20Sopenharmony_ci		 && convrate <= 0x07) {
16208c2ecf20Sopenharmony_ci			name = "max6654";
16218c2ecf20Sopenharmony_ci		}
16228c2ecf20Sopenharmony_ci	} else
16238c2ecf20Sopenharmony_ci	if (address == 0x4C
16248c2ecf20Sopenharmony_ci	 && man_id == 0x5C) { /* Winbond/Nuvoton */
16258c2ecf20Sopenharmony_ci		if ((config1 & 0x2A) == 0x00
16268c2ecf20Sopenharmony_ci		 && (config2 & 0xF8) == 0x00) {
16278c2ecf20Sopenharmony_ci			if (chip_id == 0x01 /* W83L771W/G */
16288c2ecf20Sopenharmony_ci			 && convrate <= 0x09) {
16298c2ecf20Sopenharmony_ci				name = "w83l771";
16308c2ecf20Sopenharmony_ci			} else
16318c2ecf20Sopenharmony_ci			if ((chip_id & 0xFE) == 0x10 /* W83L771AWG/ASG */
16328c2ecf20Sopenharmony_ci			 && convrate <= 0x08) {
16338c2ecf20Sopenharmony_ci				name = "w83l771";
16348c2ecf20Sopenharmony_ci			}
16358c2ecf20Sopenharmony_ci		}
16368c2ecf20Sopenharmony_ci	} else
16378c2ecf20Sopenharmony_ci	if (address >= 0x48 && address <= 0x4F
16388c2ecf20Sopenharmony_ci	 && man_id == 0xA1) { /*  NXP Semiconductor/Philips */
16398c2ecf20Sopenharmony_ci		if (chip_id == 0x00
16408c2ecf20Sopenharmony_ci		 && (config1 & 0x2A) == 0x00
16418c2ecf20Sopenharmony_ci		 && (config2 & 0xFE) == 0x00
16428c2ecf20Sopenharmony_ci		 && convrate <= 0x09) {
16438c2ecf20Sopenharmony_ci			name = "sa56004";
16448c2ecf20Sopenharmony_ci		}
16458c2ecf20Sopenharmony_ci	} else
16468c2ecf20Sopenharmony_ci	if ((address == 0x4C || address == 0x4D)
16478c2ecf20Sopenharmony_ci	 && man_id == 0x47) { /* GMT */
16488c2ecf20Sopenharmony_ci		if (chip_id == 0x01 /* G781 */
16498c2ecf20Sopenharmony_ci		 && (config1 & 0x3F) == 0x00
16508c2ecf20Sopenharmony_ci		 && convrate <= 0x08)
16518c2ecf20Sopenharmony_ci			name = "g781";
16528c2ecf20Sopenharmony_ci	} else
16538c2ecf20Sopenharmony_ci	if (man_id == 0x55 && chip_id == 0x00 &&
16548c2ecf20Sopenharmony_ci	    (config1 & 0x1B) == 0x00 && convrate <= 0x09) {
16558c2ecf20Sopenharmony_ci		int local_ext, conalert, chen, dfc;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci		local_ext = i2c_smbus_read_byte_data(client,
16588c2ecf20Sopenharmony_ci						     TMP451_REG_R_LOCAL_TEMPL);
16598c2ecf20Sopenharmony_ci		conalert = i2c_smbus_read_byte_data(client,
16608c2ecf20Sopenharmony_ci						    TMP451_REG_CONALERT);
16618c2ecf20Sopenharmony_ci		chen = i2c_smbus_read_byte_data(client, TMP461_REG_CHEN);
16628c2ecf20Sopenharmony_ci		dfc = i2c_smbus_read_byte_data(client, TMP461_REG_DFC);
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci		if ((local_ext & 0x0F) == 0x00 &&
16658c2ecf20Sopenharmony_ci		    (conalert & 0xf1) == 0x01 &&
16668c2ecf20Sopenharmony_ci		    (chen & 0xfc) == 0x00 &&
16678c2ecf20Sopenharmony_ci		    (dfc & 0xfc) == 0x00) {
16688c2ecf20Sopenharmony_ci			if (address == 0x4c && !(chen & 0x03))
16698c2ecf20Sopenharmony_ci				name = "tmp451";
16708c2ecf20Sopenharmony_ci			else if (address >= 0x48 && address <= 0x4f)
16718c2ecf20Sopenharmony_ci				name = "tmp461";
16728c2ecf20Sopenharmony_ci		}
16738c2ecf20Sopenharmony_ci	}
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	if (!name) { /* identification failed */
16768c2ecf20Sopenharmony_ci		dev_dbg(&adapter->dev,
16778c2ecf20Sopenharmony_ci			"Unsupported chip at 0x%02x (man_id=0x%02X, "
16788c2ecf20Sopenharmony_ci			"chip_id=0x%02X)\n", address, man_id, chip_id);
16798c2ecf20Sopenharmony_ci		return -ENODEV;
16808c2ecf20Sopenharmony_ci	}
16818c2ecf20Sopenharmony_ci
16828c2ecf20Sopenharmony_ci	strlcpy(info->type, name, I2C_NAME_SIZE);
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	return 0;
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_cistatic void lm90_restore_conf(void *_data)
16888c2ecf20Sopenharmony_ci{
16898c2ecf20Sopenharmony_ci	struct lm90_data *data = _data;
16908c2ecf20Sopenharmony_ci	struct i2c_client *client = data->client;
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	/* Restore initial configuration */
16938c2ecf20Sopenharmony_ci	lm90_write_convrate(data, data->convrate_orig);
16948c2ecf20Sopenharmony_ci	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
16958c2ecf20Sopenharmony_ci				  data->config_orig);
16968c2ecf20Sopenharmony_ci}
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_cistatic int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
16998c2ecf20Sopenharmony_ci{
17008c2ecf20Sopenharmony_ci	int config, convrate;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	convrate = lm90_read_reg(client, LM90_REG_R_CONVRATE);
17038c2ecf20Sopenharmony_ci	if (convrate < 0)
17048c2ecf20Sopenharmony_ci		return convrate;
17058c2ecf20Sopenharmony_ci	data->convrate_orig = convrate;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci	/*
17088c2ecf20Sopenharmony_ci	 * Start the conversions.
17098c2ecf20Sopenharmony_ci	 */
17108c2ecf20Sopenharmony_ci	config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
17118c2ecf20Sopenharmony_ci	if (config < 0)
17128c2ecf20Sopenharmony_ci		return config;
17138c2ecf20Sopenharmony_ci	data->config_orig = config;
17148c2ecf20Sopenharmony_ci	data->config = config;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	/* Check Temperature Range Select */
17198c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EXTENDED_TEMP) {
17208c2ecf20Sopenharmony_ci		if (config & 0x04)
17218c2ecf20Sopenharmony_ci			data->flags |= LM90_FLAG_ADT7461_EXT;
17228c2ecf20Sopenharmony_ci	}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	/*
17258c2ecf20Sopenharmony_ci	 * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
17268c2ecf20Sopenharmony_ci	 * 0.125 degree resolution) and range (0x08, extend range
17278c2ecf20Sopenharmony_ci	 * to -64 degree) mode for the remote temperature sensor.
17288c2ecf20Sopenharmony_ci	 */
17298c2ecf20Sopenharmony_ci	if (data->kind == max6680)
17308c2ecf20Sopenharmony_ci		config |= 0x18;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	/*
17338c2ecf20Sopenharmony_ci	 * Put MAX6654 into extended range (0x20, extend minimum range from
17348c2ecf20Sopenharmony_ci	 * 0 degrees to -64 degrees). Note that extended resolution is not
17358c2ecf20Sopenharmony_ci	 * possible on the MAX6654 unless conversion rate is set to 1 Hz or
17368c2ecf20Sopenharmony_ci	 * slower, which is intentionally not done by default.
17378c2ecf20Sopenharmony_ci	 */
17388c2ecf20Sopenharmony_ci	if (data->kind == max6654)
17398c2ecf20Sopenharmony_ci		config |= 0x20;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	/*
17428c2ecf20Sopenharmony_ci	 * Select external channel 0 for max6695/96
17438c2ecf20Sopenharmony_ci	 */
17448c2ecf20Sopenharmony_ci	if (data->kind == max6696)
17458c2ecf20Sopenharmony_ci		config &= ~0x08;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	config &= 0xBF;	/* run */
17488c2ecf20Sopenharmony_ci	lm90_update_confreg(data, config);
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	return devm_add_action_or_reset(&client->dev, lm90_restore_conf, data);
17518c2ecf20Sopenharmony_ci}
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_cistatic bool lm90_is_tripped(struct i2c_client *client, u16 *status)
17548c2ecf20Sopenharmony_ci{
17558c2ecf20Sopenharmony_ci	struct lm90_data *data = i2c_get_clientdata(client);
17568c2ecf20Sopenharmony_ci	int st, st2 = 0;
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	st = lm90_read_reg(client, LM90_REG_R_STATUS);
17598c2ecf20Sopenharmony_ci	if (st < 0)
17608c2ecf20Sopenharmony_ci		return false;
17618c2ecf20Sopenharmony_ci
17628c2ecf20Sopenharmony_ci	if (data->kind == max6696) {
17638c2ecf20Sopenharmony_ci		st2 = lm90_read_reg(client, MAX6696_REG_R_STATUS2);
17648c2ecf20Sopenharmony_ci		if (st2 < 0)
17658c2ecf20Sopenharmony_ci			return false;
17668c2ecf20Sopenharmony_ci	}
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci	*status = st | (st2 << 8);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci	if ((st & 0x7f) == 0 && (st2 & 0xfe) == 0)
17718c2ecf20Sopenharmony_ci		return false;
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_ci	if ((st & (LM90_STATUS_LLOW | LM90_STATUS_LHIGH | LM90_STATUS_LTHRM)) ||
17748c2ecf20Sopenharmony_ci	    (st2 & MAX6696_STATUS2_LOT2))
17758c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
17768c2ecf20Sopenharmony_ci			 "temp%d out of range, please check!\n", 1);
17778c2ecf20Sopenharmony_ci	if ((st & (LM90_STATUS_RLOW | LM90_STATUS_RHIGH | LM90_STATUS_RTHRM)) ||
17788c2ecf20Sopenharmony_ci	    (st2 & MAX6696_STATUS2_ROT2))
17798c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
17808c2ecf20Sopenharmony_ci			 "temp%d out of range, please check!\n", 2);
17818c2ecf20Sopenharmony_ci	if (st & LM90_STATUS_ROPEN)
17828c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
17838c2ecf20Sopenharmony_ci			 "temp%d diode open, please check!\n", 2);
17848c2ecf20Sopenharmony_ci	if (st2 & (MAX6696_STATUS2_R2LOW | MAX6696_STATUS2_R2HIGH |
17858c2ecf20Sopenharmony_ci		   MAX6696_STATUS2_R2THRM | MAX6696_STATUS2_R2OT2))
17868c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
17878c2ecf20Sopenharmony_ci			 "temp%d out of range, please check!\n", 3);
17888c2ecf20Sopenharmony_ci	if (st2 & MAX6696_STATUS2_R2OPEN)
17898c2ecf20Sopenharmony_ci		dev_warn(&client->dev,
17908c2ecf20Sopenharmony_ci			 "temp%d diode open, please check!\n", 3);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci	return true;
17938c2ecf20Sopenharmony_ci}
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_cistatic irqreturn_t lm90_irq_thread(int irq, void *dev_id)
17968c2ecf20Sopenharmony_ci{
17978c2ecf20Sopenharmony_ci	struct i2c_client *client = dev_id;
17988c2ecf20Sopenharmony_ci	u16 status;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	if (lm90_is_tripped(client, &status))
18018c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
18028c2ecf20Sopenharmony_ci	else
18038c2ecf20Sopenharmony_ci		return IRQ_NONE;
18048c2ecf20Sopenharmony_ci}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_cistatic void lm90_remove_pec(void *dev)
18078c2ecf20Sopenharmony_ci{
18088c2ecf20Sopenharmony_ci	device_remove_file(dev, &dev_attr_pec);
18098c2ecf20Sopenharmony_ci}
18108c2ecf20Sopenharmony_ci
18118c2ecf20Sopenharmony_cistatic void lm90_regulator_disable(void *regulator)
18128c2ecf20Sopenharmony_ci{
18138c2ecf20Sopenharmony_ci	regulator_disable(regulator);
18148c2ecf20Sopenharmony_ci}
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_cistatic const struct hwmon_ops lm90_ops = {
18188c2ecf20Sopenharmony_ci	.is_visible = lm90_is_visible,
18198c2ecf20Sopenharmony_ci	.read = lm90_read,
18208c2ecf20Sopenharmony_ci	.write = lm90_write,
18218c2ecf20Sopenharmony_ci};
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_cistatic int lm90_probe(struct i2c_client *client)
18248c2ecf20Sopenharmony_ci{
18258c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
18268c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
18278c2ecf20Sopenharmony_ci	struct hwmon_channel_info *info;
18288c2ecf20Sopenharmony_ci	struct regulator *regulator;
18298c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
18308c2ecf20Sopenharmony_ci	struct lm90_data *data;
18318c2ecf20Sopenharmony_ci	int err;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	regulator = devm_regulator_get(dev, "vcc");
18348c2ecf20Sopenharmony_ci	if (IS_ERR(regulator))
18358c2ecf20Sopenharmony_ci		return PTR_ERR(regulator);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	err = regulator_enable(regulator);
18388c2ecf20Sopenharmony_ci	if (err < 0) {
18398c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to enable regulator: %d\n", err);
18408c2ecf20Sopenharmony_ci		return err;
18418c2ecf20Sopenharmony_ci	}
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	err = devm_add_action_or_reset(dev, lm90_regulator_disable, regulator);
18448c2ecf20Sopenharmony_ci	if (err)
18458c2ecf20Sopenharmony_ci		return err;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct lm90_data), GFP_KERNEL);
18488c2ecf20Sopenharmony_ci	if (!data)
18498c2ecf20Sopenharmony_ci		return -ENOMEM;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	data->client = client;
18528c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
18538c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci	/* Set the device type */
18568c2ecf20Sopenharmony_ci	if (client->dev.of_node)
18578c2ecf20Sopenharmony_ci		data->kind = (enum chips)of_device_get_match_data(&client->dev);
18588c2ecf20Sopenharmony_ci	else
18598c2ecf20Sopenharmony_ci		data->kind = i2c_match_id(lm90_id, client)->driver_data;
18608c2ecf20Sopenharmony_ci	if (data->kind == adm1032) {
18618c2ecf20Sopenharmony_ci		if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
18628c2ecf20Sopenharmony_ci			client->flags &= ~I2C_CLIENT_PEC;
18638c2ecf20Sopenharmony_ci	}
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	/*
18668c2ecf20Sopenharmony_ci	 * Different devices have different alarm bits triggering the
18678c2ecf20Sopenharmony_ci	 * ALERT# output
18688c2ecf20Sopenharmony_ci	 */
18698c2ecf20Sopenharmony_ci	data->alert_alarms = lm90_params[data->kind].alert_alarms;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	/* Set chip capabilities */
18728c2ecf20Sopenharmony_ci	data->flags = lm90_params[data->kind].flags;
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	data->chip.ops = &lm90_ops;
18758c2ecf20Sopenharmony_ci	data->chip.info = data->info;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	data->info[0] = HWMON_CHANNEL_INFO(chip,
18788c2ecf20Sopenharmony_ci		HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL | HWMON_C_ALARMS);
18798c2ecf20Sopenharmony_ci	data->info[1] = &data->temp_info;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	info = &data->temp_info;
18828c2ecf20Sopenharmony_ci	info->type = hwmon_temp;
18838c2ecf20Sopenharmony_ci	info->config = data->channel_config;
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	data->channel_config[0] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
18868c2ecf20Sopenharmony_ci		HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM;
18878c2ecf20Sopenharmony_ci	data->channel_config[1] = HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
18888c2ecf20Sopenharmony_ci		HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM | HWMON_T_FAULT;
18898c2ecf20Sopenharmony_ci
18908c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_CRIT) {
18918c2ecf20Sopenharmony_ci		data->channel_config[0] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
18928c2ecf20Sopenharmony_ci		data->channel_config[1] |= HWMON_T_CRIT | HWMON_T_CRIT_ALARM | HWMON_T_CRIT_HYST;
18938c2ecf20Sopenharmony_ci	}
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_OFFSET)
18968c2ecf20Sopenharmony_ci		data->channel_config[1] |= HWMON_T_OFFSET;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EMERGENCY) {
18998c2ecf20Sopenharmony_ci		data->channel_config[0] |= HWMON_T_EMERGENCY |
19008c2ecf20Sopenharmony_ci			HWMON_T_EMERGENCY_HYST;
19018c2ecf20Sopenharmony_ci		data->channel_config[1] |= HWMON_T_EMERGENCY |
19028c2ecf20Sopenharmony_ci			HWMON_T_EMERGENCY_HYST;
19038c2ecf20Sopenharmony_ci	}
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_EMERGENCY_ALARM) {
19068c2ecf20Sopenharmony_ci		data->channel_config[0] |= HWMON_T_EMERGENCY_ALARM;
19078c2ecf20Sopenharmony_ci		data->channel_config[1] |= HWMON_T_EMERGENCY_ALARM;
19088c2ecf20Sopenharmony_ci	}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	if (data->flags & LM90_HAVE_TEMP3) {
19118c2ecf20Sopenharmony_ci		data->channel_config[2] = HWMON_T_INPUT |
19128c2ecf20Sopenharmony_ci			HWMON_T_MIN | HWMON_T_MAX |
19138c2ecf20Sopenharmony_ci			HWMON_T_CRIT | HWMON_T_CRIT_HYST |
19148c2ecf20Sopenharmony_ci			HWMON_T_EMERGENCY | HWMON_T_EMERGENCY_HYST |
19158c2ecf20Sopenharmony_ci			HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM |
19168c2ecf20Sopenharmony_ci			HWMON_T_CRIT_ALARM | HWMON_T_EMERGENCY_ALARM |
19178c2ecf20Sopenharmony_ci			HWMON_T_FAULT;
19188c2ecf20Sopenharmony_ci	}
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	data->reg_local_ext = lm90_params[data->kind].reg_local_ext;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	/* Set maximum conversion rate */
19238c2ecf20Sopenharmony_ci	data->max_convrate = lm90_params[data->kind].max_convrate;
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci	/* Initialize the LM90 chip */
19268c2ecf20Sopenharmony_ci	err = lm90_init_client(client, data);
19278c2ecf20Sopenharmony_ci	if (err < 0) {
19288c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to initialize device\n");
19298c2ecf20Sopenharmony_ci		return err;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	/*
19338c2ecf20Sopenharmony_ci	 * The 'pec' attribute is attached to the i2c device and thus created
19348c2ecf20Sopenharmony_ci	 * separately.
19358c2ecf20Sopenharmony_ci	 */
19368c2ecf20Sopenharmony_ci	if (client->flags & I2C_CLIENT_PEC) {
19378c2ecf20Sopenharmony_ci		err = device_create_file(dev, &dev_attr_pec);
19388c2ecf20Sopenharmony_ci		if (err)
19398c2ecf20Sopenharmony_ci			return err;
19408c2ecf20Sopenharmony_ci		err = devm_add_action_or_reset(dev, lm90_remove_pec, dev);
19418c2ecf20Sopenharmony_ci		if (err)
19428c2ecf20Sopenharmony_ci			return err;
19438c2ecf20Sopenharmony_ci	}
19448c2ecf20Sopenharmony_ci
19458c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
19468c2ecf20Sopenharmony_ci							 data, &data->chip,
19478c2ecf20Sopenharmony_ci							 NULL);
19488c2ecf20Sopenharmony_ci	if (IS_ERR(hwmon_dev))
19498c2ecf20Sopenharmony_ci		return PTR_ERR(hwmon_dev);
19508c2ecf20Sopenharmony_ci
19518c2ecf20Sopenharmony_ci	if (client->irq) {
19528c2ecf20Sopenharmony_ci		dev_dbg(dev, "IRQ: %d\n", client->irq);
19538c2ecf20Sopenharmony_ci		err = devm_request_threaded_irq(dev, client->irq,
19548c2ecf20Sopenharmony_ci						NULL, lm90_irq_thread,
19558c2ecf20Sopenharmony_ci						IRQF_TRIGGER_LOW | IRQF_ONESHOT,
19568c2ecf20Sopenharmony_ci						"lm90", client);
19578c2ecf20Sopenharmony_ci		if (err < 0) {
19588c2ecf20Sopenharmony_ci			dev_err(dev, "cannot request IRQ %d\n", client->irq);
19598c2ecf20Sopenharmony_ci			return err;
19608c2ecf20Sopenharmony_ci		}
19618c2ecf20Sopenharmony_ci	}
19628c2ecf20Sopenharmony_ci
19638c2ecf20Sopenharmony_ci	return 0;
19648c2ecf20Sopenharmony_ci}
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_cistatic void lm90_alert(struct i2c_client *client, enum i2c_alert_protocol type,
19678c2ecf20Sopenharmony_ci		       unsigned int flag)
19688c2ecf20Sopenharmony_ci{
19698c2ecf20Sopenharmony_ci	u16 alarms;
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	if (type != I2C_PROTOCOL_SMBUS_ALERT)
19728c2ecf20Sopenharmony_ci		return;
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	if (lm90_is_tripped(client, &alarms)) {
19758c2ecf20Sopenharmony_ci		/*
19768c2ecf20Sopenharmony_ci		 * Disable ALERT# output, because these chips don't implement
19778c2ecf20Sopenharmony_ci		 * SMBus alert correctly; they should only hold the alert line
19788c2ecf20Sopenharmony_ci		 * low briefly.
19798c2ecf20Sopenharmony_ci		 */
19808c2ecf20Sopenharmony_ci		struct lm90_data *data = i2c_get_clientdata(client);
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci		if ((data->flags & LM90_HAVE_BROKEN_ALERT) &&
19838c2ecf20Sopenharmony_ci		    (alarms & data->alert_alarms)) {
19848c2ecf20Sopenharmony_ci			dev_dbg(&client->dev, "Disabling ALERT#\n");
19858c2ecf20Sopenharmony_ci			lm90_update_confreg(data, data->config | 0x80);
19868c2ecf20Sopenharmony_ci		}
19878c2ecf20Sopenharmony_ci	} else {
19888c2ecf20Sopenharmony_ci		dev_info(&client->dev, "Everything OK\n");
19898c2ecf20Sopenharmony_ci	}
19908c2ecf20Sopenharmony_ci}
19918c2ecf20Sopenharmony_ci
19928c2ecf20Sopenharmony_cistatic struct i2c_driver lm90_driver = {
19938c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_HWMON,
19948c2ecf20Sopenharmony_ci	.driver = {
19958c2ecf20Sopenharmony_ci		.name	= "lm90",
19968c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(lm90_of_match),
19978c2ecf20Sopenharmony_ci	},
19988c2ecf20Sopenharmony_ci	.probe_new	= lm90_probe,
19998c2ecf20Sopenharmony_ci	.alert		= lm90_alert,
20008c2ecf20Sopenharmony_ci	.id_table	= lm90_id,
20018c2ecf20Sopenharmony_ci	.detect		= lm90_detect,
20028c2ecf20Sopenharmony_ci	.address_list	= normal_i2c,
20038c2ecf20Sopenharmony_ci};
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cimodule_i2c_driver(lm90_driver);
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
20088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("LM90/ADM1032 driver");
20098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2010