1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
5 * This driver handles the ADT7410 and compatible digital temperature sensors.
6 * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
7 * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
8 * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.com>
11 #include <linux/device.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/jiffies.h>
16 #include <linux/hwmon.h>
17 #include <linux/err.h>
18 #include <linux/mutex.h>
19 #include <linux/delay.h>
20 #include <linux/interrupt.h>
21 #include <linux/regmap.h>
28 #define ADT7X10_STAT_T_LOW (1 << 4)
29 #define ADT7X10_STAT_T_HIGH (1 << 5)
30 #define ADT7X10_STAT_T_CRIT (1 << 6)
31 #define ADT7X10_STAT_NOT_RDY (1 << 7)
36 #define ADT7X10_FAULT_QUEUE_MASK (1 << 0 | 1 << 1)
37 #define ADT7X10_CT_POLARITY (1 << 2)
38 #define ADT7X10_INT_POLARITY (1 << 3)
39 #define ADT7X10_EVENT_MODE (1 << 4)
40 #define ADT7X10_MODE_MASK (1 << 5 | 1 << 6)
41 #define ADT7X10_FULL (0 << 5 | 0 << 6)
42 #define ADT7X10_PD (1 << 5 | 1 << 6)
43 #define ADT7X10_RESOLUTION (1 << 7)
48 #define ADT7X10_T13_VALUE_MASK 0xFFF8
49 #define ADT7X10_T_HYST_MASK 0xF
51 /* straight from the datasheet */
52 #define ADT7X10_TEMP_MIN (-55000)
53 #define ADT7X10_TEMP_MAX 150000
55 /* Each client has this additional data */
57 struct regmap
*regmap
;
58 struct mutex update_lock
;
61 bool valid
; /* true if temperature valid */
65 adt7x10_temperature
= 0,
71 static const u8 ADT7X10_REG_TEMP
[] = {
72 [adt7x10_temperature
] = ADT7X10_TEMPERATURE
, /* input */
73 [adt7x10_t_alarm_high
] = ADT7X10_T_ALARM_HIGH
, /* high */
74 [adt7x10_t_alarm_low
] = ADT7X10_T_ALARM_LOW
, /* low */
75 [adt7x10_t_crit
] = ADT7X10_T_CRIT
, /* critical */
78 static irqreturn_t
adt7x10_irq_handler(int irq
, void *private)
80 struct device
*dev
= private;
81 struct adt7x10_data
*d
= dev_get_drvdata(dev
);
85 ret
= regmap_read(d
->regmap
, ADT7X10_STATUS
, &status
);
89 if (status
& ADT7X10_STAT_T_HIGH
)
90 hwmon_notify_event(dev
, hwmon_temp
, hwmon_temp_max_alarm
, 0);
91 if (status
& ADT7X10_STAT_T_LOW
)
92 hwmon_notify_event(dev
, hwmon_temp
, hwmon_temp_min_alarm
, 0);
93 if (status
& ADT7X10_STAT_T_CRIT
)
94 hwmon_notify_event(dev
, hwmon_temp
, hwmon_temp_crit_alarm
, 0);
99 static int adt7x10_temp_ready(struct regmap
*regmap
)
104 for (i
= 0; i
< 6; i
++) {
105 ret
= regmap_read(regmap
, ADT7X10_STATUS
, &status
);
108 if (!(status
& ADT7X10_STAT_NOT_RDY
))
115 static s16
ADT7X10_TEMP_TO_REG(long temp
)
117 return DIV_ROUND_CLOSEST(clamp_val(temp
, ADT7X10_TEMP_MIN
,
118 ADT7X10_TEMP_MAX
) * 128, 1000);
121 static int ADT7X10_REG_TO_TEMP(struct adt7x10_data
*data
, s16 reg
)
123 /* in 13 bit mode, bits 0-2 are status flags - mask them out */
124 if (!(data
->config
& ADT7X10_RESOLUTION
))
125 reg
&= ADT7X10_T13_VALUE_MASK
;
127 * temperature is stored in twos complement format, in steps of
130 return DIV_ROUND_CLOSEST(reg
* 1000, 128);
133 /*-----------------------------------------------------------------------*/
135 static int adt7x10_temp_read(struct adt7x10_data
*data
, int index
, long *val
)
140 mutex_lock(&data
->update_lock
);
141 if (index
== adt7x10_temperature
&& !data
->valid
) {
142 /* wait for valid temperature */
143 ret
= adt7x10_temp_ready(data
->regmap
);
145 mutex_unlock(&data
->update_lock
);
150 mutex_unlock(&data
->update_lock
);
152 ret
= regmap_read(data
->regmap
, ADT7X10_REG_TEMP
[index
], ®val
);
156 *val
= ADT7X10_REG_TO_TEMP(data
, regval
);
160 static int adt7x10_temp_write(struct adt7x10_data
*data
, int index
, long temp
)
164 mutex_lock(&data
->update_lock
);
165 ret
= regmap_write(data
->regmap
, ADT7X10_REG_TEMP
[index
],
166 ADT7X10_TEMP_TO_REG(temp
));
167 mutex_unlock(&data
->update_lock
);
171 static int adt7x10_hyst_read(struct adt7x10_data
*data
, int index
, long *val
)
173 unsigned int regs
[2] = {ADT7X10_T_HYST
, ADT7X10_REG_TEMP
[index
]};
177 ret
= regmap_multi_reg_read(data
->regmap
, regs
, regdata
, 2);
181 hyst
= (regdata
[0] & ADT7X10_T_HYST_MASK
) * 1000;
184 * hysteresis is stored as a 4 bit offset in the device, convert it
185 * to an absolute value
187 /* min has positive offset, others have negative */
188 if (index
== adt7x10_t_alarm_low
)
191 *val
= ADT7X10_REG_TO_TEMP(data
, regdata
[1]) - hyst
;
195 static int adt7x10_hyst_write(struct adt7x10_data
*data
, long hyst
)
200 mutex_lock(&data
->update_lock
);
202 /* convert absolute hysteresis value to a 4 bit delta value */
203 ret
= regmap_read(data
->regmap
, ADT7X10_T_ALARM_HIGH
, ®val
);
207 limit
= ADT7X10_REG_TO_TEMP(data
, regval
);
209 hyst
= clamp_val(hyst
, ADT7X10_TEMP_MIN
, ADT7X10_TEMP_MAX
);
210 regval
= clamp_val(DIV_ROUND_CLOSEST(limit
- hyst
, 1000), 0,
211 ADT7X10_T_HYST_MASK
);
212 ret
= regmap_write(data
->regmap
, ADT7X10_T_HYST
, regval
);
214 mutex_unlock(&data
->update_lock
);
218 static int adt7x10_alarm_read(struct adt7x10_data
*data
, int index
, long *val
)
223 ret
= regmap_read(data
->regmap
, ADT7X10_STATUS
, &status
);
227 *val
= !!(status
& index
);
232 static umode_t
adt7x10_is_visible(const void *data
,
233 enum hwmon_sensor_types type
,
234 u32 attr
, int channel
)
239 case hwmon_temp_crit
:
240 case hwmon_temp_max_hyst
:
242 case hwmon_temp_input
:
243 case hwmon_temp_min_alarm
:
244 case hwmon_temp_max_alarm
:
245 case hwmon_temp_crit_alarm
:
246 case hwmon_temp_min_hyst
:
247 case hwmon_temp_crit_hyst
:
256 static int adt7x10_read(struct device
*dev
, enum hwmon_sensor_types type
,
257 u32 attr
, int channel
, long *val
)
259 struct adt7x10_data
*data
= dev_get_drvdata(dev
);
262 case hwmon_temp_input
:
263 return adt7x10_temp_read(data
, adt7x10_temperature
, val
);
265 return adt7x10_temp_read(data
, adt7x10_t_alarm_high
, val
);
267 return adt7x10_temp_read(data
, adt7x10_t_alarm_low
, val
);
268 case hwmon_temp_crit
:
269 return adt7x10_temp_read(data
, adt7x10_t_crit
, val
);
270 case hwmon_temp_max_hyst
:
271 return adt7x10_hyst_read(data
, adt7x10_t_alarm_high
, val
);
272 case hwmon_temp_min_hyst
:
273 return adt7x10_hyst_read(data
, adt7x10_t_alarm_low
, val
);
274 case hwmon_temp_crit_hyst
:
275 return adt7x10_hyst_read(data
, adt7x10_t_crit
, val
);
276 case hwmon_temp_min_alarm
:
277 return adt7x10_alarm_read(data
, ADT7X10_STAT_T_LOW
, val
);
278 case hwmon_temp_max_alarm
:
279 return adt7x10_alarm_read(data
, ADT7X10_STAT_T_HIGH
, val
);
280 case hwmon_temp_crit_alarm
:
281 return adt7x10_alarm_read(data
, ADT7X10_STAT_T_CRIT
, val
);
287 static int adt7x10_write(struct device
*dev
, enum hwmon_sensor_types type
,
288 u32 attr
, int channel
, long val
)
290 struct adt7x10_data
*data
= dev_get_drvdata(dev
);
294 return adt7x10_temp_write(data
, adt7x10_t_alarm_high
, val
);
296 return adt7x10_temp_write(data
, adt7x10_t_alarm_low
, val
);
297 case hwmon_temp_crit
:
298 return adt7x10_temp_write(data
, adt7x10_t_crit
, val
);
299 case hwmon_temp_max_hyst
:
300 return adt7x10_hyst_write(data
, val
);
306 static const struct hwmon_channel_info
* const adt7x10_info
[] = {
307 HWMON_CHANNEL_INFO(temp
, HWMON_T_INPUT
| HWMON_T_MAX
| HWMON_T_MIN
|
308 HWMON_T_CRIT
| HWMON_T_MAX_HYST
| HWMON_T_MIN_HYST
|
309 HWMON_T_CRIT_HYST
| HWMON_T_MIN_ALARM
|
310 HWMON_T_MAX_ALARM
| HWMON_T_CRIT_ALARM
),
314 static const struct hwmon_ops adt7x10_hwmon_ops
= {
315 .is_visible
= adt7x10_is_visible
,
316 .read
= adt7x10_read
,
317 .write
= adt7x10_write
,
320 static const struct hwmon_chip_info adt7x10_chip_info
= {
321 .ops
= &adt7x10_hwmon_ops
,
322 .info
= adt7x10_info
,
325 static void adt7x10_restore_config(void *private)
327 struct adt7x10_data
*data
= private;
329 regmap_write(data
->regmap
, ADT7X10_CONFIG
, data
->oldconfig
);
332 int adt7x10_probe(struct device
*dev
, const char *name
, int irq
,
333 struct regmap
*regmap
)
335 struct adt7x10_data
*data
;
340 data
= devm_kzalloc(dev
, sizeof(*data
), GFP_KERNEL
);
344 data
->regmap
= regmap
;
346 dev_set_drvdata(dev
, data
);
347 mutex_init(&data
->update_lock
);
349 /* configure as specified */
350 ret
= regmap_read(regmap
, ADT7X10_CONFIG
, &config
);
352 dev_dbg(dev
, "Can't read config? %d\n", ret
);
355 data
->oldconfig
= config
;
358 * Set to 16 bit resolution, continous conversion and comparator mode.
360 data
->config
= data
->oldconfig
;
361 data
->config
&= ~(ADT7X10_MODE_MASK
| ADT7X10_CT_POLARITY
|
362 ADT7X10_INT_POLARITY
);
363 data
->config
|= ADT7X10_FULL
| ADT7X10_RESOLUTION
| ADT7X10_EVENT_MODE
;
365 if (data
->config
!= data
->oldconfig
) {
366 ret
= regmap_write(regmap
, ADT7X10_CONFIG
, data
->config
);
369 ret
= devm_add_action_or_reset(dev
, adt7x10_restore_config
, data
);
373 dev_dbg(dev
, "Config %02x\n", data
->config
);
375 hdev
= devm_hwmon_device_register_with_info(dev
, name
, data
,
376 &adt7x10_chip_info
, NULL
);
378 return PTR_ERR(hdev
);
381 ret
= devm_request_threaded_irq(dev
, irq
, NULL
,
383 IRQF_TRIGGER_FALLING
|
385 dev_name(dev
), hdev
);
392 EXPORT_SYMBOL_GPL(adt7x10_probe
);
394 static int adt7x10_suspend(struct device
*dev
)
396 struct adt7x10_data
*data
= dev_get_drvdata(dev
);
398 return regmap_write(data
->regmap
, ADT7X10_CONFIG
,
399 data
->config
| ADT7X10_PD
);
402 static int adt7x10_resume(struct device
*dev
)
404 struct adt7x10_data
*data
= dev_get_drvdata(dev
);
406 return regmap_write(data
->regmap
, ADT7X10_CONFIG
, data
->config
);
409 EXPORT_SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops
, adt7x10_suspend
, adt7x10_resume
);
411 MODULE_AUTHOR("Hartmut Knaack");
412 MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
413 MODULE_LICENSE("GPL");