174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24453d736SGuenter Roeck /*
34453d736SGuenter Roeck * jc42.c - driver for Jedec JC42.4 compliant temperature sensors
44453d736SGuenter Roeck *
54453d736SGuenter Roeck * Copyright (c) 2010 Ericsson AB.
64453d736SGuenter Roeck *
74453d736SGuenter Roeck * Derived from lm77.c by Andras BALI <drewie@freemail.hu>.
84453d736SGuenter Roeck *
94453d736SGuenter Roeck * JC42.4 compliant temperature sensors are typically used on memory modules.
104453d736SGuenter Roeck */
114453d736SGuenter Roeck
1268615eb0SPeter Rosin #include <linux/bitops.h>
1378d448a3SMartin Blumenstingl #include <linux/bitfield.h>
144453d736SGuenter Roeck #include <linux/module.h>
154453d736SGuenter Roeck #include <linux/init.h>
164453d736SGuenter Roeck #include <linux/slab.h>
174453d736SGuenter Roeck #include <linux/jiffies.h>
184453d736SGuenter Roeck #include <linux/i2c.h>
194453d736SGuenter Roeck #include <linux/hwmon.h>
204453d736SGuenter Roeck #include <linux/err.h>
214453d736SGuenter Roeck #include <linux/mutex.h>
22803decceSGuenter Roeck #include <linux/of.h>
238f2fa472SMartin Blumenstingl #include <linux/regmap.h>
244453d736SGuenter Roeck
254453d736SGuenter Roeck /* Addresses to scan */
264453d736SGuenter Roeck static const unsigned short normal_i2c[] = {
274453d736SGuenter Roeck 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, I2C_CLIENT_END };
284453d736SGuenter Roeck
294453d736SGuenter Roeck /* JC42 registers. All registers are 16 bit. */
304453d736SGuenter Roeck #define JC42_REG_CAP 0x00
314453d736SGuenter Roeck #define JC42_REG_CONFIG 0x01
324453d736SGuenter Roeck #define JC42_REG_TEMP_UPPER 0x02
334453d736SGuenter Roeck #define JC42_REG_TEMP_LOWER 0x03
344453d736SGuenter Roeck #define JC42_REG_TEMP_CRITICAL 0x04
354453d736SGuenter Roeck #define JC42_REG_TEMP 0x05
364453d736SGuenter Roeck #define JC42_REG_MANID 0x06
374453d736SGuenter Roeck #define JC42_REG_DEVICEID 0x07
3868615eb0SPeter Rosin #define JC42_REG_SMBUS 0x22 /* NXP and Atmel, possibly others? */
394453d736SGuenter Roeck
404453d736SGuenter Roeck /* Status bits in temperature register */
4178d448a3SMartin Blumenstingl #define JC42_ALARM_CRIT BIT(15)
4278d448a3SMartin Blumenstingl #define JC42_ALARM_MAX BIT(14)
4378d448a3SMartin Blumenstingl #define JC42_ALARM_MIN BIT(13)
444453d736SGuenter Roeck
454453d736SGuenter Roeck /* Configuration register defines */
4678d448a3SMartin Blumenstingl #define JC42_CFG_CRIT_ONLY BIT(2)
4778d448a3SMartin Blumenstingl #define JC42_CFG_TCRIT_LOCK BIT(6)
4878d448a3SMartin Blumenstingl #define JC42_CFG_EVENT_LOCK BIT(7)
4978d448a3SMartin Blumenstingl #define JC42_CFG_SHUTDOWN BIT(8)
5078d448a3SMartin Blumenstingl #define JC42_CFG_HYST_MASK GENMASK(10, 9)
514453d736SGuenter Roeck
524453d736SGuenter Roeck /* Capabilities */
5378d448a3SMartin Blumenstingl #define JC42_CAP_RANGE BIT(2)
544453d736SGuenter Roeck
554453d736SGuenter Roeck /* Manufacturer IDs */
564453d736SGuenter Roeck #define ADT_MANID 0x11d4 /* Analog Devices */
571bd612a2SGuenter Roeck #define ATMEL_MANID 0x001f /* Atmel */
58175c490cSGuenter Roeck #define ATMEL_MANID2 0x1114 /* Atmel */
594453d736SGuenter Roeck #define MAX_MANID 0x004d /* Maxim */
604453d736SGuenter Roeck #define IDT_MANID 0x00b3 /* IDT */
614453d736SGuenter Roeck #define MCP_MANID 0x0054 /* Microchip */
624453d736SGuenter Roeck #define NXP_MANID 0x1131 /* NXP Semiconductors */
634453d736SGuenter Roeck #define ONS_MANID 0x1b09 /* ON Semiconductor */
644453d736SGuenter Roeck #define STM_MANID 0x104a /* ST Microelectronics */
65568003ceSGuenter Roeck #define GT_MANID 0x1c68 /* Giantec */
66568003ceSGuenter Roeck #define GT_MANID2 0x132d /* Giantec, 2nd mfg ID */
67c7250b5dSOleksandr Shamray #define SI_MANID 0x1c85 /* Seiko Instruments */
684453d736SGuenter Roeck
6968615eb0SPeter Rosin /* SMBUS register */
7068615eb0SPeter Rosin #define SMBUS_STMOUT BIT(7) /* SMBus time-out, active low */
7168615eb0SPeter Rosin
724453d736SGuenter Roeck /* Supported chips */
734453d736SGuenter Roeck
744453d736SGuenter Roeck /* Analog Devices */
754453d736SGuenter Roeck #define ADT7408_DEVID 0x0801
764453d736SGuenter Roeck #define ADT7408_DEVID_MASK 0xffff
774453d736SGuenter Roeck
781bd612a2SGuenter Roeck /* Atmel */
791bd612a2SGuenter Roeck #define AT30TS00_DEVID 0x8201
801bd612a2SGuenter Roeck #define AT30TS00_DEVID_MASK 0xffff
811bd612a2SGuenter Roeck
82175c490cSGuenter Roeck #define AT30TSE004_DEVID 0x2200
83175c490cSGuenter Roeck #define AT30TSE004_DEVID_MASK 0xffff
84175c490cSGuenter Roeck
85568003ceSGuenter Roeck /* Giantec */
86568003ceSGuenter Roeck #define GT30TS00_DEVID 0x2200
87568003ceSGuenter Roeck #define GT30TS00_DEVID_MASK 0xff00
88568003ceSGuenter Roeck
89568003ceSGuenter Roeck #define GT34TS02_DEVID 0x3300
90568003ceSGuenter Roeck #define GT34TS02_DEVID_MASK 0xff00
91568003ceSGuenter Roeck
924453d736SGuenter Roeck /* IDT */
930ea2f1dbSGuenter Roeck #define TSE2004_DEVID 0x2200
940ea2f1dbSGuenter Roeck #define TSE2004_DEVID_MASK 0xff00
954453d736SGuenter Roeck
960ea2f1dbSGuenter Roeck #define TS3000_DEVID 0x2900 /* Also matches TSE2002 */
970ea2f1dbSGuenter Roeck #define TS3000_DEVID_MASK 0xff00
980ea2f1dbSGuenter Roeck
990ea2f1dbSGuenter Roeck #define TS3001_DEVID 0x3000
1000ea2f1dbSGuenter Roeck #define TS3001_DEVID_MASK 0xff00
1011bd612a2SGuenter Roeck
1024453d736SGuenter Roeck /* Maxim */
1034453d736SGuenter Roeck #define MAX6604_DEVID 0x3e00
1044453d736SGuenter Roeck #define MAX6604_DEVID_MASK 0xffff
1054453d736SGuenter Roeck
1064453d736SGuenter Roeck /* Microchip */
1071bd612a2SGuenter Roeck #define MCP9804_DEVID 0x0200
1081bd612a2SGuenter Roeck #define MCP9804_DEVID_MASK 0xfffc
1091bd612a2SGuenter Roeck
110a31887dcSAlison Schofield #define MCP9808_DEVID 0x0400
111a31887dcSAlison Schofield #define MCP9808_DEVID_MASK 0xfffc
112a31887dcSAlison Schofield
1134453d736SGuenter Roeck #define MCP98242_DEVID 0x2000
1144453d736SGuenter Roeck #define MCP98242_DEVID_MASK 0xfffc
1154453d736SGuenter Roeck
1164453d736SGuenter Roeck #define MCP98243_DEVID 0x2100
1174453d736SGuenter Roeck #define MCP98243_DEVID_MASK 0xfffc
1184453d736SGuenter Roeck
119d4768280SGuenter Roeck #define MCP98244_DEVID 0x2200
120d4768280SGuenter Roeck #define MCP98244_DEVID_MASK 0xfffc
121d4768280SGuenter Roeck
1224453d736SGuenter Roeck #define MCP9843_DEVID 0x0000 /* Also matches mcp9805 */
1234453d736SGuenter Roeck #define MCP9843_DEVID_MASK 0xfffe
1244453d736SGuenter Roeck
1254453d736SGuenter Roeck /* NXP */
1264453d736SGuenter Roeck #define SE97_DEVID 0xa200
1274453d736SGuenter Roeck #define SE97_DEVID_MASK 0xfffc
1284453d736SGuenter Roeck
1294453d736SGuenter Roeck #define SE98_DEVID 0xa100
1304453d736SGuenter Roeck #define SE98_DEVID_MASK 0xfffc
1314453d736SGuenter Roeck
1324453d736SGuenter Roeck /* ON Semiconductor */
1334453d736SGuenter Roeck #define CAT6095_DEVID 0x0800 /* Also matches CAT34TS02 */
1344453d736SGuenter Roeck #define CAT6095_DEVID_MASK 0xffe0
1354453d736SGuenter Roeck
13699b981b2SGuenter Roeck #define CAT34TS02C_DEVID 0x0a00
13799b981b2SGuenter Roeck #define CAT34TS02C_DEVID_MASK 0xfff0
13899b981b2SGuenter Roeck
139568003ceSGuenter Roeck #define CAT34TS04_DEVID 0x2200
140568003ceSGuenter Roeck #define CAT34TS04_DEVID_MASK 0xfff0
141568003ceSGuenter Roeck
142bf4d8430SGuenter Roeck #define N34TS04_DEVID 0x2230
143bf4d8430SGuenter Roeck #define N34TS04_DEVID_MASK 0xfff0
144bf4d8430SGuenter Roeck
1454453d736SGuenter Roeck /* ST Microelectronics */
1464453d736SGuenter Roeck #define STTS424_DEVID 0x0101
1474453d736SGuenter Roeck #define STTS424_DEVID_MASK 0xffff
1484453d736SGuenter Roeck
1494453d736SGuenter Roeck #define STTS424E_DEVID 0x0000
1504453d736SGuenter Roeck #define STTS424E_DEVID_MASK 0xfffe
1514453d736SGuenter Roeck
1524de86126SJean Delvare #define STTS2002_DEVID 0x0300
1534de86126SJean Delvare #define STTS2002_DEVID_MASK 0xffff
1544de86126SJean Delvare
155175c490cSGuenter Roeck #define STTS2004_DEVID 0x2201
156175c490cSGuenter Roeck #define STTS2004_DEVID_MASK 0xffff
157175c490cSGuenter Roeck
1584de86126SJean Delvare #define STTS3000_DEVID 0x0200
1594de86126SJean Delvare #define STTS3000_DEVID_MASK 0xffff
1604de86126SJean Delvare
161c7250b5dSOleksandr Shamray /* Seiko Instruments */
162c7250b5dSOleksandr Shamray #define S34TS04A_DEVID 0x2221
163c7250b5dSOleksandr Shamray #define S34TS04A_DEVID_MASK 0xffff
164c7250b5dSOleksandr Shamray
1654453d736SGuenter Roeck static u16 jc42_hysteresis[] = { 0, 1500, 3000, 6000 };
1664453d736SGuenter Roeck
1674453d736SGuenter Roeck struct jc42_chips {
1684453d736SGuenter Roeck u16 manid;
1694453d736SGuenter Roeck u16 devid;
1704453d736SGuenter Roeck u16 devid_mask;
1714453d736SGuenter Roeck };
1724453d736SGuenter Roeck
1734453d736SGuenter Roeck static struct jc42_chips jc42_chips[] = {
1744453d736SGuenter Roeck { ADT_MANID, ADT7408_DEVID, ADT7408_DEVID_MASK },
1751bd612a2SGuenter Roeck { ATMEL_MANID, AT30TS00_DEVID, AT30TS00_DEVID_MASK },
176175c490cSGuenter Roeck { ATMEL_MANID2, AT30TSE004_DEVID, AT30TSE004_DEVID_MASK },
177568003ceSGuenter Roeck { GT_MANID, GT30TS00_DEVID, GT30TS00_DEVID_MASK },
178568003ceSGuenter Roeck { GT_MANID2, GT34TS02_DEVID, GT34TS02_DEVID_MASK },
1790ea2f1dbSGuenter Roeck { IDT_MANID, TSE2004_DEVID, TSE2004_DEVID_MASK },
1800ea2f1dbSGuenter Roeck { IDT_MANID, TS3000_DEVID, TS3000_DEVID_MASK },
1810ea2f1dbSGuenter Roeck { IDT_MANID, TS3001_DEVID, TS3001_DEVID_MASK },
1824453d736SGuenter Roeck { MAX_MANID, MAX6604_DEVID, MAX6604_DEVID_MASK },
1831bd612a2SGuenter Roeck { MCP_MANID, MCP9804_DEVID, MCP9804_DEVID_MASK },
184a31887dcSAlison Schofield { MCP_MANID, MCP9808_DEVID, MCP9808_DEVID_MASK },
1854453d736SGuenter Roeck { MCP_MANID, MCP98242_DEVID, MCP98242_DEVID_MASK },
1864453d736SGuenter Roeck { MCP_MANID, MCP98243_DEVID, MCP98243_DEVID_MASK },
187d4768280SGuenter Roeck { MCP_MANID, MCP98244_DEVID, MCP98244_DEVID_MASK },
1884453d736SGuenter Roeck { MCP_MANID, MCP9843_DEVID, MCP9843_DEVID_MASK },
1894453d736SGuenter Roeck { NXP_MANID, SE97_DEVID, SE97_DEVID_MASK },
1904453d736SGuenter Roeck { ONS_MANID, CAT6095_DEVID, CAT6095_DEVID_MASK },
19199b981b2SGuenter Roeck { ONS_MANID, CAT34TS02C_DEVID, CAT34TS02C_DEVID_MASK },
192568003ceSGuenter Roeck { ONS_MANID, CAT34TS04_DEVID, CAT34TS04_DEVID_MASK },
193bf4d8430SGuenter Roeck { ONS_MANID, N34TS04_DEVID, N34TS04_DEVID_MASK },
1944453d736SGuenter Roeck { NXP_MANID, SE98_DEVID, SE98_DEVID_MASK },
195c7250b5dSOleksandr Shamray { SI_MANID, S34TS04A_DEVID, S34TS04A_DEVID_MASK },
1964453d736SGuenter Roeck { STM_MANID, STTS424_DEVID, STTS424_DEVID_MASK },
1974453d736SGuenter Roeck { STM_MANID, STTS424E_DEVID, STTS424E_DEVID_MASK },
1984de86126SJean Delvare { STM_MANID, STTS2002_DEVID, STTS2002_DEVID_MASK },
199175c490cSGuenter Roeck { STM_MANID, STTS2004_DEVID, STTS2004_DEVID_MASK },
2004de86126SJean Delvare { STM_MANID, STTS3000_DEVID, STTS3000_DEVID_MASK },
2014453d736SGuenter Roeck };
2024453d736SGuenter Roeck
2034453d736SGuenter Roeck /* Each client has this additional data */
2044453d736SGuenter Roeck struct jc42_data {
2054453d736SGuenter Roeck struct mutex update_lock; /* protect register access */
2068f2fa472SMartin Blumenstingl struct regmap *regmap;
2074453d736SGuenter Roeck bool extended; /* true if extended range supported */
2084453d736SGuenter Roeck bool valid;
2094453d736SGuenter Roeck u16 orig_config; /* original configuration */
2104453d736SGuenter Roeck u16 config; /* current configuration */
2114453d736SGuenter Roeck };
2124453d736SGuenter Roeck
2134453d736SGuenter Roeck #define JC42_TEMP_MIN_EXTENDED (-40000)
2144453d736SGuenter Roeck #define JC42_TEMP_MIN 0
2154453d736SGuenter Roeck #define JC42_TEMP_MAX 125000
2164453d736SGuenter Roeck
jc42_temp_to_reg(long temp,bool extended)2173a05633bSGuenter Roeck static u16 jc42_temp_to_reg(long temp, bool extended)
2184453d736SGuenter Roeck {
2192a844c14SGuenter Roeck int ntemp = clamp_val(temp,
2204453d736SGuenter Roeck extended ? JC42_TEMP_MIN_EXTENDED :
2214453d736SGuenter Roeck JC42_TEMP_MIN, JC42_TEMP_MAX);
2224453d736SGuenter Roeck
2234453d736SGuenter Roeck /* convert from 0.001 to 0.0625 resolution */
2244453d736SGuenter Roeck return (ntemp * 2 / 125) & 0x1fff;
2254453d736SGuenter Roeck }
2264453d736SGuenter Roeck
jc42_temp_from_reg(s16 reg)2274453d736SGuenter Roeck static int jc42_temp_from_reg(s16 reg)
2284453d736SGuenter Roeck {
229bca6a1adSGuenter Roeck reg = sign_extend32(reg, 12);
2304453d736SGuenter Roeck
2314453d736SGuenter Roeck /* convert from 0.0625 to 0.001 resolution */
2324453d736SGuenter Roeck return reg * 125 / 2;
2334453d736SGuenter Roeck }
2344453d736SGuenter Roeck
jc42_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)235fcc448cfSGuenter Roeck static int jc42_read(struct device *dev, enum hwmon_sensor_types type,
236fcc448cfSGuenter Roeck u32 attr, int channel, long *val)
23710192bc6SGuenter Roeck {
2388f2fa472SMartin Blumenstingl struct jc42_data *data = dev_get_drvdata(dev);
2398f2fa472SMartin Blumenstingl unsigned int regval;
2408f2fa472SMartin Blumenstingl int ret, temp, hyst;
2414453d736SGuenter Roeck
2428f2fa472SMartin Blumenstingl mutex_lock(&data->update_lock);
2434453d736SGuenter Roeck
244fcc448cfSGuenter Roeck switch (attr) {
245fcc448cfSGuenter Roeck case hwmon_temp_input:
2468f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val);
2478f2fa472SMartin Blumenstingl if (ret)
2488f2fa472SMartin Blumenstingl break;
2498f2fa472SMartin Blumenstingl
2508f2fa472SMartin Blumenstingl *val = jc42_temp_from_reg(regval);
2518f2fa472SMartin Blumenstingl break;
252fcc448cfSGuenter Roeck case hwmon_temp_min:
2538f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_LOWER, ®val);
2548f2fa472SMartin Blumenstingl if (ret)
2558f2fa472SMartin Blumenstingl break;
2568f2fa472SMartin Blumenstingl
2578f2fa472SMartin Blumenstingl *val = jc42_temp_from_reg(regval);
2588f2fa472SMartin Blumenstingl break;
259fcc448cfSGuenter Roeck case hwmon_temp_max:
2608f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val);
2618f2fa472SMartin Blumenstingl if (ret)
2628f2fa472SMartin Blumenstingl break;
2638f2fa472SMartin Blumenstingl
2648f2fa472SMartin Blumenstingl *val = jc42_temp_from_reg(regval);
2658f2fa472SMartin Blumenstingl break;
266fcc448cfSGuenter Roeck case hwmon_temp_crit:
2678f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
2688f2fa472SMartin Blumenstingl ®val);
2698f2fa472SMartin Blumenstingl if (ret)
2708f2fa472SMartin Blumenstingl break;
2718f2fa472SMartin Blumenstingl
2728f2fa472SMartin Blumenstingl *val = jc42_temp_from_reg(regval);
2738f2fa472SMartin Blumenstingl break;
274fcc448cfSGuenter Roeck case hwmon_temp_max_hyst:
2758f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_UPPER, ®val);
2768f2fa472SMartin Blumenstingl if (ret)
2778f2fa472SMartin Blumenstingl break;
2788f2fa472SMartin Blumenstingl
2798f2fa472SMartin Blumenstingl temp = jc42_temp_from_reg(regval);
28078d448a3SMartin Blumenstingl hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK,
28178d448a3SMartin Blumenstingl data->config)];
282fcc448cfSGuenter Roeck *val = temp - hyst;
2838f2fa472SMartin Blumenstingl break;
284fcc448cfSGuenter Roeck case hwmon_temp_crit_hyst:
2858f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
2868f2fa472SMartin Blumenstingl ®val);
2878f2fa472SMartin Blumenstingl if (ret)
2888f2fa472SMartin Blumenstingl break;
2898f2fa472SMartin Blumenstingl
2908f2fa472SMartin Blumenstingl temp = jc42_temp_from_reg(regval);
29178d448a3SMartin Blumenstingl hyst = jc42_hysteresis[FIELD_GET(JC42_CFG_HYST_MASK,
29278d448a3SMartin Blumenstingl data->config)];
293fcc448cfSGuenter Roeck *val = temp - hyst;
2948f2fa472SMartin Blumenstingl break;
295fcc448cfSGuenter Roeck case hwmon_temp_min_alarm:
2968f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val);
2978f2fa472SMartin Blumenstingl if (ret)
2988f2fa472SMartin Blumenstingl break;
2998f2fa472SMartin Blumenstingl
30078d448a3SMartin Blumenstingl *val = FIELD_GET(JC42_ALARM_MIN, regval);
3018f2fa472SMartin Blumenstingl break;
302fcc448cfSGuenter Roeck case hwmon_temp_max_alarm:
3038f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val);
3048f2fa472SMartin Blumenstingl if (ret)
3058f2fa472SMartin Blumenstingl break;
3068f2fa472SMartin Blumenstingl
30778d448a3SMartin Blumenstingl *val = FIELD_GET(JC42_ALARM_MAX, regval);
3088f2fa472SMartin Blumenstingl break;
309fcc448cfSGuenter Roeck case hwmon_temp_crit_alarm:
3108f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP, ®val);
3118f2fa472SMartin Blumenstingl if (ret)
3128f2fa472SMartin Blumenstingl break;
3138f2fa472SMartin Blumenstingl
31478d448a3SMartin Blumenstingl *val = FIELD_GET(JC42_ALARM_CRIT, regval);
3158f2fa472SMartin Blumenstingl break;
316fcc448cfSGuenter Roeck default:
3178f2fa472SMartin Blumenstingl ret = -EOPNOTSUPP;
3188f2fa472SMartin Blumenstingl break;
319fcc448cfSGuenter Roeck }
3208f2fa472SMartin Blumenstingl
3218f2fa472SMartin Blumenstingl mutex_unlock(&data->update_lock);
3228f2fa472SMartin Blumenstingl
3238f2fa472SMartin Blumenstingl return ret;
3244453d736SGuenter Roeck }
3254453d736SGuenter Roeck
jc42_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)326fcc448cfSGuenter Roeck static int jc42_write(struct device *dev, enum hwmon_sensor_types type,
327fcc448cfSGuenter Roeck u32 attr, int channel, long val)
3284453d736SGuenter Roeck {
32910192bc6SGuenter Roeck struct jc42_data *data = dev_get_drvdata(dev);
3308f2fa472SMartin Blumenstingl unsigned int regval;
331fcc448cfSGuenter Roeck int diff, hyst;
332fcc448cfSGuenter Roeck int ret;
3334453d736SGuenter Roeck
33410192bc6SGuenter Roeck mutex_lock(&data->update_lock);
3354453d736SGuenter Roeck
336fcc448cfSGuenter Roeck switch (attr) {
337fcc448cfSGuenter Roeck case hwmon_temp_min:
3388f2fa472SMartin Blumenstingl ret = regmap_write(data->regmap, JC42_REG_TEMP_LOWER,
3398f2fa472SMartin Blumenstingl jc42_temp_to_reg(val, data->extended));
340fcc448cfSGuenter Roeck break;
341fcc448cfSGuenter Roeck case hwmon_temp_max:
3428f2fa472SMartin Blumenstingl ret = regmap_write(data->regmap, JC42_REG_TEMP_UPPER,
3438f2fa472SMartin Blumenstingl jc42_temp_to_reg(val, data->extended));
344fcc448cfSGuenter Roeck break;
345fcc448cfSGuenter Roeck case hwmon_temp_crit:
3468f2fa472SMartin Blumenstingl ret = regmap_write(data->regmap, JC42_REG_TEMP_CRITICAL,
3478f2fa472SMartin Blumenstingl jc42_temp_to_reg(val, data->extended));
348fcc448cfSGuenter Roeck break;
349fcc448cfSGuenter Roeck case hwmon_temp_crit_hyst:
3508f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_TEMP_CRITICAL,
3518f2fa472SMartin Blumenstingl ®val);
3528f2fa472SMartin Blumenstingl if (ret)
353b744db17SYang Yingliang break;
3548f2fa472SMartin Blumenstingl
3555d577dbaSGuenter Roeck /*
3565d577dbaSGuenter Roeck * JC42.4 compliant chips only support four hysteresis values.
3575d577dbaSGuenter Roeck * Pick best choice and go from there.
3585d577dbaSGuenter Roeck */
359fcc448cfSGuenter Roeck val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED
360fcc448cfSGuenter Roeck : JC42_TEMP_MIN) - 6000,
361fcc448cfSGuenter Roeck JC42_TEMP_MAX);
3628f2fa472SMartin Blumenstingl diff = jc42_temp_from_reg(regval) - val;
3634453d736SGuenter Roeck hyst = 0;
3644453d736SGuenter Roeck if (diff > 0) {
3654453d736SGuenter Roeck if (diff < 2250)
3664453d736SGuenter Roeck hyst = 1; /* 1.5 degrees C */
3674453d736SGuenter Roeck else if (diff < 4500)
3684453d736SGuenter Roeck hyst = 2; /* 3.0 degrees C */
3694453d736SGuenter Roeck else
3704453d736SGuenter Roeck hyst = 3; /* 6.0 degrees C */
3714453d736SGuenter Roeck }
372fcc448cfSGuenter Roeck data->config = (data->config & ~JC42_CFG_HYST_MASK) |
37378d448a3SMartin Blumenstingl FIELD_PREP(JC42_CFG_HYST_MASK, hyst);
3748f2fa472SMartin Blumenstingl ret = regmap_write(data->regmap, JC42_REG_CONFIG,
37590f4102cSJean Delvare data->config);
376fcc448cfSGuenter Roeck break;
377fcc448cfSGuenter Roeck default:
378fcc448cfSGuenter Roeck ret = -EOPNOTSUPP;
379fcc448cfSGuenter Roeck break;
380fcc448cfSGuenter Roeck }
381fcc448cfSGuenter Roeck
3824453d736SGuenter Roeck mutex_unlock(&data->update_lock);
383fcc448cfSGuenter Roeck
3844453d736SGuenter Roeck return ret;
3854453d736SGuenter Roeck }
3864453d736SGuenter Roeck
jc42_is_visible(const void * _data,enum hwmon_sensor_types type,u32 attr,int channel)387fcc448cfSGuenter Roeck static umode_t jc42_is_visible(const void *_data, enum hwmon_sensor_types type,
388fcc448cfSGuenter Roeck u32 attr, int channel)
3894453d736SGuenter Roeck {
390fcc448cfSGuenter Roeck const struct jc42_data *data = _data;
3912c6315daSClemens Ladisch unsigned int config = data->config;
3924820d511SGuenter Roeck umode_t mode = 0444;
3932c6315daSClemens Ladisch
394fcc448cfSGuenter Roeck switch (attr) {
395fcc448cfSGuenter Roeck case hwmon_temp_min:
396fcc448cfSGuenter Roeck case hwmon_temp_max:
397fcc448cfSGuenter Roeck if (!(config & JC42_CFG_EVENT_LOCK))
3984820d511SGuenter Roeck mode |= 0200;
399fcc448cfSGuenter Roeck break;
400fcc448cfSGuenter Roeck case hwmon_temp_crit:
401fcc448cfSGuenter Roeck if (!(config & JC42_CFG_TCRIT_LOCK))
4024820d511SGuenter Roeck mode |= 0200;
403fcc448cfSGuenter Roeck break;
404fcc448cfSGuenter Roeck case hwmon_temp_crit_hyst:
405fcc448cfSGuenter Roeck if (!(config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK)))
4064820d511SGuenter Roeck mode |= 0200;
407fcc448cfSGuenter Roeck break;
408fcc448cfSGuenter Roeck case hwmon_temp_input:
409fcc448cfSGuenter Roeck case hwmon_temp_max_hyst:
410fcc448cfSGuenter Roeck case hwmon_temp_min_alarm:
411fcc448cfSGuenter Roeck case hwmon_temp_max_alarm:
412fcc448cfSGuenter Roeck case hwmon_temp_crit_alarm:
413fcc448cfSGuenter Roeck break;
414fcc448cfSGuenter Roeck default:
415fcc448cfSGuenter Roeck mode = 0;
416fcc448cfSGuenter Roeck break;
4172c6315daSClemens Ladisch }
418fcc448cfSGuenter Roeck return mode;
419fcc448cfSGuenter Roeck }
4204453d736SGuenter Roeck
4214453d736SGuenter Roeck /* Return 0 if detection is successful, -ENODEV otherwise */
jc42_detect(struct i2c_client * client,struct i2c_board_info * info)422f15df57dSGuenter Roeck static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info)
4234453d736SGuenter Roeck {
424f15df57dSGuenter Roeck struct i2c_adapter *adapter = client->adapter;
4254453d736SGuenter Roeck int i, config, cap, manid, devid;
4264453d736SGuenter Roeck
4274453d736SGuenter Roeck if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
4284453d736SGuenter Roeck I2C_FUNC_SMBUS_WORD_DATA))
4294453d736SGuenter Roeck return -ENODEV;
4304453d736SGuenter Roeck
431f15df57dSGuenter Roeck cap = i2c_smbus_read_word_swapped(client, JC42_REG_CAP);
432f15df57dSGuenter Roeck config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
433f15df57dSGuenter Roeck manid = i2c_smbus_read_word_swapped(client, JC42_REG_MANID);
434f15df57dSGuenter Roeck devid = i2c_smbus_read_word_swapped(client, JC42_REG_DEVICEID);
4354453d736SGuenter Roeck
4364453d736SGuenter Roeck if (cap < 0 || config < 0 || manid < 0 || devid < 0)
4374453d736SGuenter Roeck return -ENODEV;
4384453d736SGuenter Roeck
4394453d736SGuenter Roeck if ((cap & 0xff00) || (config & 0xf800))
4404453d736SGuenter Roeck return -ENODEV;
4414453d736SGuenter Roeck
4424453d736SGuenter Roeck for (i = 0; i < ARRAY_SIZE(jc42_chips); i++) {
4434453d736SGuenter Roeck struct jc42_chips *chip = &jc42_chips[i];
4444453d736SGuenter Roeck if (manid == chip->manid &&
4454453d736SGuenter Roeck (devid & chip->devid_mask) == chip->devid) {
446f2f394dbSWolfram Sang strscpy(info->type, "jc42", I2C_NAME_SIZE);
4474453d736SGuenter Roeck return 0;
4484453d736SGuenter Roeck }
4494453d736SGuenter Roeck }
4504453d736SGuenter Roeck return -ENODEV;
4514453d736SGuenter Roeck }
4524453d736SGuenter Roeck
453*b3dc5eeeSKrzysztof Kozlowski static const struct hwmon_channel_info * const jc42_info[] = {
454032c1623SEduardo Valentin HWMON_CHANNEL_INFO(chip,
455032c1623SEduardo Valentin HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
4561eade10fSGuenter Roeck HWMON_CHANNEL_INFO(temp,
4571eade10fSGuenter Roeck HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
4581eade10fSGuenter Roeck HWMON_T_CRIT | HWMON_T_MAX_HYST |
4591eade10fSGuenter Roeck HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
4601eade10fSGuenter Roeck HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM),
461fcc448cfSGuenter Roeck NULL
462fcc448cfSGuenter Roeck };
463fcc448cfSGuenter Roeck
464fcc448cfSGuenter Roeck static const struct hwmon_ops jc42_hwmon_ops = {
465fcc448cfSGuenter Roeck .is_visible = jc42_is_visible,
466fcc448cfSGuenter Roeck .read = jc42_read,
467fcc448cfSGuenter Roeck .write = jc42_write,
468fcc448cfSGuenter Roeck };
469fcc448cfSGuenter Roeck
470fcc448cfSGuenter Roeck static const struct hwmon_chip_info jc42_chip_info = {
471fcc448cfSGuenter Roeck .ops = &jc42_hwmon_ops,
472fcc448cfSGuenter Roeck .info = jc42_info,
473fcc448cfSGuenter Roeck };
474fcc448cfSGuenter Roeck
jc42_readable_reg(struct device * dev,unsigned int reg)4758f2fa472SMartin Blumenstingl static bool jc42_readable_reg(struct device *dev, unsigned int reg)
4768f2fa472SMartin Blumenstingl {
4778f2fa472SMartin Blumenstingl return (reg >= JC42_REG_CAP && reg <= JC42_REG_DEVICEID) ||
4788f2fa472SMartin Blumenstingl reg == JC42_REG_SMBUS;
4798f2fa472SMartin Blumenstingl }
4808f2fa472SMartin Blumenstingl
jc42_writable_reg(struct device * dev,unsigned int reg)4818f2fa472SMartin Blumenstingl static bool jc42_writable_reg(struct device *dev, unsigned int reg)
4828f2fa472SMartin Blumenstingl {
4838f2fa472SMartin Blumenstingl return (reg >= JC42_REG_CONFIG && reg <= JC42_REG_TEMP_CRITICAL) ||
4848f2fa472SMartin Blumenstingl reg == JC42_REG_SMBUS;
4858f2fa472SMartin Blumenstingl }
4868f2fa472SMartin Blumenstingl
jc42_volatile_reg(struct device * dev,unsigned int reg)4878f2fa472SMartin Blumenstingl static bool jc42_volatile_reg(struct device *dev, unsigned int reg)
4888f2fa472SMartin Blumenstingl {
4898f2fa472SMartin Blumenstingl return reg == JC42_REG_CONFIG || reg == JC42_REG_TEMP;
4908f2fa472SMartin Blumenstingl }
4918f2fa472SMartin Blumenstingl
4928f2fa472SMartin Blumenstingl static const struct regmap_config jc42_regmap_config = {
4938f2fa472SMartin Blumenstingl .reg_bits = 8,
4948f2fa472SMartin Blumenstingl .val_bits = 16,
4958f2fa472SMartin Blumenstingl .val_format_endian = REGMAP_ENDIAN_BIG,
4968f2fa472SMartin Blumenstingl .max_register = JC42_REG_SMBUS,
4978f2fa472SMartin Blumenstingl .writeable_reg = jc42_writable_reg,
4988f2fa472SMartin Blumenstingl .readable_reg = jc42_readable_reg,
4998f2fa472SMartin Blumenstingl .volatile_reg = jc42_volatile_reg,
5008f2fa472SMartin Blumenstingl .cache_type = REGCACHE_RBTREE,
5018f2fa472SMartin Blumenstingl };
5028f2fa472SMartin Blumenstingl
jc42_probe(struct i2c_client * client)50367487038SStephen Kitt static int jc42_probe(struct i2c_client *client)
5044453d736SGuenter Roeck {
505f15df57dSGuenter Roeck struct device *dev = &client->dev;
50662f9a57cSGuenter Roeck struct device *hwmon_dev;
5078f2fa472SMartin Blumenstingl unsigned int config, cap;
50862f9a57cSGuenter Roeck struct jc42_data *data;
5098f2fa472SMartin Blumenstingl int ret;
5104453d736SGuenter Roeck
511f15df57dSGuenter Roeck data = devm_kzalloc(dev, sizeof(struct jc42_data), GFP_KERNEL);
512f15df57dSGuenter Roeck if (!data)
513f15df57dSGuenter Roeck return -ENOMEM;
5144453d736SGuenter Roeck
5158f2fa472SMartin Blumenstingl data->regmap = devm_regmap_init_i2c(client, &jc42_regmap_config);
5168f2fa472SMartin Blumenstingl if (IS_ERR(data->regmap))
5178f2fa472SMartin Blumenstingl return PTR_ERR(data->regmap);
5188f2fa472SMartin Blumenstingl
519f15df57dSGuenter Roeck i2c_set_clientdata(client, data);
5204453d736SGuenter Roeck mutex_init(&data->update_lock);
5214453d736SGuenter Roeck
5228f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_CAP, &cap);
5238f2fa472SMartin Blumenstingl if (ret)
5248f2fa472SMartin Blumenstingl return ret;
525f15df57dSGuenter Roeck
5264453d736SGuenter Roeck data->extended = !!(cap & JC42_CAP_RANGE);
5274453d736SGuenter Roeck
52868615eb0SPeter Rosin if (device_property_read_bool(dev, "smbus-timeout-disable")) {
52968615eb0SPeter Rosin /*
53068615eb0SPeter Rosin * Not all chips support this register, but from a
53168615eb0SPeter Rosin * quick read of various datasheets no chip appears
53268615eb0SPeter Rosin * incompatible with the below attempt to disable
53368615eb0SPeter Rosin * the timeout. And the whole thing is opt-in...
53468615eb0SPeter Rosin */
5358f2fa472SMartin Blumenstingl ret = regmap_set_bits(data->regmap, JC42_REG_SMBUS,
5368f2fa472SMartin Blumenstingl SMBUS_STMOUT);
5378f2fa472SMartin Blumenstingl if (ret)
5388f2fa472SMartin Blumenstingl return ret;
53968615eb0SPeter Rosin }
54068615eb0SPeter Rosin
5418f2fa472SMartin Blumenstingl ret = regmap_read(data->regmap, JC42_REG_CONFIG, &config);
5428f2fa472SMartin Blumenstingl if (ret)
5438f2fa472SMartin Blumenstingl return ret;
544f15df57dSGuenter Roeck
5454453d736SGuenter Roeck data->orig_config = config;
5464453d736SGuenter Roeck if (config & JC42_CFG_SHUTDOWN) {
5474453d736SGuenter Roeck config &= ~JC42_CFG_SHUTDOWN;
5488f2fa472SMartin Blumenstingl regmap_write(data->regmap, JC42_REG_CONFIG, config);
5494453d736SGuenter Roeck }
5504453d736SGuenter Roeck data->config = config;
5514453d736SGuenter Roeck
552c843b382SSascha Hauer hwmon_dev = devm_hwmon_device_register_with_info(dev, "jc42",
553fcc448cfSGuenter Roeck data, &jc42_chip_info,
554fcc448cfSGuenter Roeck NULL);
555650a2c02SFengguang Wu return PTR_ERR_OR_ZERO(hwmon_dev);
5564453d736SGuenter Roeck }
5574453d736SGuenter Roeck
jc42_remove(struct i2c_client * client)558ed5c2f5fSUwe Kleine-König static void jc42_remove(struct i2c_client *client)
5594453d736SGuenter Roeck {
5604453d736SGuenter Roeck struct jc42_data *data = i2c_get_clientdata(client);
5615953e276SJean Delvare
5625953e276SJean Delvare /* Restore original configuration except hysteresis */
5635953e276SJean Delvare if ((data->config & ~JC42_CFG_HYST_MASK) !=
5645953e276SJean Delvare (data->orig_config & ~JC42_CFG_HYST_MASK)) {
5655953e276SJean Delvare int config;
5665953e276SJean Delvare
5675953e276SJean Delvare config = (data->orig_config & ~JC42_CFG_HYST_MASK)
5685953e276SJean Delvare | (data->config & JC42_CFG_HYST_MASK);
5698f2fa472SMartin Blumenstingl regmap_write(data->regmap, JC42_REG_CONFIG, config);
5705953e276SJean Delvare }
5714453d736SGuenter Roeck }
5724453d736SGuenter Roeck
573d397276bSGuenter Roeck #ifdef CONFIG_PM
574d397276bSGuenter Roeck
jc42_suspend(struct device * dev)575d397276bSGuenter Roeck static int jc42_suspend(struct device *dev)
5764453d736SGuenter Roeck {
57762f9a57cSGuenter Roeck struct jc42_data *data = dev_get_drvdata(dev);
5784453d736SGuenter Roeck
579d397276bSGuenter Roeck data->config |= JC42_CFG_SHUTDOWN;
5808f2fa472SMartin Blumenstingl regmap_write(data->regmap, JC42_REG_CONFIG, data->config);
581084ed144SMartin Blumenstingl
582084ed144SMartin Blumenstingl regcache_cache_only(data->regmap, true);
583084ed144SMartin Blumenstingl regcache_mark_dirty(data->regmap);
584084ed144SMartin Blumenstingl
585d397276bSGuenter Roeck return 0;
586d397276bSGuenter Roeck }
5874453d736SGuenter Roeck
jc42_resume(struct device * dev)588d397276bSGuenter Roeck static int jc42_resume(struct device *dev)
589d397276bSGuenter Roeck {
590d397276bSGuenter Roeck struct jc42_data *data = dev_get_drvdata(dev);
5914453d736SGuenter Roeck
592084ed144SMartin Blumenstingl regcache_cache_only(data->regmap, false);
593084ed144SMartin Blumenstingl
594d397276bSGuenter Roeck data->config &= ~JC42_CFG_SHUTDOWN;
5958f2fa472SMartin Blumenstingl regmap_write(data->regmap, JC42_REG_CONFIG, data->config);
596084ed144SMartin Blumenstingl
597084ed144SMartin Blumenstingl /* Restore cached register values to hardware */
598084ed144SMartin Blumenstingl return regcache_sync(data->regmap);
5994453d736SGuenter Roeck }
6004453d736SGuenter Roeck
601d397276bSGuenter Roeck static const struct dev_pm_ops jc42_dev_pm_ops = {
602d397276bSGuenter Roeck .suspend = jc42_suspend,
603d397276bSGuenter Roeck .resume = jc42_resume,
604d397276bSGuenter Roeck };
6054453d736SGuenter Roeck
606d397276bSGuenter Roeck #define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
607d397276bSGuenter Roeck #else
608d397276bSGuenter Roeck #define JC42_DEV_PM_OPS NULL
609d397276bSGuenter Roeck #endif /* CONFIG_PM */
6104453d736SGuenter Roeck
611d397276bSGuenter Roeck static const struct i2c_device_id jc42_id[] = {
612d397276bSGuenter Roeck { "jc42", 0 },
613d397276bSGuenter Roeck { }
614d397276bSGuenter Roeck };
615d397276bSGuenter Roeck MODULE_DEVICE_TABLE(i2c, jc42_id);
616d397276bSGuenter Roeck
617803decceSGuenter Roeck #ifdef CONFIG_OF
618803decceSGuenter Roeck static const struct of_device_id jc42_of_ids[] = {
619803decceSGuenter Roeck { .compatible = "jedec,jc-42.4-temp", },
620803decceSGuenter Roeck { }
621803decceSGuenter Roeck };
622803decceSGuenter Roeck MODULE_DEVICE_TABLE(of, jc42_of_ids);
623803decceSGuenter Roeck #endif
624803decceSGuenter Roeck
625d397276bSGuenter Roeck static struct i2c_driver jc42_driver = {
626eacc48ceSAlison Schofield .class = I2C_CLASS_SPD | I2C_CLASS_HWMON,
627d397276bSGuenter Roeck .driver = {
628d397276bSGuenter Roeck .name = "jc42",
629d397276bSGuenter Roeck .pm = JC42_DEV_PM_OPS,
630803decceSGuenter Roeck .of_match_table = of_match_ptr(jc42_of_ids),
631d397276bSGuenter Roeck },
63267487038SStephen Kitt .probe = jc42_probe,
633d397276bSGuenter Roeck .remove = jc42_remove,
634d397276bSGuenter Roeck .id_table = jc42_id,
635d397276bSGuenter Roeck .detect = jc42_detect,
636d397276bSGuenter Roeck .address_list = normal_i2c,
637d397276bSGuenter Roeck };
6384453d736SGuenter Roeck
639f0967eeaSAxel Lin module_i2c_driver(jc42_driver);
6404453d736SGuenter Roeck
641bb9a80e5SGuenter Roeck MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
6424453d736SGuenter Roeck MODULE_DESCRIPTION("JC42 driver");
6434453d736SGuenter Roeck MODULE_LICENSE("GPL");
644