xref: /linux/drivers/hwmon/max31827.c (revision 5e2cb28dd7e182dfa641550dfa225913509ad45d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * max31827.c - Support for Maxim Low-Power Switch
4  *
5  * Copyright (c) 2023 Daniel Matyas <daniel.matyas@analog.com>
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/bitops.h>
10 #include <linux/delay.h>
11 #include <linux/hwmon.h>
12 #include <linux/i2c.h>
13 #include <linux/mutex.h>
14 #include <linux/regmap.h>
15 
16 #define MAX31827_T_REG			0x0
17 #define MAX31827_CONFIGURATION_REG	0x2
18 #define MAX31827_TH_REG			0x4
19 #define MAX31827_TL_REG			0x6
20 #define MAX31827_TH_HYST_REG		0x8
21 #define MAX31827_TL_HYST_REG		0xA
22 
23 #define MAX31827_CONFIGURATION_1SHOT_MASK	BIT(0)
24 #define MAX31827_CONFIGURATION_CNV_RATE_MASK	GENMASK(3, 1)
25 #define MAX31827_CONFIGURATION_U_TEMP_STAT_MASK	BIT(14)
26 #define MAX31827_CONFIGURATION_O_TEMP_STAT_MASK	BIT(15)
27 
28 #define MAX31827_12_BIT_CNV_TIME	140
29 
30 #define MAX31827_16_BIT_TO_M_DGR(x)	(sign_extend32(x, 15) * 1000 / 16)
31 #define MAX31827_M_DGR_TO_16_BIT(x)	(((x) << 4) / 1000)
32 #define MAX31827_DEVICE_ENABLE(x)	((x) ? 0xA : 0x0)
33 
34 enum max31827_cnv {
35 	MAX31827_CNV_1_DIV_64_HZ = 1,
36 	MAX31827_CNV_1_DIV_32_HZ,
37 	MAX31827_CNV_1_DIV_16_HZ,
38 	MAX31827_CNV_1_DIV_4_HZ,
39 	MAX31827_CNV_1_HZ,
40 	MAX31827_CNV_4_HZ,
41 	MAX31827_CNV_8_HZ,
42 };
43 
44 static const u16 max31827_conversions[] = {
45 	[MAX31827_CNV_1_DIV_64_HZ] = 64000,
46 	[MAX31827_CNV_1_DIV_32_HZ] = 32000,
47 	[MAX31827_CNV_1_DIV_16_HZ] = 16000,
48 	[MAX31827_CNV_1_DIV_4_HZ] = 4000,
49 	[MAX31827_CNV_1_HZ] = 1000,
50 	[MAX31827_CNV_4_HZ] = 250,
51 	[MAX31827_CNV_8_HZ] = 125,
52 };
53 
54 struct max31827_state {
55 	/*
56 	 * Prevent simultaneous access to the i2c client.
57 	 */
58 	struct mutex lock;
59 	struct regmap *regmap;
60 	bool enable;
61 };
62 
63 static const struct regmap_config max31827_regmap = {
64 	.reg_bits = 8,
65 	.val_bits = 16,
66 	.max_register = 0xA,
67 };
68 
69 static int shutdown_write(struct max31827_state *st, unsigned int reg,
70 			  unsigned int val)
71 {
72 	unsigned int cfg;
73 	unsigned int cnv_rate;
74 	int ret;
75 
76 	/*
77 	 * Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
78 	 * register values are changed over I2C, the part must be in shutdown
79 	 * mode.
80 	 *
81 	 * Mutex is used to ensure, that some other process doesn't change the
82 	 * configuration register.
83 	 */
84 	mutex_lock(&st->lock);
85 
86 	if (!st->enable) {
87 		ret = regmap_write(st->regmap, reg, val);
88 		goto unlock;
89 	}
90 
91 	ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &cfg);
92 	if (ret)
93 		goto unlock;
94 
95 	cnv_rate = MAX31827_CONFIGURATION_CNV_RATE_MASK & cfg;
96 	cfg = cfg & ~(MAX31827_CONFIGURATION_1SHOT_MASK |
97 		      MAX31827_CONFIGURATION_CNV_RATE_MASK);
98 	ret = regmap_write(st->regmap, MAX31827_CONFIGURATION_REG, cfg);
99 	if (ret)
100 		goto unlock;
101 
102 	ret = regmap_write(st->regmap, reg, val);
103 	if (ret)
104 		goto unlock;
105 
106 	ret = regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
107 				 MAX31827_CONFIGURATION_CNV_RATE_MASK,
108 				 cnv_rate);
109 
110 unlock:
111 	mutex_unlock(&st->lock);
112 	return ret;
113 }
114 
115 static int write_alarm_val(struct max31827_state *st, unsigned int reg,
116 			   long val)
117 {
118 	val = MAX31827_M_DGR_TO_16_BIT(val);
119 
120 	return shutdown_write(st, reg, val);
121 }
122 
123 static umode_t max31827_is_visible(const void *state,
124 				   enum hwmon_sensor_types type, u32 attr,
125 				   int channel)
126 {
127 	if (type == hwmon_temp) {
128 		switch (attr) {
129 		case hwmon_temp_enable:
130 		case hwmon_temp_max:
131 		case hwmon_temp_min:
132 		case hwmon_temp_max_hyst:
133 		case hwmon_temp_min_hyst:
134 			return 0644;
135 		case hwmon_temp_input:
136 		case hwmon_temp_min_alarm:
137 		case hwmon_temp_max_alarm:
138 			return 0444;
139 		default:
140 			return 0;
141 		}
142 	} else if (type == hwmon_chip) {
143 		if (attr == hwmon_chip_update_interval)
144 			return 0644;
145 	}
146 
147 	return 0;
148 }
149 
150 static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
151 			 u32 attr, int channel, long *val)
152 {
153 	struct max31827_state *st = dev_get_drvdata(dev);
154 	unsigned int uval;
155 	int ret = 0;
156 
157 	switch (type) {
158 	case hwmon_temp:
159 		switch (attr) {
160 		case hwmon_temp_enable:
161 			ret = regmap_read(st->regmap,
162 					  MAX31827_CONFIGURATION_REG, &uval);
163 			if (ret)
164 				break;
165 
166 			uval = FIELD_GET(MAX31827_CONFIGURATION_1SHOT_MASK |
167 					 MAX31827_CONFIGURATION_CNV_RATE_MASK,
168 					 uval);
169 			*val = !!uval;
170 
171 			break;
172 		case hwmon_temp_input:
173 			mutex_lock(&st->lock);
174 
175 			if (!st->enable) {
176 				/*
177 				 * This operation requires mutex protection,
178 				 * because the chip configuration should not
179 				 * be changed during the conversion process.
180 				 */
181 
182 				ret = regmap_update_bits(st->regmap,
183 							 MAX31827_CONFIGURATION_REG,
184 							 MAX31827_CONFIGURATION_1SHOT_MASK,
185 							 1);
186 				if (ret) {
187 					mutex_unlock(&st->lock);
188 					return ret;
189 				}
190 
191 				msleep(MAX31827_12_BIT_CNV_TIME);
192 			}
193 			ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
194 
195 			mutex_unlock(&st->lock);
196 
197 			if (ret)
198 				break;
199 
200 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
201 
202 			break;
203 		case hwmon_temp_max:
204 			ret = regmap_read(st->regmap, MAX31827_TH_REG, &uval);
205 			if (ret)
206 				break;
207 
208 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
209 			break;
210 		case hwmon_temp_max_hyst:
211 			ret = regmap_read(st->regmap, MAX31827_TH_HYST_REG,
212 					  &uval);
213 			if (ret)
214 				break;
215 
216 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
217 			break;
218 		case hwmon_temp_max_alarm:
219 			ret = regmap_read(st->regmap,
220 					  MAX31827_CONFIGURATION_REG, &uval);
221 			if (ret)
222 				break;
223 
224 			*val = FIELD_GET(MAX31827_CONFIGURATION_O_TEMP_STAT_MASK,
225 					 uval);
226 			break;
227 		case hwmon_temp_min:
228 			ret = regmap_read(st->regmap, MAX31827_TL_REG, &uval);
229 			if (ret)
230 				break;
231 
232 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
233 			break;
234 		case hwmon_temp_min_hyst:
235 			ret = regmap_read(st->regmap, MAX31827_TL_HYST_REG,
236 					  &uval);
237 			if (ret)
238 				break;
239 
240 			*val = MAX31827_16_BIT_TO_M_DGR(uval);
241 			break;
242 		case hwmon_temp_min_alarm:
243 			ret = regmap_read(st->regmap,
244 					  MAX31827_CONFIGURATION_REG, &uval);
245 			if (ret)
246 				break;
247 
248 			*val = FIELD_GET(MAX31827_CONFIGURATION_U_TEMP_STAT_MASK,
249 					 uval);
250 			break;
251 		default:
252 			ret = -EOPNOTSUPP;
253 			break;
254 		}
255 
256 		break;
257 
258 	case hwmon_chip:
259 		if (attr == hwmon_chip_update_interval) {
260 			ret = regmap_read(st->regmap,
261 					  MAX31827_CONFIGURATION_REG, &uval);
262 			if (ret)
263 				break;
264 
265 			uval = FIELD_GET(MAX31827_CONFIGURATION_CNV_RATE_MASK,
266 					 uval);
267 			*val = max31827_conversions[uval];
268 		}
269 		break;
270 
271 	default:
272 		ret = -EOPNOTSUPP;
273 		break;
274 	}
275 
276 	return ret;
277 }
278 
279 static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
280 			  u32 attr, int channel, long val)
281 {
282 	struct max31827_state *st = dev_get_drvdata(dev);
283 	int res = 1;
284 	int ret;
285 
286 	switch (type) {
287 	case hwmon_temp:
288 		switch (attr) {
289 		case hwmon_temp_enable:
290 			if (val >> 1)
291 				return -EINVAL;
292 
293 			mutex_lock(&st->lock);
294 			/**
295 			 * The chip should not be enabled while a conversion is
296 			 * performed. Neither should the chip be enabled when
297 			 * the alarm values are changed.
298 			 */
299 
300 			st->enable = val;
301 
302 			ret = regmap_update_bits(st->regmap,
303 						 MAX31827_CONFIGURATION_REG,
304 						 MAX31827_CONFIGURATION_1SHOT_MASK |
305 						 MAX31827_CONFIGURATION_CNV_RATE_MASK,
306 						 MAX31827_DEVICE_ENABLE(val));
307 
308 			mutex_unlock(&st->lock);
309 
310 			return ret;
311 
312 		case hwmon_temp_max:
313 			return write_alarm_val(st, MAX31827_TH_REG, val);
314 
315 		case hwmon_temp_max_hyst:
316 			return write_alarm_val(st, MAX31827_TH_HYST_REG, val);
317 
318 		case hwmon_temp_min:
319 			return write_alarm_val(st, MAX31827_TL_REG, val);
320 
321 		case hwmon_temp_min_hyst:
322 			return write_alarm_val(st, MAX31827_TL_HYST_REG, val);
323 
324 		default:
325 			return -EOPNOTSUPP;
326 		}
327 
328 	case hwmon_chip:
329 		if (attr == hwmon_chip_update_interval) {
330 			if (!st->enable)
331 				return -EINVAL;
332 
333 			/*
334 			 * Convert the desired conversion rate into register
335 			 * bits. res is already initialized with 1.
336 			 *
337 			 * This was inspired by lm73 driver.
338 			 */
339 			while (res < ARRAY_SIZE(max31827_conversions) &&
340 			       val < max31827_conversions[res])
341 				res++;
342 
343 			if (res == ARRAY_SIZE(max31827_conversions) ||
344 			    val != max31827_conversions[res])
345 				return -EINVAL;
346 
347 			res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
348 					 res);
349 
350 			return regmap_update_bits(st->regmap,
351 						  MAX31827_CONFIGURATION_REG,
352 						  MAX31827_CONFIGURATION_CNV_RATE_MASK,
353 						  res);
354 		}
355 		break;
356 
357 	default:
358 		return -EOPNOTSUPP;
359 	}
360 
361 	return -EOPNOTSUPP;
362 }
363 
364 static int max31827_init_client(struct max31827_state *st)
365 {
366 	st->enable = true;
367 
368 	return regmap_update_bits(st->regmap, MAX31827_CONFIGURATION_REG,
369 				  MAX31827_CONFIGURATION_1SHOT_MASK |
370 					  MAX31827_CONFIGURATION_CNV_RATE_MASK,
371 				  MAX31827_DEVICE_ENABLE(1));
372 }
373 
374 static const struct hwmon_channel_info *max31827_info[] = {
375 	HWMON_CHANNEL_INFO(temp, HWMON_T_ENABLE | HWMON_T_INPUT | HWMON_T_MIN |
376 					 HWMON_T_MIN_HYST | HWMON_T_MIN_ALARM |
377 					 HWMON_T_MAX | HWMON_T_MAX_HYST |
378 					 HWMON_T_MAX_ALARM),
379 	HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL),
380 	NULL,
381 };
382 
383 static const struct hwmon_ops max31827_hwmon_ops = {
384 	.is_visible = max31827_is_visible,
385 	.read = max31827_read,
386 	.write = max31827_write,
387 };
388 
389 static const struct hwmon_chip_info max31827_chip_info = {
390 	.ops = &max31827_hwmon_ops,
391 	.info = max31827_info,
392 };
393 
394 static int max31827_probe(struct i2c_client *client)
395 {
396 	struct device *dev = &client->dev;
397 	struct device *hwmon_dev;
398 	struct max31827_state *st;
399 	int err;
400 
401 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
402 		return -EOPNOTSUPP;
403 
404 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
405 	if (!st)
406 		return -ENOMEM;
407 
408 	mutex_init(&st->lock);
409 
410 	st->regmap = devm_regmap_init_i2c(client, &max31827_regmap);
411 	if (IS_ERR(st->regmap))
412 		return dev_err_probe(dev, PTR_ERR(st->regmap),
413 				     "Failed to allocate regmap.\n");
414 
415 	err = devm_regulator_get_enable(dev, "vref");
416 	if (err)
417 		return dev_err_probe(dev, err, "failed to enable regulator\n");
418 
419 	err = max31827_init_client(st);
420 	if (err)
421 		return err;
422 
423 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
424 							 &max31827_chip_info,
425 							 NULL);
426 
427 	return PTR_ERR_OR_ZERO(hwmon_dev);
428 }
429 
430 static const struct i2c_device_id max31827_i2c_ids[] = {
431 	{ "max31827", 0 },
432 	{ }
433 };
434 MODULE_DEVICE_TABLE(i2c, max31827_i2c_ids);
435 
436 static const struct of_device_id max31827_of_match[] = {
437 	{ .compatible = "adi,max31827" },
438 	{ }
439 };
440 MODULE_DEVICE_TABLE(of, max31827_of_match);
441 
442 static struct i2c_driver max31827_driver = {
443 	.class = I2C_CLASS_HWMON,
444 	.driver = {
445 		.name = "max31827",
446 		.of_match_table = max31827_of_match,
447 	},
448 	.probe = max31827_probe,
449 	.id_table = max31827_i2c_ids,
450 };
451 module_i2c_driver(max31827_driver);
452 
453 MODULE_AUTHOR("Daniel Matyas <daniel.matyas@analog.com>");
454 MODULE_DESCRIPTION("Maxim MAX31827 low-power temperature switch driver");
455 MODULE_LICENSE("GPL");
456