xref: /kernel/linux/linux-5.10/drivers/hwmon/jc42.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * jc42.c - driver for Jedec JC42.4 compliant temperature sensors
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010  Ericsson AB.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Derived from lm77.c by Andras BALI <drewie@freemail.hu>.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * JC42.4 compliant temperature sensors are typically used on memory modules.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/bitops.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/init.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
178c2ecf20Sopenharmony_ci#include <linux/i2c.h>
188c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
198c2ecf20Sopenharmony_ci#include <linux/err.h>
208c2ecf20Sopenharmony_ci#include <linux/mutex.h>
218c2ecf20Sopenharmony_ci#include <linux/of.h>
228c2ecf20Sopenharmony_ci#include <linux/regmap.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Addresses to scan */
258c2ecf20Sopenharmony_cistatic const unsigned short normal_i2c[] = {
268c2ecf20Sopenharmony_ci	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, I2C_CLIENT_END };
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* JC42 registers. All registers are 16 bit. */
298c2ecf20Sopenharmony_ci#define JC42_REG_CAP		0x00
308c2ecf20Sopenharmony_ci#define JC42_REG_CONFIG		0x01
318c2ecf20Sopenharmony_ci#define JC42_REG_TEMP_UPPER	0x02
328c2ecf20Sopenharmony_ci#define JC42_REG_TEMP_LOWER	0x03
338c2ecf20Sopenharmony_ci#define JC42_REG_TEMP_CRITICAL	0x04
348c2ecf20Sopenharmony_ci#define JC42_REG_TEMP		0x05
358c2ecf20Sopenharmony_ci#define JC42_REG_MANID		0x06
368c2ecf20Sopenharmony_ci#define JC42_REG_DEVICEID	0x07
378c2ecf20Sopenharmony_ci#define JC42_REG_SMBUS		0x22 /* NXP and Atmel, possibly others? */
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/* Status bits in temperature register */
408c2ecf20Sopenharmony_ci#define JC42_ALARM_CRIT_BIT	15
418c2ecf20Sopenharmony_ci#define JC42_ALARM_MAX_BIT	14
428c2ecf20Sopenharmony_ci#define JC42_ALARM_MIN_BIT	13
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Configuration register defines */
458c2ecf20Sopenharmony_ci#define JC42_CFG_CRIT_ONLY	(1 << 2)
468c2ecf20Sopenharmony_ci#define JC42_CFG_TCRIT_LOCK	(1 << 6)
478c2ecf20Sopenharmony_ci#define JC42_CFG_EVENT_LOCK	(1 << 7)
488c2ecf20Sopenharmony_ci#define JC42_CFG_SHUTDOWN	(1 << 8)
498c2ecf20Sopenharmony_ci#define JC42_CFG_HYST_SHIFT	9
508c2ecf20Sopenharmony_ci#define JC42_CFG_HYST_MASK	(0x03 << 9)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/* Capabilities */
538c2ecf20Sopenharmony_ci#define JC42_CAP_RANGE		(1 << 2)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Manufacturer IDs */
568c2ecf20Sopenharmony_ci#define ADT_MANID		0x11d4  /* Analog Devices */
578c2ecf20Sopenharmony_ci#define ATMEL_MANID		0x001f  /* Atmel */
588c2ecf20Sopenharmony_ci#define ATMEL_MANID2		0x1114	/* Atmel */
598c2ecf20Sopenharmony_ci#define MAX_MANID		0x004d  /* Maxim */
608c2ecf20Sopenharmony_ci#define IDT_MANID		0x00b3  /* IDT */
618c2ecf20Sopenharmony_ci#define MCP_MANID		0x0054  /* Microchip */
628c2ecf20Sopenharmony_ci#define NXP_MANID		0x1131  /* NXP Semiconductors */
638c2ecf20Sopenharmony_ci#define ONS_MANID		0x1b09  /* ON Semiconductor */
648c2ecf20Sopenharmony_ci#define STM_MANID		0x104a  /* ST Microelectronics */
658c2ecf20Sopenharmony_ci#define GT_MANID		0x1c68	/* Giantec */
668c2ecf20Sopenharmony_ci#define GT_MANID2		0x132d	/* Giantec, 2nd mfg ID */
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/* SMBUS register */
698c2ecf20Sopenharmony_ci#define SMBUS_STMOUT		BIT(7)  /* SMBus time-out, active low */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* Supported chips */
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/* Analog Devices */
748c2ecf20Sopenharmony_ci#define ADT7408_DEVID		0x0801
758c2ecf20Sopenharmony_ci#define ADT7408_DEVID_MASK	0xffff
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/* Atmel */
788c2ecf20Sopenharmony_ci#define AT30TS00_DEVID		0x8201
798c2ecf20Sopenharmony_ci#define AT30TS00_DEVID_MASK	0xffff
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define AT30TSE004_DEVID	0x2200
828c2ecf20Sopenharmony_ci#define AT30TSE004_DEVID_MASK	0xffff
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci/* Giantec */
858c2ecf20Sopenharmony_ci#define GT30TS00_DEVID		0x2200
868c2ecf20Sopenharmony_ci#define GT30TS00_DEVID_MASK	0xff00
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define GT34TS02_DEVID		0x3300
898c2ecf20Sopenharmony_ci#define GT34TS02_DEVID_MASK	0xff00
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* IDT */
928c2ecf20Sopenharmony_ci#define TSE2004_DEVID		0x2200
938c2ecf20Sopenharmony_ci#define TSE2004_DEVID_MASK	0xff00
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define TS3000_DEVID		0x2900  /* Also matches TSE2002 */
968c2ecf20Sopenharmony_ci#define TS3000_DEVID_MASK	0xff00
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#define TS3001_DEVID		0x3000
998c2ecf20Sopenharmony_ci#define TS3001_DEVID_MASK	0xff00
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* Maxim */
1028c2ecf20Sopenharmony_ci#define MAX6604_DEVID		0x3e00
1038c2ecf20Sopenharmony_ci#define MAX6604_DEVID_MASK	0xffff
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Microchip */
1068c2ecf20Sopenharmony_ci#define MCP9804_DEVID		0x0200
1078c2ecf20Sopenharmony_ci#define MCP9804_DEVID_MASK	0xfffc
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci#define MCP9808_DEVID		0x0400
1108c2ecf20Sopenharmony_ci#define MCP9808_DEVID_MASK	0xfffc
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci#define MCP98242_DEVID		0x2000
1138c2ecf20Sopenharmony_ci#define MCP98242_DEVID_MASK	0xfffc
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define MCP98243_DEVID		0x2100
1168c2ecf20Sopenharmony_ci#define MCP98243_DEVID_MASK	0xfffc
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci#define MCP98244_DEVID		0x2200
1198c2ecf20Sopenharmony_ci#define MCP98244_DEVID_MASK	0xfffc
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci#define MCP9843_DEVID		0x0000	/* Also matches mcp9805 */
1228c2ecf20Sopenharmony_ci#define MCP9843_DEVID_MASK	0xfffe
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* NXP */
1258c2ecf20Sopenharmony_ci#define SE97_DEVID		0xa200
1268c2ecf20Sopenharmony_ci#define SE97_DEVID_MASK		0xfffc
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define SE98_DEVID		0xa100
1298c2ecf20Sopenharmony_ci#define SE98_DEVID_MASK		0xfffc
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* ON Semiconductor */
1328c2ecf20Sopenharmony_ci#define CAT6095_DEVID		0x0800	/* Also matches CAT34TS02 */
1338c2ecf20Sopenharmony_ci#define CAT6095_DEVID_MASK	0xffe0
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#define CAT34TS02C_DEVID	0x0a00
1368c2ecf20Sopenharmony_ci#define CAT34TS02C_DEVID_MASK	0xfff0
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#define CAT34TS04_DEVID		0x2200
1398c2ecf20Sopenharmony_ci#define CAT34TS04_DEVID_MASK	0xfff0
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci/* ST Microelectronics */
1428c2ecf20Sopenharmony_ci#define STTS424_DEVID		0x0101
1438c2ecf20Sopenharmony_ci#define STTS424_DEVID_MASK	0xffff
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define STTS424E_DEVID		0x0000
1468c2ecf20Sopenharmony_ci#define STTS424E_DEVID_MASK	0xfffe
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci#define STTS2002_DEVID		0x0300
1498c2ecf20Sopenharmony_ci#define STTS2002_DEVID_MASK	0xffff
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci#define STTS2004_DEVID		0x2201
1528c2ecf20Sopenharmony_ci#define STTS2004_DEVID_MASK	0xffff
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci#define STTS3000_DEVID		0x0200
1558c2ecf20Sopenharmony_ci#define STTS3000_DEVID_MASK	0xffff
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic u16 jc42_hysteresis[] = { 0, 1500, 3000, 6000 };
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistruct jc42_chips {
1608c2ecf20Sopenharmony_ci	u16 manid;
1618c2ecf20Sopenharmony_ci	u16 devid;
1628c2ecf20Sopenharmony_ci	u16 devid_mask;
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic struct jc42_chips jc42_chips[] = {
1668c2ecf20Sopenharmony_ci	{ ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
1678c2ecf20Sopenharmony_ci	{ ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
1688c2ecf20Sopenharmony_ci	{ ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK },
1698c2ecf20Sopenharmony_ci	{ GT_MANID, GT30TS00_DEVID, GT30TS00_DEVID_MASK },
1708c2ecf20Sopenharmony_ci	{ GT_MANID2, GT34TS02_DEVID, GT34TS02_DEVID_MASK },
1718c2ecf20Sopenharmony_ci	{ IDT_MANID, TSE2004_DEVID, TSE2004_DEVID_MASK },
1728c2ecf20Sopenharmony_ci	{ IDT_MANID, TS3000_DEVID, TS3000_DEVID_MASK },
1738c2ecf20Sopenharmony_ci	{ IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK },
1748c2ecf20Sopenharmony_ci	{ MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
1758c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
1768c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP9808_DEVID, MCP9808_DEVID_MASK },
1778c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
1788c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
1798c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
1808c2ecf20Sopenharmony_ci	{ MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
1818c2ecf20Sopenharmony_ci	{ NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
1828c2ecf20Sopenharmony_ci	{ ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
1838c2ecf20Sopenharmony_ci	{ ONS_MANID, CAT34TS02C_DEVID, CAT34TS02C_DEVID_MASK },
1848c2ecf20Sopenharmony_ci	{ ONS_MANID, CAT34TS04_DEVID, CAT34TS04_DEVID_MASK },
1858c2ecf20Sopenharmony_ci	{ NXP_MANID, SE98_DEVID, SE98_DEVID_MASK },
1868c2ecf20Sopenharmony_ci	{ STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
1878c2ecf20Sopenharmony_ci	{ STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
1888c2ecf20Sopenharmony_ci	{ STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
1898c2ecf20Sopenharmony_ci	{ STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK },
1908c2ecf20Sopenharmony_ci	{ STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* Each client has this additional data */
1948c2ecf20Sopenharmony_cistruct jc42_data {
1958c2ecf20Sopenharmony_ci	struct mutex	update_lock;	/* protect register access */
1968c2ecf20Sopenharmony_ci	struct regmap	*regmap;
1978c2ecf20Sopenharmony_ci	bool		extended;	/* true if extended range supported */
1988c2ecf20Sopenharmony_ci	bool		valid;
1998c2ecf20Sopenharmony_ci	u16		orig_config;	/* original configuration */
2008c2ecf20Sopenharmony_ci	u16		config;		/* current configuration */
2018c2ecf20Sopenharmony_ci};
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci#define JC42_TEMP_MIN_EXTENDED	(-40000)
2048c2ecf20Sopenharmony_ci#define JC42_TEMP_MIN		0
2058c2ecf20Sopenharmony_ci#define JC42_TEMP_MAX		125000
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic u16 jc42_temp_to_reg(long temp, bool extended)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	int ntemp = clamp_val(temp,
2108c2ecf20Sopenharmony_ci			      extended ? JC42_TEMP_MIN_EXTENDED :
2118c2ecf20Sopenharmony_ci			      JC42_TEMP_MIN, JC42_TEMP_MAX);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/* convert from 0.001 to 0.0625 resolution */
2148c2ecf20Sopenharmony_ci	return (ntemp * 2 / 125) & 0x1fff;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int jc42_temp_from_reg(s16 reg)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	reg = sign_extend32(reg, 12);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* convert from 0.0625 to 0.001 resolution */
2228c2ecf20Sopenharmony_ci	return reg * 125 / 2;
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int jc42_read(struct device *dev, enum hwmon_sensor_types type,
2268c2ecf20Sopenharmony_ci		     u32 attr, int channel, long *val)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	struct jc42_data *data = dev_get_drvdata(dev);
2298c2ecf20Sopenharmony_ci	unsigned int regval;
2308c2ecf20Sopenharmony_ci	int ret, temp, hyst;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	switch (attr) {
2358c2ecf20Sopenharmony_ci	case hwmon_temp_input:
2368c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval);
2378c2ecf20Sopenharmony_ci		if (ret)
2388c2ecf20Sopenharmony_ci			break;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		*val = jc42_temp_from_reg(regval);
2418c2ecf20Sopenharmony_ci		break;
2428c2ecf20Sopenharmony_ci	case hwmon_temp_min:
2438c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_LOWER, &regval);
2448c2ecf20Sopenharmony_ci		if (ret)
2458c2ecf20Sopenharmony_ci			break;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		*val = jc42_temp_from_reg(regval);
2488c2ecf20Sopenharmony_ci		break;
2498c2ecf20Sopenharmony_ci	case hwmon_temp_max:
2508c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, &regval);
2518c2ecf20Sopenharmony_ci		if (ret)
2528c2ecf20Sopenharmony_ci			break;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		*val = jc42_temp_from_reg(regval);
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
2578c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
2588c2ecf20Sopenharmony_ci				  &regval);
2598c2ecf20Sopenharmony_ci		if (ret)
2608c2ecf20Sopenharmony_ci			break;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		*val = jc42_temp_from_reg(regval);
2638c2ecf20Sopenharmony_ci		break;
2648c2ecf20Sopenharmony_ci	case hwmon_temp_max_hyst:
2658c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, &regval);
2668c2ecf20Sopenharmony_ci		if (ret)
2678c2ecf20Sopenharmony_ci			break;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		temp = jc42_temp_from_reg(regval);
2708c2ecf20Sopenharmony_ci		hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
2718c2ecf20Sopenharmony_ci						>> JC42_CFG_HYST_SHIFT];
2728c2ecf20Sopenharmony_ci		*val = temp - hyst;
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
2758c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
2768c2ecf20Sopenharmony_ci				  &regval);
2778c2ecf20Sopenharmony_ci		if (ret)
2788c2ecf20Sopenharmony_ci			break;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		temp = jc42_temp_from_reg(regval);
2818c2ecf20Sopenharmony_ci		hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
2828c2ecf20Sopenharmony_ci						>> JC42_CFG_HYST_SHIFT];
2838c2ecf20Sopenharmony_ci		*val = temp - hyst;
2848c2ecf20Sopenharmony_ci		break;
2858c2ecf20Sopenharmony_ci	case hwmon_temp_min_alarm:
2868c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval);
2878c2ecf20Sopenharmony_ci		if (ret)
2888c2ecf20Sopenharmony_ci			break;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		*val = (regval >> JC42_ALARM_MIN_BIT) & 1;
2918c2ecf20Sopenharmony_ci		break;
2928c2ecf20Sopenharmony_ci	case hwmon_temp_max_alarm:
2938c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval);
2948c2ecf20Sopenharmony_ci		if (ret)
2958c2ecf20Sopenharmony_ci			break;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		*val = (regval >> JC42_ALARM_MAX_BIT) & 1;
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	case hwmon_temp_crit_alarm:
3008c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP, &regval);
3018c2ecf20Sopenharmony_ci		if (ret)
3028c2ecf20Sopenharmony_ci			break;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		*val = (regval >> JC42_ALARM_CRIT_BIT) & 1;
3058c2ecf20Sopenharmony_ci		break;
3068c2ecf20Sopenharmony_ci	default:
3078c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
3088c2ecf20Sopenharmony_ci		break;
3098c2ecf20Sopenharmony_ci	}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return ret;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int jc42_write(struct device *dev, enum hwmon_sensor_types type,
3178c2ecf20Sopenharmony_ci		      u32 attr, int channel, long val)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct jc42_data *data = dev_get_drvdata(dev);
3208c2ecf20Sopenharmony_ci	unsigned int regval;
3218c2ecf20Sopenharmony_ci	int diff, hyst;
3228c2ecf20Sopenharmony_ci	int ret;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	mutex_lock(&data->update_lock);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	switch (attr) {
3278c2ecf20Sopenharmony_ci	case hwmon_temp_min:
3288c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER,
3298c2ecf20Sopenharmony_ci				   jc42_temp_to_reg(val, data->extended));
3308c2ecf20Sopenharmony_ci		break;
3318c2ecf20Sopenharmony_ci	case hwmon_temp_max:
3328c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, JC42_REG_TEMP_UPPER,
3338c2ecf20Sopenharmony_ci				   jc42_temp_to_reg(val, data->extended));
3348c2ecf20Sopenharmony_ci		break;
3358c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
3368c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, JC42_REG_TEMP_CRITICAL,
3378c2ecf20Sopenharmony_ci				   jc42_temp_to_reg(val, data->extended));
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
3408c2ecf20Sopenharmony_ci		ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
3418c2ecf20Sopenharmony_ci				  &regval);
3428c2ecf20Sopenharmony_ci		if (ret)
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		/*
3468c2ecf20Sopenharmony_ci		 * JC42.4 compliant chips only support four hysteresis values.
3478c2ecf20Sopenharmony_ci		 * Pick best choice and go from there.
3488c2ecf20Sopenharmony_ci		 */
3498c2ecf20Sopenharmony_ci		val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED
3508c2ecf20Sopenharmony_ci						     : JC42_TEMP_MIN) - 6000,
3518c2ecf20Sopenharmony_ci				JC42_TEMP_MAX);
3528c2ecf20Sopenharmony_ci		diff = jc42_temp_from_reg(regval) - val;
3538c2ecf20Sopenharmony_ci		hyst = 0;
3548c2ecf20Sopenharmony_ci		if (diff > 0) {
3558c2ecf20Sopenharmony_ci			if (diff < 2250)
3568c2ecf20Sopenharmony_ci				hyst = 1;	/* 1.5 degrees C */
3578c2ecf20Sopenharmony_ci			else if (diff < 4500)
3588c2ecf20Sopenharmony_ci				hyst = 2;	/* 3.0 degrees C */
3598c2ecf20Sopenharmony_ci			else
3608c2ecf20Sopenharmony_ci				hyst = 3;	/* 6.0 degrees C */
3618c2ecf20Sopenharmony_ci		}
3628c2ecf20Sopenharmony_ci		data->config = (data->config & ~JC42_CFG_HYST_MASK) |
3638c2ecf20Sopenharmony_ci				(hyst << JC42_CFG_HYST_SHIFT);
3648c2ecf20Sopenharmony_ci		ret = regmap_write(data->regmap, JC42_REG_CONFIG,
3658c2ecf20Sopenharmony_ci				   data->config);
3668c2ecf20Sopenharmony_ci		break;
3678c2ecf20Sopenharmony_ci	default:
3688c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
3698c2ecf20Sopenharmony_ci		break;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	mutex_unlock(&data->update_lock);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return ret;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_cistatic umode_t jc42_is_visible(const void *_data, enum hwmon_sensor_types type,
3788c2ecf20Sopenharmony_ci			       u32 attr, int channel)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	const struct jc42_data *data = _data;
3818c2ecf20Sopenharmony_ci	unsigned int config = data->config;
3828c2ecf20Sopenharmony_ci	umode_t mode = 0444;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	switch (attr) {
3858c2ecf20Sopenharmony_ci	case hwmon_temp_min:
3868c2ecf20Sopenharmony_ci	case hwmon_temp_max:
3878c2ecf20Sopenharmony_ci		if (!(config & JC42_CFG_EVENT_LOCK))
3888c2ecf20Sopenharmony_ci			mode |= 0200;
3898c2ecf20Sopenharmony_ci		break;
3908c2ecf20Sopenharmony_ci	case hwmon_temp_crit:
3918c2ecf20Sopenharmony_ci		if (!(config & JC42_CFG_TCRIT_LOCK))
3928c2ecf20Sopenharmony_ci			mode |= 0200;
3938c2ecf20Sopenharmony_ci		break;
3948c2ecf20Sopenharmony_ci	case hwmon_temp_crit_hyst:
3958c2ecf20Sopenharmony_ci		if (!(config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK)))
3968c2ecf20Sopenharmony_ci			mode |= 0200;
3978c2ecf20Sopenharmony_ci		break;
3988c2ecf20Sopenharmony_ci	case hwmon_temp_input:
3998c2ecf20Sopenharmony_ci	case hwmon_temp_max_hyst:
4008c2ecf20Sopenharmony_ci	case hwmon_temp_min_alarm:
4018c2ecf20Sopenharmony_ci	case hwmon_temp_max_alarm:
4028c2ecf20Sopenharmony_ci	case hwmon_temp_crit_alarm:
4038c2ecf20Sopenharmony_ci		break;
4048c2ecf20Sopenharmony_ci	default:
4058c2ecf20Sopenharmony_ci		mode = 0;
4068c2ecf20Sopenharmony_ci		break;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci	return mode;
4098c2ecf20Sopenharmony_ci}
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci/* Return 0 if detection is successful, -ENODEV otherwise */
4128c2ecf20Sopenharmony_cistatic int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = client->adapter;
4158c2ecf20Sopenharmony_ci	int i, config, cap, manid, devid;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
4188c2ecf20Sopenharmony_ci				     I2C_FUNC_SMBUS_WORD_DATA))
4198c2ecf20Sopenharmony_ci		return -ENODEV;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
4228c2ecf20Sopenharmony_ci	config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
4238c2ecf20Sopenharmony_ci	manid = i2c_smbus_read_word_swapped(client, JC42_REG_MANID);
4248c2ecf20Sopenharmony_ci	devid = i2c_smbus_read_word_swapped(client, JC42_REG_DEVICEID);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (cap < 0 || config < 0 || manid < 0 || devid < 0)
4278c2ecf20Sopenharmony_ci		return -ENODEV;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	if ((cap & 0xff00) || (config & 0xf800))
4308c2ecf20Sopenharmony_ci		return -ENODEV;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(jc42_chips); i++) {
4338c2ecf20Sopenharmony_ci		struct jc42_chips *chip = &jc42_chips[i];
4348c2ecf20Sopenharmony_ci		if (manid == chip->manid &&
4358c2ecf20Sopenharmony_ci		    (devid & chip->devid_mask) == chip->devid) {
4368c2ecf20Sopenharmony_ci			strlcpy(info->type, "jc42", I2C_NAME_SIZE);
4378c2ecf20Sopenharmony_ci			return 0;
4388c2ecf20Sopenharmony_ci		}
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci	return -ENODEV;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic const struct hwmon_channel_info *jc42_info[] = {
4448c2ecf20Sopenharmony_ci	HWMON_CHANNEL_INFO(temp,
4458c2ecf20Sopenharmony_ci			   HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
4468c2ecf20Sopenharmony_ci			   HWMON_T_CRIT | HWMON_T_MAX_HYST |
4478c2ecf20Sopenharmony_ci			   HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
4488c2ecf20Sopenharmony_ci			   HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM),
4498c2ecf20Sopenharmony_ci	NULL
4508c2ecf20Sopenharmony_ci};
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic const struct hwmon_ops jc42_hwmon_ops = {
4538c2ecf20Sopenharmony_ci	.is_visible = jc42_is_visible,
4548c2ecf20Sopenharmony_ci	.read = jc42_read,
4558c2ecf20Sopenharmony_ci	.write = jc42_write,
4568c2ecf20Sopenharmony_ci};
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic const struct hwmon_chip_info jc42_chip_info = {
4598c2ecf20Sopenharmony_ci	.ops = &jc42_hwmon_ops,
4608c2ecf20Sopenharmony_ci	.info = jc42_info,
4618c2ecf20Sopenharmony_ci};
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic bool jc42_readable_reg(struct device *dev, unsigned int reg)
4648c2ecf20Sopenharmony_ci{
4658c2ecf20Sopenharmony_ci	return (reg >= JC42_REG_CAP && reg <= JC42_REG_DEVICEID) ||
4668c2ecf20Sopenharmony_ci		reg == JC42_REG_SMBUS;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic bool jc42_writable_reg(struct device *dev, unsigned int reg)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	return (reg >= JC42_REG_CONFIG && reg <= JC42_REG_TEMP_CRITICAL) ||
4728c2ecf20Sopenharmony_ci		reg == JC42_REG_SMBUS;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic bool jc42_volatile_reg(struct device *dev, unsigned int reg)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	return reg == JC42_REG_CONFIG || reg == JC42_REG_TEMP;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic const struct regmap_config jc42_regmap_config = {
4818c2ecf20Sopenharmony_ci	.reg_bits = 8,
4828c2ecf20Sopenharmony_ci	.val_bits = 16,
4838c2ecf20Sopenharmony_ci	.val_format_endian = REGMAP_ENDIAN_BIG,
4848c2ecf20Sopenharmony_ci	.max_register = JC42_REG_SMBUS,
4858c2ecf20Sopenharmony_ci	.writeable_reg = jc42_writable_reg,
4868c2ecf20Sopenharmony_ci	.readable_reg = jc42_readable_reg,
4878c2ecf20Sopenharmony_ci	.volatile_reg = jc42_volatile_reg,
4888c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
4898c2ecf20Sopenharmony_ci};
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic int jc42_probe(struct i2c_client *client)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
4948c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
4958c2ecf20Sopenharmony_ci	unsigned int config, cap;
4968c2ecf20Sopenharmony_ci	struct jc42_data *data;
4978c2ecf20Sopenharmony_ci	int ret;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL);
5008c2ecf20Sopenharmony_ci	if (!data)
5018c2ecf20Sopenharmony_ci		return -ENOMEM;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	data->regmap = devm_regmap_init_i2c(client, &jc42_regmap_config);
5048c2ecf20Sopenharmony_ci	if (IS_ERR(data->regmap))
5058c2ecf20Sopenharmony_ci		return PTR_ERR(data->regmap);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, data);
5088c2ecf20Sopenharmony_ci	mutex_init(&data->update_lock);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, JC42_REG_CAP, &cap);
5118c2ecf20Sopenharmony_ci	if (ret)
5128c2ecf20Sopenharmony_ci		return ret;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	data->extended = !!(cap & JC42_CAP_RANGE);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	if (device_property_read_bool(dev, "smbus-timeout-disable")) {
5178c2ecf20Sopenharmony_ci		/*
5188c2ecf20Sopenharmony_ci		 * Not all chips support this register, but from a
5198c2ecf20Sopenharmony_ci		 * quick read of various datasheets no chip appears
5208c2ecf20Sopenharmony_ci		 * incompatible with the below attempt to disable
5218c2ecf20Sopenharmony_ci		 * the timeout. And the whole thing is opt-in...
5228c2ecf20Sopenharmony_ci		 */
5238c2ecf20Sopenharmony_ci		ret = regmap_set_bits(data->regmap, JC42_REG_SMBUS,
5248c2ecf20Sopenharmony_ci				      SMBUS_STMOUT);
5258c2ecf20Sopenharmony_ci		if (ret)
5268c2ecf20Sopenharmony_ci			return ret;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	ret = regmap_read(data->regmap, JC42_REG_CONFIG, &config);
5308c2ecf20Sopenharmony_ci	if (ret)
5318c2ecf20Sopenharmony_ci		return ret;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	data->orig_config = config;
5348c2ecf20Sopenharmony_ci	if (config & JC42_CFG_SHUTDOWN) {
5358c2ecf20Sopenharmony_ci		config &= ~JC42_CFG_SHUTDOWN;
5368c2ecf20Sopenharmony_ci		regmap_write(data->regmap, JC42_REG_CONFIG, config);
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci	data->config = config;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	hwmon_dev = devm_hwmon_device_register_with_info(dev, "jc42",
5418c2ecf20Sopenharmony_ci							 data, &jc42_chip_info,
5428c2ecf20Sopenharmony_ci							 NULL);
5438c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(hwmon_dev);
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic int jc42_remove(struct i2c_client *client)
5478c2ecf20Sopenharmony_ci{
5488c2ecf20Sopenharmony_ci	struct jc42_data *data = i2c_get_clientdata(client);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	/* Restore original configuration except hysteresis */
5518c2ecf20Sopenharmony_ci	if ((data->config & ~JC42_CFG_HYST_MASK) !=
5528c2ecf20Sopenharmony_ci	    (data->orig_config & ~JC42_CFG_HYST_MASK)) {
5538c2ecf20Sopenharmony_ci		int config;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		config = (data->orig_config & ~JC42_CFG_HYST_MASK)
5568c2ecf20Sopenharmony_ci		  | (data->config & JC42_CFG_HYST_MASK);
5578c2ecf20Sopenharmony_ci		regmap_write(data->regmap, JC42_REG_CONFIG, config);
5588c2ecf20Sopenharmony_ci	}
5598c2ecf20Sopenharmony_ci	return 0;
5608c2ecf20Sopenharmony_ci}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic int jc42_suspend(struct device *dev)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct jc42_data *data = dev_get_drvdata(dev);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	data->config |= JC42_CFG_SHUTDOWN;
5698c2ecf20Sopenharmony_ci	regmap_write(data->regmap, JC42_REG_CONFIG, data->config);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	regcache_cache_only(data->regmap, true);
5728c2ecf20Sopenharmony_ci	regcache_mark_dirty(data->regmap);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return 0;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic int jc42_resume(struct device *dev)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct jc42_data *data = dev_get_drvdata(dev);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	regcache_cache_only(data->regmap, false);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	data->config &= ~JC42_CFG_SHUTDOWN;
5848c2ecf20Sopenharmony_ci	regmap_write(data->regmap, JC42_REG_CONFIG, data->config);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	/* Restore cached register values to hardware */
5878c2ecf20Sopenharmony_ci	return regcache_sync(data->regmap);
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_cistatic const struct dev_pm_ops jc42_dev_pm_ops = {
5918c2ecf20Sopenharmony_ci	.suspend = jc42_suspend,
5928c2ecf20Sopenharmony_ci	.resume = jc42_resume,
5938c2ecf20Sopenharmony_ci};
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
5968c2ecf20Sopenharmony_ci#else
5978c2ecf20Sopenharmony_ci#define JC42_DEV_PM_OPS NULL
5988c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic const struct i2c_device_id jc42_id[] = {
6018c2ecf20Sopenharmony_ci	{ "jc42", 0 },
6028c2ecf20Sopenharmony_ci	{ }
6038c2ecf20Sopenharmony_ci};
6048c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, jc42_id);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
6078c2ecf20Sopenharmony_cistatic const struct of_device_id jc42_of_ids[] = {
6088c2ecf20Sopenharmony_ci	{ .compatible = "jedec,jc-42.4-temp", },
6098c2ecf20Sopenharmony_ci	{ }
6108c2ecf20Sopenharmony_ci};
6118c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, jc42_of_ids);
6128c2ecf20Sopenharmony_ci#endif
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic struct i2c_driver jc42_driver = {
6158c2ecf20Sopenharmony_ci	.class		= I2C_CLASS_SPD | I2C_CLASS_HWMON,
6168c2ecf20Sopenharmony_ci	.driver = {
6178c2ecf20Sopenharmony_ci		.name	= "jc42",
6188c2ecf20Sopenharmony_ci		.pm = JC42_DEV_PM_OPS,
6198c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(jc42_of_ids),
6208c2ecf20Sopenharmony_ci	},
6218c2ecf20Sopenharmony_ci	.probe_new	= jc42_probe,
6228c2ecf20Sopenharmony_ci	.remove		= jc42_remove,
6238c2ecf20Sopenharmony_ci	.id_table	= jc42_id,
6248c2ecf20Sopenharmony_ci	.detect		= jc42_detect,
6258c2ecf20Sopenharmony_ci	.address_list	= normal_i2c,
6268c2ecf20Sopenharmony_ci};
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cimodule_i2c_driver(jc42_driver);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
6318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("JC42 driver");
6328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
633