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