xref: /linux/drivers/hwmon/ina238.c (revision 24bce201d79807b668bf9d9e0aca801c5c0d5f78)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Driver for Texas Instruments INA238 power monitor chip
4  * Datasheet: https://www.ti.com/product/ina238
5  *
6  * Copyright (C) 2021 Nathan Rossi <nathan.rossi@digi.com>
7  */
8 
9 #include <linux/err.h>
10 #include <linux/hwmon.h>
11 #include <linux/i2c.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/of.h>
16 #include <linux/regmap.h>
17 
18 #include <linux/platform_data/ina2xx.h>
19 
20 /* INA238 register definitions */
21 #define INA238_CONFIG			0x0
22 #define INA238_ADC_CONFIG		0x1
23 #define INA238_SHUNT_CALIBRATION	0x2
24 #define INA238_SHUNT_VOLTAGE		0x4
25 #define INA238_BUS_VOLTAGE		0x5
26 #define INA238_DIE_TEMP			0x6
27 #define INA238_CURRENT			0x7
28 #define INA238_POWER			0x8
29 #define INA238_DIAG_ALERT		0xb
30 #define INA238_SHUNT_OVER_VOLTAGE	0xc
31 #define INA238_SHUNT_UNDER_VOLTAGE	0xd
32 #define INA238_BUS_OVER_VOLTAGE		0xe
33 #define INA238_BUS_UNDER_VOLTAGE	0xf
34 #define INA238_TEMP_LIMIT		0x10
35 #define INA238_POWER_LIMIT		0x11
36 #define INA238_DEVICE_ID		0x3f
37 
38 #define INA238_CONFIG_ADCRANGE		BIT(4)
39 
40 #define INA238_DIAG_ALERT_TMPOL		BIT(7)
41 #define INA238_DIAG_ALERT_SHNTOL	BIT(6)
42 #define INA238_DIAG_ALERT_SHNTUL	BIT(5)
43 #define INA238_DIAG_ALERT_BUSOL		BIT(4)
44 #define INA238_DIAG_ALERT_BUSUL		BIT(3)
45 #define INA238_DIAG_ALERT_POL		BIT(2)
46 
47 #define INA238_REGISTERS		0x11
48 
49 #define INA238_RSHUNT_DEFAULT		10000 /* uOhm */
50 
51 /* Default configuration of device on reset. */
52 #define INA238_CONFIG_DEFAULT		0
53 /* 16 sample averaging, 1052us conversion time, continuous mode */
54 #define INA238_ADC_CONFIG_DEFAULT	0xfb6a
55 /* Configure alerts to be based on averaged value (SLOWALERT) */
56 #define INA238_DIAG_ALERT_DEFAULT	0x2000
57 /*
58  * This driver uses a fixed calibration value in order to scale current/power
59  * based on a fixed shunt resistor value. This allows for conversion within the
60  * device to avoid integer limits whilst current/power accuracy is scaled
61  * relative to the shunt resistor value within the driver. This is similar to
62  * how the ina2xx driver handles current/power scaling.
63  *
64  * The end result of this is that increasing shunt values (from a fixed 20 mOhm
65  * shunt) increase the effective current/power accuracy whilst limiting the
66  * range and decreasing shunt values decrease the effective accuracy but
67  * increase the range.
68  *
69  * The value of the Current register is calculated given the following:
70  *   Current (A) = (shunt voltage register * 5) * calibration / 81920
71  *
72  * The maximum shunt voltage is 163.835 mV (0x7fff, ADC_RANGE = 0, gain = 4).
73  * With the maximum current value of 0x7fff and a fixed shunt value results in
74  * a calibration value of 16384 (0x4000).
75  *
76  *   0x7fff = (0x7fff * 5) * calibration / 81920
77  *   calibration = 0x4000
78  *
79  * Equivalent calibration is applied for the Power register (maximum value for
80  * bus voltage is 102396.875 mV, 0x7fff), where the maximum power that can
81  * occur is ~16776192 uW (register value 0x147a8):
82  *
83  * This scaling means the resulting values for Current and Power registers need
84  * to be scaled by the difference between the fixed shunt resistor and the
85  * actual shunt resistor:
86  *
87  *  shunt = 0x4000 / (819.2 * 10^6) / 0.001 = 20000 uOhms (with 1mA/lsb)
88  *
89  *  Current (mA) = register value * 20000 / rshunt / 4 * gain
90  *  Power (W) = 0.2 * register value * 20000 / rshunt / 4 * gain
91  */
92 #define INA238_CALIBRATION_VALUE	16384
93 #define INA238_FIXED_SHUNT		20000
94 
95 #define INA238_SHUNT_VOLTAGE_LSB	5 /* 5 uV/lsb */
96 #define INA238_BUS_VOLTAGE_LSB		3125 /* 3.125 mV/lsb */
97 #define INA238_DIE_TEMP_LSB		125 /* 125 mC/lsb */
98 
99 static struct regmap_config ina238_regmap_config = {
100 	.max_register = INA238_REGISTERS,
101 	.reg_bits = 8,
102 	.val_bits = 16,
103 };
104 
105 struct ina238_data {
106 	struct i2c_client *client;
107 	struct mutex config_lock;
108 	struct regmap *regmap;
109 	u32 rshunt;
110 	int gain;
111 };
112 
113 static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
114 {
115 	u8 data[3];
116 	int err;
117 
118 	/* 24-bit register read */
119 	err = i2c_smbus_read_i2c_block_data(client, reg, 3, data);
120 	if (err < 0)
121 		return err;
122 	if (err != 3)
123 		return -EIO;
124 	*val = (data[0] << 16) | (data[1] << 8) | data[2];
125 
126 	return 0;
127 }
128 
129 static int ina238_read_in(struct device *dev, u32 attr, int channel,
130 			  long *val)
131 {
132 	struct ina238_data *data = dev_get_drvdata(dev);
133 	int reg, mask;
134 	int regval;
135 	int err;
136 
137 	switch (channel) {
138 	case 0:
139 		switch (attr) {
140 		case hwmon_in_input:
141 			reg = INA238_SHUNT_VOLTAGE;
142 			break;
143 		case hwmon_in_max:
144 			reg = INA238_SHUNT_OVER_VOLTAGE;
145 			break;
146 		case hwmon_in_min:
147 			reg = INA238_SHUNT_UNDER_VOLTAGE;
148 			break;
149 		case hwmon_in_max_alarm:
150 			reg = INA238_DIAG_ALERT;
151 			mask = INA238_DIAG_ALERT_SHNTOL;
152 			break;
153 		case hwmon_in_min_alarm:
154 			reg = INA238_DIAG_ALERT;
155 			mask = INA238_DIAG_ALERT_SHNTUL;
156 			break;
157 		default:
158 			return -EOPNOTSUPP;
159 		}
160 		break;
161 	case 1:
162 		switch (attr) {
163 		case hwmon_in_input:
164 			reg = INA238_BUS_VOLTAGE;
165 			break;
166 		case hwmon_in_max:
167 			reg = INA238_BUS_OVER_VOLTAGE;
168 			break;
169 		case hwmon_in_min:
170 			reg = INA238_BUS_UNDER_VOLTAGE;
171 			break;
172 		case hwmon_in_max_alarm:
173 			reg = INA238_DIAG_ALERT;
174 			mask = INA238_DIAG_ALERT_BUSOL;
175 			break;
176 		case hwmon_in_min_alarm:
177 			reg = INA238_DIAG_ALERT;
178 			mask = INA238_DIAG_ALERT_BUSUL;
179 			break;
180 		default:
181 			return -EOPNOTSUPP;
182 		}
183 		break;
184 	default:
185 		return -EOPNOTSUPP;
186 	}
187 
188 	err = regmap_read(data->regmap, reg, &regval);
189 	if (err < 0)
190 		return err;
191 
192 	switch (attr) {
193 	case hwmon_in_input:
194 	case hwmon_in_max:
195 	case hwmon_in_min:
196 		/* signed register, value in mV */
197 		regval = (s16)regval;
198 		if (channel == 0)
199 			/* gain of 1 -> LSB / 4 */
200 			*val = (regval * INA238_SHUNT_VOLTAGE_LSB) /
201 			       (1000 * (4 - data->gain + 1));
202 		else
203 			*val = (regval * INA238_BUS_VOLTAGE_LSB) / 1000;
204 		break;
205 	case hwmon_in_max_alarm:
206 	case hwmon_in_min_alarm:
207 		*val = !!(regval & mask);
208 		break;
209 	}
210 
211 	return 0;
212 }
213 
214 static int ina238_write_in(struct device *dev, u32 attr, int channel,
215 			   long val)
216 {
217 	struct ina238_data *data = dev_get_drvdata(dev);
218 	int regval;
219 
220 	if (attr != hwmon_in_max && attr != hwmon_in_min)
221 		return -EOPNOTSUPP;
222 
223 	/* convert decimal to register value */
224 	switch (channel) {
225 	case 0:
226 		/* signed value, clamp to max range +/-163 mV */
227 		regval = clamp_val(val, -163, 163);
228 		regval = (regval * 1000 * (4 - data->gain + 1)) /
229 			 INA238_SHUNT_VOLTAGE_LSB;
230 		regval = clamp_val(regval, S16_MIN, S16_MAX);
231 
232 		switch (attr) {
233 		case hwmon_in_max:
234 			return regmap_write(data->regmap,
235 					    INA238_SHUNT_OVER_VOLTAGE, regval);
236 		case hwmon_in_min:
237 			return regmap_write(data->regmap,
238 					    INA238_SHUNT_UNDER_VOLTAGE, regval);
239 		default:
240 			return -EOPNOTSUPP;
241 		}
242 	case 1:
243 		/* signed value, positive values only. Clamp to max 102.396 V */
244 		regval = clamp_val(val, 0, 102396);
245 		regval = (regval * 1000) / INA238_BUS_VOLTAGE_LSB;
246 		regval = clamp_val(regval, 0, S16_MAX);
247 
248 		switch (attr) {
249 		case hwmon_in_max:
250 			return regmap_write(data->regmap,
251 					    INA238_BUS_OVER_VOLTAGE, regval);
252 		case hwmon_in_min:
253 			return regmap_write(data->regmap,
254 					    INA238_BUS_UNDER_VOLTAGE, regval);
255 		default:
256 			return -EOPNOTSUPP;
257 		}
258 	default:
259 		return -EOPNOTSUPP;
260 	}
261 }
262 
263 static int ina238_read_current(struct device *dev, u32 attr, long *val)
264 {
265 	struct ina238_data *data = dev_get_drvdata(dev);
266 	int regval;
267 	int err;
268 
269 	switch (attr) {
270 	case hwmon_curr_input:
271 		err = regmap_read(data->regmap, INA238_CURRENT, &regval);
272 		if (err < 0)
273 			return err;
274 
275 		/* Signed register, fixed 1mA current lsb. result in mA */
276 		*val = div_s64((s16)regval * INA238_FIXED_SHUNT * data->gain,
277 			       data->rshunt * 4);
278 		break;
279 	default:
280 		return -EOPNOTSUPP;
281 	}
282 
283 	return 0;
284 }
285 
286 static int ina238_read_power(struct device *dev, u32 attr, long *val)
287 {
288 	struct ina238_data *data = dev_get_drvdata(dev);
289 	long long power;
290 	int regval;
291 	int err;
292 
293 	switch (attr) {
294 	case hwmon_power_input:
295 		err = ina238_read_reg24(data->client, INA238_POWER, &regval);
296 		if (err)
297 			return err;
298 
299 		/* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
300 		power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT *
301 				data->gain, 20 * data->rshunt);
302 		/* Clamp value to maximum value of long */
303 		*val = clamp_val(power, 0, LONG_MAX);
304 		break;
305 	case hwmon_power_max:
306 		err = regmap_read(data->regmap, INA238_POWER_LIMIT, &regval);
307 		if (err)
308 			return err;
309 
310 		/*
311 		 * Truncated 24-bit compare register, lower 8-bits are
312 		 * truncated. Same conversion to/from uW as POWER register.
313 		 */
314 		power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT *
315 			       data->gain, 20 * data->rshunt);
316 		/* Clamp value to maximum value of long */
317 		*val = clamp_val(power, 0, LONG_MAX);
318 		break;
319 	case hwmon_power_max_alarm:
320 		err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval);
321 		if (err)
322 			return err;
323 
324 		*val = !!(regval & INA238_DIAG_ALERT_POL);
325 		break;
326 	default:
327 		return -EOPNOTSUPP;
328 	}
329 
330 	return 0;
331 }
332 
333 static int ina238_write_power(struct device *dev, u32 attr, long val)
334 {
335 	struct ina238_data *data = dev_get_drvdata(dev);
336 	long regval;
337 
338 	if (attr != hwmon_power_max)
339 		return -EOPNOTSUPP;
340 
341 	/*
342 	 * Unsigned postive values. Compared against the 24-bit power register,
343 	 * lower 8-bits are truncated. Same conversion to/from uW as POWER
344 	 * register.
345 	 */
346 	regval = clamp_val(val, 0, LONG_MAX);
347 	regval = div_u64(val * 20ULL * data->rshunt,
348 			 1000ULL * INA238_FIXED_SHUNT * data->gain);
349 	regval = clamp_val(regval >> 8, 0, U16_MAX);
350 
351 	return regmap_write(data->regmap, INA238_POWER_LIMIT, regval);
352 }
353 
354 static int ina238_read_temp(struct device *dev, u32 attr, long *val)
355 {
356 	struct ina238_data *data = dev_get_drvdata(dev);
357 	int regval;
358 	int err;
359 
360 	switch (attr) {
361 	case hwmon_temp_input:
362 		err = regmap_read(data->regmap, INA238_DIE_TEMP, &regval);
363 		if (err)
364 			return err;
365 
366 		/* Signed, bits 15-4 of register, result in mC */
367 		*val = ((s16)regval >> 4) * INA238_DIE_TEMP_LSB;
368 		break;
369 	case hwmon_temp_max:
370 		err = regmap_read(data->regmap, INA238_TEMP_LIMIT, &regval);
371 		if (err)
372 			return err;
373 
374 		/* Signed, bits 15-4 of register, result in mC */
375 		*val = ((s16)regval >> 4) * INA238_DIE_TEMP_LSB;
376 		break;
377 	case hwmon_temp_max_alarm:
378 		err = regmap_read(data->regmap, INA238_DIAG_ALERT, &regval);
379 		if (err)
380 			return err;
381 
382 		*val = !!(regval & INA238_DIAG_ALERT_TMPOL);
383 		break;
384 	default:
385 		return -EOPNOTSUPP;
386 	}
387 
388 	return 0;
389 }
390 
391 static int ina238_write_temp(struct device *dev, u32 attr, long val)
392 {
393 	struct ina238_data *data = dev_get_drvdata(dev);
394 	int regval;
395 
396 	if (attr != hwmon_temp_max)
397 		return -EOPNOTSUPP;
398 
399 	/* Signed, bits 15-4 of register */
400 	regval = (val / INA238_DIE_TEMP_LSB) << 4;
401 	regval = clamp_val(regval, S16_MIN, S16_MAX) & 0xfff0;
402 
403 	return regmap_write(data->regmap, INA238_TEMP_LIMIT, regval);
404 }
405 
406 static int ina238_read(struct device *dev, enum hwmon_sensor_types type,
407 		       u32 attr, int channel, long *val)
408 {
409 	switch (type) {
410 	case hwmon_in:
411 		return ina238_read_in(dev, attr, channel, val);
412 	case hwmon_curr:
413 		return ina238_read_current(dev, attr, val);
414 	case hwmon_power:
415 		return ina238_read_power(dev, attr, val);
416 	case hwmon_temp:
417 		return ina238_read_temp(dev, attr, val);
418 	default:
419 		return -EOPNOTSUPP;
420 	}
421 	return 0;
422 }
423 
424 static int ina238_write(struct device *dev, enum hwmon_sensor_types type,
425 		       u32 attr, int channel, long val)
426 {
427 	struct ina238_data *data = dev_get_drvdata(dev);
428 	int err;
429 
430 	mutex_lock(&data->config_lock);
431 
432 	switch (type) {
433 	case hwmon_in:
434 		err = ina238_write_in(dev, attr, channel, val);
435 		break;
436 	case hwmon_power:
437 		err = ina238_write_power(dev, attr, val);
438 		break;
439 	case hwmon_temp:
440 		err = ina238_write_temp(dev, attr, val);
441 		break;
442 	default:
443 		err = -EOPNOTSUPP;
444 		break;
445 	}
446 
447 	mutex_unlock(&data->config_lock);
448 	return err;
449 }
450 
451 static umode_t ina238_is_visible(const void *drvdata,
452 				 enum hwmon_sensor_types type,
453 				 u32 attr, int channel)
454 {
455 	switch (type) {
456 	case hwmon_in:
457 		switch (attr) {
458 		case hwmon_in_input:
459 		case hwmon_in_max_alarm:
460 		case hwmon_in_min_alarm:
461 			return 0444;
462 		case hwmon_in_max:
463 		case hwmon_in_min:
464 			return 0644;
465 		default:
466 			return 0;
467 		}
468 	case hwmon_curr:
469 		switch (attr) {
470 		case hwmon_curr_input:
471 			return 0444;
472 		default:
473 			return 0;
474 		}
475 	case hwmon_power:
476 		switch (attr) {
477 		case hwmon_power_input:
478 		case hwmon_power_max_alarm:
479 			return 0444;
480 		case hwmon_power_max:
481 			return 0644;
482 		default:
483 			return 0;
484 		}
485 	case hwmon_temp:
486 		switch (attr) {
487 		case hwmon_temp_input:
488 		case hwmon_temp_max_alarm:
489 			return 0444;
490 		case hwmon_temp_max:
491 			return 0644;
492 		default:
493 			return 0;
494 		}
495 	default:
496 		return 0;
497 	}
498 }
499 
500 #define INA238_HWMON_IN_CONFIG (HWMON_I_INPUT | \
501 				HWMON_I_MAX | HWMON_I_MAX_ALARM | \
502 				HWMON_I_MIN | HWMON_I_MIN_ALARM)
503 
504 static const struct hwmon_channel_info *ina238_info[] = {
505 	HWMON_CHANNEL_INFO(in,
506 			   /* 0: shunt voltage */
507 			   INA238_HWMON_IN_CONFIG,
508 			   /* 1: bus voltage */
509 			   INA238_HWMON_IN_CONFIG),
510 	HWMON_CHANNEL_INFO(curr,
511 			   /* 0: current through shunt */
512 			   HWMON_C_INPUT),
513 	HWMON_CHANNEL_INFO(power,
514 			   /* 0: power */
515 			   HWMON_P_INPUT | HWMON_P_MAX | HWMON_P_MAX_ALARM),
516 	HWMON_CHANNEL_INFO(temp,
517 			   /* 0: die temperature */
518 			   HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_ALARM),
519 	NULL
520 };
521 
522 static const struct hwmon_ops ina238_hwmon_ops = {
523 	.is_visible = ina238_is_visible,
524 	.read = ina238_read,
525 	.write = ina238_write,
526 };
527 
528 static const struct hwmon_chip_info ina238_chip_info = {
529 	.ops = &ina238_hwmon_ops,
530 	.info = ina238_info,
531 };
532 
533 static int ina238_probe(struct i2c_client *client)
534 {
535 	struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
536 	struct device *dev = &client->dev;
537 	struct device *hwmon_dev;
538 	struct ina238_data *data;
539 	int config;
540 	int ret;
541 
542 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
543 	if (!data)
544 		return -ENOMEM;
545 
546 	data->client = client;
547 	mutex_init(&data->config_lock);
548 
549 	data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config);
550 	if (IS_ERR(data->regmap)) {
551 		dev_err(dev, "failed to allocate register map\n");
552 		return PTR_ERR(data->regmap);
553 	}
554 
555 	/* load shunt value */
556 	data->rshunt = INA238_RSHUNT_DEFAULT;
557 	if (device_property_read_u32(dev, "shunt-resistor", &data->rshunt) < 0 && pdata)
558 		data->rshunt = pdata->shunt_uohms;
559 	if (data->rshunt == 0) {
560 		dev_err(dev, "invalid shunt resister value %u\n", data->rshunt);
561 		return -EINVAL;
562 	}
563 
564 	/* load shunt gain value */
565 	if (device_property_read_u32(dev, "ti,shunt-gain", &data->gain) < 0)
566 		data->gain = 4; /* Default of ADCRANGE = 0 */
567 	if (data->gain != 1 && data->gain != 4) {
568 		dev_err(dev, "invalid shunt gain value %u\n", data->gain);
569 		return -EINVAL;
570 	}
571 
572 	/* Setup CONFIG register */
573 	config = INA238_CONFIG_DEFAULT;
574 	if (data->gain == 1)
575 		config |= INA238_CONFIG_ADCRANGE; /* ADCRANGE = 1 is /1 */
576 	ret = regmap_write(data->regmap, INA238_CONFIG, config);
577 	if (ret < 0) {
578 		dev_err(dev, "error configuring the device: %d\n", ret);
579 		return -ENODEV;
580 	}
581 
582 	/* Setup ADC_CONFIG register */
583 	ret = regmap_write(data->regmap, INA238_ADC_CONFIG,
584 			   INA238_ADC_CONFIG_DEFAULT);
585 	if (ret < 0) {
586 		dev_err(dev, "error configuring the device: %d\n", ret);
587 		return -ENODEV;
588 	}
589 
590 	/* Setup SHUNT_CALIBRATION register with fixed value */
591 	ret = regmap_write(data->regmap, INA238_SHUNT_CALIBRATION,
592 			   INA238_CALIBRATION_VALUE);
593 	if (ret < 0) {
594 		dev_err(dev, "error configuring the device: %d\n", ret);
595 		return -ENODEV;
596 	}
597 
598 	/* Setup alert/alarm configuration */
599 	ret = regmap_write(data->regmap, INA238_DIAG_ALERT,
600 			   INA238_DIAG_ALERT_DEFAULT);
601 	if (ret < 0) {
602 		dev_err(dev, "error configuring the device: %d\n", ret);
603 		return -ENODEV;
604 	}
605 
606 	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
607 							 &ina238_chip_info,
608 							 NULL);
609 	if (IS_ERR(hwmon_dev))
610 		return PTR_ERR(hwmon_dev);
611 
612 	dev_info(dev, "power monitor %s (Rshunt = %u uOhm, gain = %u)\n",
613 		 client->name, data->rshunt, data->gain);
614 
615 	return 0;
616 }
617 
618 static const struct i2c_device_id ina238_id[] = {
619 	{ "ina238", 0 },
620 	{ }
621 };
622 MODULE_DEVICE_TABLE(i2c, ina238_id);
623 
624 static const struct of_device_id __maybe_unused ina238_of_match[] = {
625 	{ .compatible = "ti,ina238" },
626 	{ },
627 };
628 MODULE_DEVICE_TABLE(of, ina238_of_match);
629 
630 static struct i2c_driver ina238_driver = {
631 	.class		= I2C_CLASS_HWMON,
632 	.driver = {
633 		.name	= "ina238",
634 		.of_match_table = of_match_ptr(ina238_of_match),
635 	},
636 	.probe_new	= ina238_probe,
637 	.id_table	= ina238_id,
638 };
639 
640 module_i2c_driver(ina238_driver);
641 
642 MODULE_AUTHOR("Nathan Rossi <nathan.rossi@digi.com>");
643 MODULE_DESCRIPTION("ina238 driver");
644 MODULE_LICENSE("GPL");
645