1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * adt7x10.c - Part of lm_sensors, Linux kernel modules for hardware
4 *	 monitoring
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>
9 */
10
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>
22
23#include "adt7x10.h"
24
25/*
26 * ADT7X10 status
27 */
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)
32
33/*
34 * ADT7X10 config
35 */
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)
44
45/*
46 * ADT7X10 masks
47 */
48#define ADT7X10_T13_VALUE_MASK		0xFFF8
49#define ADT7X10_T_HYST_MASK		0xF
50
51/* straight from the datasheet */
52#define ADT7X10_TEMP_MIN (-55000)
53#define ADT7X10_TEMP_MAX 150000
54
55/* Each client has this additional data */
56struct adt7x10_data {
57	struct regmap		*regmap;
58	struct mutex		update_lock;
59	u8			config;
60	u8			oldconfig;
61	bool			valid;		/* true if temperature valid */
62};
63
64enum {
65	adt7x10_temperature = 0,
66	adt7x10_t_alarm_high,
67	adt7x10_t_alarm_low,
68	adt7x10_t_crit,
69};
70
71static 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 */
76};
77
78static irqreturn_t adt7x10_irq_handler(int irq, void *private)
79{
80	struct device *dev = private;
81	struct adt7x10_data *d = dev_get_drvdata(dev);
82	unsigned int status;
83	int ret;
84
85	ret = regmap_read(d->regmap, ADT7X10_STATUS, &status);
86	if (ret < 0)
87		return IRQ_HANDLED;
88
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);
95
96	return IRQ_HANDLED;
97}
98
99static int adt7x10_temp_ready(struct regmap *regmap)
100{
101	unsigned int status;
102	int i, ret;
103
104	for (i = 0; i < 6; i++) {
105		ret = regmap_read(regmap, ADT7X10_STATUS, &status);
106		if (ret < 0)
107			return ret;
108		if (!(status & ADT7X10_STAT_NOT_RDY))
109			return 0;
110		msleep(60);
111	}
112	return -ETIMEDOUT;
113}
114
115static s16 ADT7X10_TEMP_TO_REG(long temp)
116{
117	return DIV_ROUND_CLOSEST(clamp_val(temp, ADT7X10_TEMP_MIN,
118					   ADT7X10_TEMP_MAX) * 128, 1000);
119}
120
121static int ADT7X10_REG_TO_TEMP(struct adt7x10_data *data, s16 reg)
122{
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;
126	/*
127	 * temperature is stored in twos complement format, in steps of
128	 * 1/128��C
129	 */
130	return DIV_ROUND_CLOSEST(reg * 1000, 128);
131}
132
133/*-----------------------------------------------------------------------*/
134
135static int adt7x10_temp_read(struct adt7x10_data *data, int index, long *val)
136{
137	unsigned int regval;
138	int ret;
139
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);
144		if (ret) {
145			mutex_unlock(&data->update_lock);
146			return ret;
147		}
148		data->valid = true;
149	}
150	mutex_unlock(&data->update_lock);
151
152	ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &regval);
153	if (ret)
154		return ret;
155
156	*val = ADT7X10_REG_TO_TEMP(data, regval);
157	return 0;
158}
159
160static int adt7x10_temp_write(struct adt7x10_data *data, int index, long temp)
161{
162	int ret;
163
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);
168	return ret;
169}
170
171static int adt7x10_hyst_read(struct adt7x10_data *data, int index, long *val)
172{
173	int hyst, temp, ret;
174
175	mutex_lock(&data->update_lock);
176	ret = regmap_read(data->regmap, ADT7X10_T_HYST, &hyst);
177	if (ret) {
178		mutex_unlock(&data->update_lock);
179		return ret;
180	}
181
182	ret = regmap_read(data->regmap, ADT7X10_REG_TEMP[index], &temp);
183	mutex_unlock(&data->update_lock);
184	if (ret)
185		return ret;
186
187	hyst = (hyst & ADT7X10_T_HYST_MASK) * 1000;
188
189	/*
190	 * hysteresis is stored as a 4 bit offset in the device, convert it
191	 * to an absolute value
192	 */
193	/* min has positive offset, others have negative */
194	if (index == adt7x10_t_alarm_low)
195		hyst = -hyst;
196
197	*val = ADT7X10_REG_TO_TEMP(data, temp) - hyst;
198	return 0;
199}
200
201static int adt7x10_hyst_write(struct adt7x10_data *data, long hyst)
202{
203	unsigned int regval;
204	int limit, ret;
205
206	mutex_lock(&data->update_lock);
207
208	/* convert absolute hysteresis value to a 4 bit delta value */
209	ret = regmap_read(data->regmap, ADT7X10_T_ALARM_HIGH, &regval);
210	if (ret < 0)
211		goto abort;
212
213	limit = ADT7X10_REG_TO_TEMP(data, regval);
214
215	hyst = clamp_val(hyst, ADT7X10_TEMP_MIN, ADT7X10_TEMP_MAX);
216	regval = clamp_val(DIV_ROUND_CLOSEST(limit - hyst, 1000), 0,
217			   ADT7X10_T_HYST_MASK);
218	ret = regmap_write(data->regmap, ADT7X10_T_HYST, regval);
219abort:
220	mutex_unlock(&data->update_lock);
221	return ret;
222}
223
224static int adt7x10_alarm_read(struct adt7x10_data *data, int index, long *val)
225{
226	unsigned int status;
227	int ret;
228
229	ret = regmap_read(data->regmap, ADT7X10_STATUS, &status);
230	if (ret < 0)
231		return ret;
232
233	*val = !!(status & index);
234
235	return 0;
236}
237
238static umode_t adt7x10_is_visible(const void *data,
239				  enum hwmon_sensor_types type,
240				  u32 attr, int channel)
241{
242	switch (attr) {
243	case hwmon_temp_max:
244	case hwmon_temp_min:
245	case hwmon_temp_crit:
246	case hwmon_temp_max_hyst:
247		return 0644;
248	case hwmon_temp_input:
249	case hwmon_temp_min_alarm:
250	case hwmon_temp_max_alarm:
251	case hwmon_temp_crit_alarm:
252	case hwmon_temp_min_hyst:
253	case hwmon_temp_crit_hyst:
254		return 0444;
255	default:
256		break;
257	}
258
259	return 0;
260}
261
262static int adt7x10_read(struct device *dev, enum hwmon_sensor_types type,
263			u32 attr, int channel, long *val)
264{
265	struct adt7x10_data *data = dev_get_drvdata(dev);
266
267	switch (attr) {
268	case hwmon_temp_input:
269		return adt7x10_temp_read(data, adt7x10_temperature, val);
270	case hwmon_temp_max:
271		return adt7x10_temp_read(data, adt7x10_t_alarm_high, val);
272	case hwmon_temp_min:
273		return adt7x10_temp_read(data, adt7x10_t_alarm_low, val);
274	case hwmon_temp_crit:
275		return adt7x10_temp_read(data, adt7x10_t_crit, val);
276	case hwmon_temp_max_hyst:
277		return adt7x10_hyst_read(data, adt7x10_t_alarm_high, val);
278	case hwmon_temp_min_hyst:
279		return adt7x10_hyst_read(data, adt7x10_t_alarm_low, val);
280	case hwmon_temp_crit_hyst:
281		return adt7x10_hyst_read(data, adt7x10_t_crit, val);
282	case hwmon_temp_min_alarm:
283		return adt7x10_alarm_read(data, ADT7X10_STAT_T_LOW, val);
284	case hwmon_temp_max_alarm:
285		return adt7x10_alarm_read(data, ADT7X10_STAT_T_HIGH, val);
286	case hwmon_temp_crit_alarm:
287		return adt7x10_alarm_read(data, ADT7X10_STAT_T_CRIT, val);
288	default:
289		return -EOPNOTSUPP;
290	}
291}
292
293static int adt7x10_write(struct device *dev, enum hwmon_sensor_types type,
294			 u32 attr, int channel, long val)
295{
296	struct adt7x10_data *data = dev_get_drvdata(dev);
297
298	switch (attr) {
299	case hwmon_temp_max:
300		return adt7x10_temp_write(data, adt7x10_t_alarm_high, val);
301	case hwmon_temp_min:
302		return adt7x10_temp_write(data, adt7x10_t_alarm_low, val);
303	case hwmon_temp_crit:
304		return adt7x10_temp_write(data, adt7x10_t_crit, val);
305	case hwmon_temp_max_hyst:
306		return adt7x10_hyst_write(data, val);
307	default:
308		return -EOPNOTSUPP;
309	}
310}
311
312static const struct hwmon_channel_info * const adt7x10_info[] = {
313	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN |
314			   HWMON_T_CRIT | HWMON_T_MAX_HYST | HWMON_T_MIN_HYST |
315			   HWMON_T_CRIT_HYST | HWMON_T_MIN_ALARM |
316			   HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM),
317	NULL,
318};
319
320static const struct hwmon_ops adt7x10_hwmon_ops = {
321	.is_visible = adt7x10_is_visible,
322	.read = adt7x10_read,
323	.write = adt7x10_write,
324};
325
326static const struct hwmon_chip_info adt7x10_chip_info = {
327	.ops = &adt7x10_hwmon_ops,
328	.info = adt7x10_info,
329};
330
331static void adt7x10_restore_config(void *private)
332{
333	struct adt7x10_data *data = private;
334
335	regmap_write(data->regmap, ADT7X10_CONFIG, data->oldconfig);
336}
337
338int adt7x10_probe(struct device *dev, const char *name, int irq,
339		  struct regmap *regmap)
340{
341	struct adt7x10_data *data;
342	unsigned int config;
343	struct device *hdev;
344	int ret;
345
346	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
347	if (!data)
348		return -ENOMEM;
349
350	data->regmap = regmap;
351
352	dev_set_drvdata(dev, data);
353	mutex_init(&data->update_lock);
354
355	/* configure as specified */
356	ret = regmap_read(regmap, ADT7X10_CONFIG, &config);
357	if (ret < 0) {
358		dev_dbg(dev, "Can't read config? %d\n", ret);
359		return ret;
360	}
361	data->oldconfig = config;
362
363	/*
364	 * Set to 16 bit resolution, continous conversion and comparator mode.
365	 */
366	data->config = data->oldconfig;
367	data->config &= ~(ADT7X10_MODE_MASK | ADT7X10_CT_POLARITY |
368			ADT7X10_INT_POLARITY);
369	data->config |= ADT7X10_FULL | ADT7X10_RESOLUTION | ADT7X10_EVENT_MODE;
370
371	if (data->config != data->oldconfig) {
372		ret = regmap_write(regmap, ADT7X10_CONFIG, data->config);
373		if (ret)
374			return ret;
375		ret = devm_add_action_or_reset(dev, adt7x10_restore_config, data);
376		if (ret)
377			return ret;
378	}
379	dev_dbg(dev, "Config %02x\n", data->config);
380
381	hdev = devm_hwmon_device_register_with_info(dev, name, data,
382						    &adt7x10_chip_info, NULL);
383	if (IS_ERR(hdev))
384		return PTR_ERR(hdev);
385
386	if (irq > 0) {
387		ret = devm_request_threaded_irq(dev, irq, NULL,
388						adt7x10_irq_handler,
389						IRQF_TRIGGER_FALLING |
390						IRQF_ONESHOT,
391						dev_name(dev), hdev);
392		if (ret)
393			return ret;
394	}
395
396	return 0;
397}
398EXPORT_SYMBOL_GPL(adt7x10_probe);
399
400static int adt7x10_suspend(struct device *dev)
401{
402	struct adt7x10_data *data = dev_get_drvdata(dev);
403
404	return regmap_write(data->regmap, ADT7X10_CONFIG,
405			    data->config | ADT7X10_PD);
406}
407
408static int adt7x10_resume(struct device *dev)
409{
410	struct adt7x10_data *data = dev_get_drvdata(dev);
411
412	return regmap_write(data->regmap, ADT7X10_CONFIG, data->config);
413}
414
415EXPORT_SIMPLE_DEV_PM_OPS(adt7x10_dev_pm_ops, adt7x10_suspend, adt7x10_resume);
416
417MODULE_AUTHOR("Hartmut Knaack");
418MODULE_DESCRIPTION("ADT7410/ADT7420, ADT7310/ADT7320 common code");
419MODULE_LICENSE("GPL");
420