Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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/bitops.h>
10#include <linux/err.h>
11#include <linux/hwmon.h>
12#include <linux/i2c.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/regmap.h>
18
19#include <linux/platform_data/ina2xx.h>
20
21/* INA238 register definitions */
22#define INA238_CONFIG 0x0
23#define INA238_ADC_CONFIG 0x1
24#define INA238_SHUNT_CALIBRATION 0x2
25#define SQ52206_SHUNT_TEMPCO 0x3
26#define INA238_SHUNT_VOLTAGE 0x4
27#define INA238_BUS_VOLTAGE 0x5
28#define INA238_DIE_TEMP 0x6
29#define INA238_CURRENT 0x7
30#define INA238_POWER 0x8
31#define SQ52206_ENERGY 0x9
32#define SQ52206_CHARGE 0xa
33#define INA238_DIAG_ALERT 0xb
34#define INA238_SHUNT_OVER_VOLTAGE 0xc
35#define INA238_SHUNT_UNDER_VOLTAGE 0xd
36#define INA238_BUS_OVER_VOLTAGE 0xe
37#define INA238_BUS_UNDER_VOLTAGE 0xf
38#define INA238_TEMP_LIMIT 0x10
39#define INA238_POWER_LIMIT 0x11
40#define SQ52206_POWER_PEAK 0x20
41#define INA238_DEVICE_ID 0x3f /* not available on INA237 */
42
43#define INA238_CONFIG_ADCRANGE BIT(4)
44#define SQ52206_CONFIG_ADCRANGE_HIGH BIT(4)
45#define SQ52206_CONFIG_ADCRANGE_LOW BIT(3)
46
47#define INA238_DIAG_ALERT_TMPOL BIT(7)
48#define INA238_DIAG_ALERT_SHNTOL BIT(6)
49#define INA238_DIAG_ALERT_SHNTUL BIT(5)
50#define INA238_DIAG_ALERT_BUSOL BIT(4)
51#define INA238_DIAG_ALERT_BUSUL BIT(3)
52#define INA238_DIAG_ALERT_POL BIT(2)
53
54#define INA238_REGISTERS 0x20
55
56#define INA238_RSHUNT_DEFAULT 10000 /* uOhm */
57
58/* Default configuration of device on reset. */
59#define INA238_CONFIG_DEFAULT 0
60#define SQ52206_CONFIG_DEFAULT 0x0005
61/* 16 sample averaging, 1052us conversion time, continuous mode */
62#define INA238_ADC_CONFIG_DEFAULT 0xfb6a
63/* Configure alerts to be based on averaged value (SLOWALERT) */
64#define INA238_DIAG_ALERT_DEFAULT 0x2000
65/*
66 * This driver uses a fixed calibration value in order to scale current/power
67 * based on a fixed shunt resistor value. This allows for conversion within the
68 * device to avoid integer limits whilst current/power accuracy is scaled
69 * relative to the shunt resistor value within the driver. This is similar to
70 * how the ina2xx driver handles current/power scaling.
71 *
72 * The end result of this is that increasing shunt values (from a fixed 20 mOhm
73 * shunt) increase the effective current/power accuracy whilst limiting the
74 * range and decreasing shunt values decrease the effective accuracy but
75 * increase the range.
76 *
77 * The value of the Current register is calculated given the following:
78 * Current (A) = (shunt voltage register * 5) * calibration / 81920
79 *
80 * The maximum shunt voltage is 163.835 mV (0x7fff, ADC_RANGE = 0, gain = 4).
81 * With the maximum current value of 0x7fff and a fixed shunt value results in
82 * a calibration value of 16384 (0x4000).
83 *
84 * 0x7fff = (0x7fff * 5) * calibration / 81920
85 * calibration = 0x4000
86 *
87 * Equivalent calibration is applied for the Power register (maximum value for
88 * bus voltage is 102396.875 mV, 0x7fff), where the maximum power that can
89 * occur is ~16776192 uW (register value 0x147a8):
90 *
91 * This scaling means the resulting values for Current and Power registers need
92 * to be scaled by the difference between the fixed shunt resistor and the
93 * actual shunt resistor:
94 *
95 * shunt = 0x4000 / (819.2 * 10^6) / 0.001 = 20000 uOhms (with 1mA/lsb)
96 *
97 * Current (mA) = register value * 20000 / rshunt / 4 * gain
98 * Power (mW) = 0.2 * register value * 20000 / rshunt / 4 * gain
99 * (Specific for SQ52206)
100 * Power (mW) = 0.24 * register value * 20000 / rshunt / 4 * gain
101 * Energy (uJ) = 16 * 0.24 * register value * 20000 / rshunt / 4 * gain * 1000
102 */
103#define INA238_CALIBRATION_VALUE 16384
104#define INA238_FIXED_SHUNT 20000
105
106#define INA238_SHUNT_VOLTAGE_LSB 5 /* 5 uV/lsb */
107#define INA238_BUS_VOLTAGE_LSB 3125 /* 3.125 mV/lsb */
108#define INA238_DIE_TEMP_LSB 1250000 /* 125.0000 mC/lsb */
109#define SQ52206_BUS_VOLTAGE_LSB 3750 /* 3.75 mV/lsb */
110#define SQ52206_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
111#define INA228_DIE_TEMP_LSB 78125 /* 7.8125 mC/lsb */
112
113static const struct regmap_config ina238_regmap_config = {
114 .max_register = INA238_REGISTERS,
115 .reg_bits = 8,
116 .val_bits = 16,
117};
118
119enum ina238_ids { ina238, ina237, sq52206, ina228 };
120
121struct ina238_config {
122 bool has_20bit_voltage_current; /* vshunt, vbus and current are 20-bit fields */
123 bool has_power_highest; /* chip detection power peak */
124 bool has_energy; /* chip detection energy */
125 u8 temp_shift; /* fixed parameters for temp calculate */
126 u32 power_calculate_factor; /* fixed parameters for power calculate */
127 u16 config_default; /* Power-on default state */
128 int bus_voltage_lsb; /* use for temperature calculate, uV/lsb */
129 int temp_lsb; /* use for temperature calculate */
130};
131
132struct ina238_data {
133 const struct ina238_config *config;
134 struct i2c_client *client;
135 struct mutex config_lock;
136 struct regmap *regmap;
137 u32 rshunt;
138 int gain;
139};
140
141static const struct ina238_config ina238_config[] = {
142 [ina238] = {
143 .has_20bit_voltage_current = false,
144 .has_energy = false,
145 .has_power_highest = false,
146 .temp_shift = 4,
147 .power_calculate_factor = 20,
148 .config_default = INA238_CONFIG_DEFAULT,
149 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
150 .temp_lsb = INA238_DIE_TEMP_LSB,
151 },
152 [ina237] = {
153 .has_20bit_voltage_current = false,
154 .has_energy = false,
155 .has_power_highest = false,
156 .temp_shift = 4,
157 .power_calculate_factor = 20,
158 .config_default = INA238_CONFIG_DEFAULT,
159 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
160 .temp_lsb = INA238_DIE_TEMP_LSB,
161 },
162 [sq52206] = {
163 .has_20bit_voltage_current = false,
164 .has_energy = true,
165 .has_power_highest = true,
166 .temp_shift = 0,
167 .power_calculate_factor = 24,
168 .config_default = SQ52206_CONFIG_DEFAULT,
169 .bus_voltage_lsb = SQ52206_BUS_VOLTAGE_LSB,
170 .temp_lsb = SQ52206_DIE_TEMP_LSB,
171 },
172 [ina228] = {
173 .has_20bit_voltage_current = true,
174 .has_energy = true,
175 .has_power_highest = false,
176 .temp_shift = 0,
177 .power_calculate_factor = 20,
178 .config_default = INA238_CONFIG_DEFAULT,
179 .bus_voltage_lsb = INA238_BUS_VOLTAGE_LSB,
180 .temp_lsb = INA228_DIE_TEMP_LSB,
181 },
182};
183
184static int ina238_read_reg24(const struct i2c_client *client, u8 reg, u32 *val)
185{
186 u8 data[3];
187 int err;
188
189 /* 24-bit register read */
190 err = i2c_smbus_read_i2c_block_data(client, reg, 3, data);
191 if (err < 0)
192 return err;
193 if (err != 3)
194 return -EIO;
195 *val = (data[0] << 16) | (data[1] << 8) | data[2];
196
197 return 0;
198}
199
200static int ina238_read_reg40(const struct i2c_client *client, u8 reg, u64 *val)
201{
202 u8 data[5];
203 u32 low;
204 int err;
205
206 /* 40-bit register read */
207 err = i2c_smbus_read_i2c_block_data(client, reg, 5, data);
208 if (err < 0)
209 return err;
210 if (err != 5)
211 return -EIO;
212 low = (data[1] << 24) | (data[2] << 16) | (data[3] << 8) | data[4];
213 *val = ((long long)data[0] << 32) | low;
214
215 return 0;
216}
217
218static int ina238_read_field_s20(const struct i2c_client *client, u8 reg, s32 *val)
219{
220 u32 regval;
221 int err;
222
223 err = ina238_read_reg24(client, reg, ®val);
224 if (err)
225 return err;
226
227 /* bits 3-0 Reserved, always zero */
228 regval >>= 4;
229
230 *val = sign_extend32(regval, 19);
231
232 return 0;
233}
234
235static int ina228_read_shunt_voltage(struct device *dev, u32 attr, int channel,
236 long *val)
237{
238 struct ina238_data *data = dev_get_drvdata(dev);
239 int regval;
240 int err;
241
242 err = ina238_read_field_s20(data->client, INA238_SHUNT_VOLTAGE, ®val);
243 if (err)
244 return err;
245
246 /*
247 * gain of 1 -> LSB / 4
248 * This field has 16 bit on ina238. ina228 adds another 4 bits of
249 * precision. ina238 conversion factors can still be applied when
250 * dividing by 16.
251 */
252 *val = (regval * INA238_SHUNT_VOLTAGE_LSB) * data->gain / (1000 * 4) / 16;
253 return 0;
254}
255
256static int ina228_read_bus_voltage(struct device *dev, u32 attr, int channel,
257 long *val)
258{
259 struct ina238_data *data = dev_get_drvdata(dev);
260 int regval;
261 int err;
262
263 err = ina238_read_field_s20(data->client, INA238_BUS_VOLTAGE, ®val);
264 if (err)
265 return err;
266
267 /*
268 * gain of 1 -> LSB / 4
269 * This field has 16 bit on ina238. ina228 adds another 4 bits of
270 * precision. ina238 conversion factors can still be applied when
271 * dividing by 16.
272 */
273 *val = (regval * data->config->bus_voltage_lsb) / 1000 / 16;
274 return 0;
275}
276
277static int ina238_read_in(struct device *dev, u32 attr, int channel,
278 long *val)
279{
280 struct ina238_data *data = dev_get_drvdata(dev);
281 int reg, mask;
282 int regval;
283 int err;
284
285 switch (channel) {
286 case 0:
287 switch (attr) {
288 case hwmon_in_input:
289 if (data->config->has_20bit_voltage_current)
290 return ina228_read_shunt_voltage(dev, attr, channel, val);
291 reg = INA238_SHUNT_VOLTAGE;
292 break;
293 case hwmon_in_max:
294 reg = INA238_SHUNT_OVER_VOLTAGE;
295 break;
296 case hwmon_in_min:
297 reg = INA238_SHUNT_UNDER_VOLTAGE;
298 break;
299 case hwmon_in_max_alarm:
300 reg = INA238_DIAG_ALERT;
301 mask = INA238_DIAG_ALERT_SHNTOL;
302 break;
303 case hwmon_in_min_alarm:
304 reg = INA238_DIAG_ALERT;
305 mask = INA238_DIAG_ALERT_SHNTUL;
306 break;
307 default:
308 return -EOPNOTSUPP;
309 }
310 break;
311 case 1:
312 switch (attr) {
313 case hwmon_in_input:
314 if (data->config->has_20bit_voltage_current)
315 return ina228_read_bus_voltage(dev, attr, channel, val);
316 reg = INA238_BUS_VOLTAGE;
317 break;
318 case hwmon_in_max:
319 reg = INA238_BUS_OVER_VOLTAGE;
320 break;
321 case hwmon_in_min:
322 reg = INA238_BUS_UNDER_VOLTAGE;
323 break;
324 case hwmon_in_max_alarm:
325 reg = INA238_DIAG_ALERT;
326 mask = INA238_DIAG_ALERT_BUSOL;
327 break;
328 case hwmon_in_min_alarm:
329 reg = INA238_DIAG_ALERT;
330 mask = INA238_DIAG_ALERT_BUSUL;
331 break;
332 default:
333 return -EOPNOTSUPP;
334 }
335 break;
336 default:
337 return -EOPNOTSUPP;
338 }
339
340 err = regmap_read(data->regmap, reg, ®val);
341 if (err < 0)
342 return err;
343
344 switch (attr) {
345 case hwmon_in_input:
346 case hwmon_in_max:
347 case hwmon_in_min:
348 /* signed register, value in mV */
349 regval = (s16)regval;
350 if (channel == 0)
351 /* gain of 1 -> LSB / 4 */
352 *val = (regval * INA238_SHUNT_VOLTAGE_LSB) *
353 data->gain / (1000 * 4);
354 else
355 *val = (regval * data->config->bus_voltage_lsb) / 1000;
356 break;
357 case hwmon_in_max_alarm:
358 case hwmon_in_min_alarm:
359 *val = !!(regval & mask);
360 break;
361 }
362
363 return 0;
364}
365
366static int ina238_write_in(struct device *dev, u32 attr, int channel,
367 long val)
368{
369 struct ina238_data *data = dev_get_drvdata(dev);
370 int regval;
371
372 if (attr != hwmon_in_max && attr != hwmon_in_min)
373 return -EOPNOTSUPP;
374
375 /* convert decimal to register value */
376 switch (channel) {
377 case 0:
378 /* signed value, clamp to max range +/-163 mV */
379 regval = clamp_val(val, -163, 163);
380 regval = (regval * 1000 * 4) /
381 (INA238_SHUNT_VOLTAGE_LSB * data->gain);
382 regval = clamp_val(regval, S16_MIN, S16_MAX) & 0xffff;
383
384 switch (attr) {
385 case hwmon_in_max:
386 return regmap_write(data->regmap,
387 INA238_SHUNT_OVER_VOLTAGE, regval);
388 case hwmon_in_min:
389 return regmap_write(data->regmap,
390 INA238_SHUNT_UNDER_VOLTAGE, regval);
391 default:
392 return -EOPNOTSUPP;
393 }
394 case 1:
395 /* signed value, positive values only. Clamp to max 102.396 V */
396 regval = clamp_val(val, 0, 102396);
397 regval = (regval * 1000) / data->config->bus_voltage_lsb;
398 regval = clamp_val(regval, 0, S16_MAX);
399
400 switch (attr) {
401 case hwmon_in_max:
402 return regmap_write(data->regmap,
403 INA238_BUS_OVER_VOLTAGE, regval);
404 case hwmon_in_min:
405 return regmap_write(data->regmap,
406 INA238_BUS_UNDER_VOLTAGE, regval);
407 default:
408 return -EOPNOTSUPP;
409 }
410 default:
411 return -EOPNOTSUPP;
412 }
413}
414
415static int ina238_read_current(struct device *dev, u32 attr, long *val)
416{
417 struct ina238_data *data = dev_get_drvdata(dev);
418 int regval;
419 int err;
420
421 switch (attr) {
422 case hwmon_curr_input:
423 if (data->config->has_20bit_voltage_current) {
424 err = ina238_read_field_s20(data->client, INA238_CURRENT, ®val);
425 if (err)
426 return err;
427 } else {
428 err = regmap_read(data->regmap, INA238_CURRENT, ®val);
429 if (err < 0)
430 return err;
431 /* sign-extend */
432 regval = (s16)regval;
433 }
434
435 /* Signed register, fixed 1mA current lsb. result in mA */
436 *val = div_s64((s64)regval * INA238_FIXED_SHUNT * data->gain,
437 data->rshunt * 4);
438
439 /* Account for 4 bit offset */
440 if (data->config->has_20bit_voltage_current)
441 *val /= 16;
442 break;
443 default:
444 return -EOPNOTSUPP;
445 }
446
447 return 0;
448}
449
450static int ina238_read_power(struct device *dev, u32 attr, long *val)
451{
452 struct ina238_data *data = dev_get_drvdata(dev);
453 long long power;
454 int regval;
455 int err;
456
457 switch (attr) {
458 case hwmon_power_input:
459 err = ina238_read_reg24(data->client, INA238_POWER, ®val);
460 if (err)
461 return err;
462
463 /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
464 power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
465 data->config->power_calculate_factor, 4 * 100 * data->rshunt);
466 /* Clamp value to maximum value of long */
467 *val = clamp_val(power, 0, LONG_MAX);
468 break;
469 case hwmon_power_input_highest:
470 err = ina238_read_reg24(data->client, SQ52206_POWER_PEAK, ®val);
471 if (err)
472 return err;
473
474 /* Fixed 1mA lsb, scaled by 1000000 to have result in uW */
475 power = div_u64(regval * 1000ULL * INA238_FIXED_SHUNT * data->gain *
476 data->config->power_calculate_factor, 4 * 100 * data->rshunt);
477 /* Clamp value to maximum value of long */
478 *val = clamp_val(power, 0, LONG_MAX);
479 break;
480 case hwmon_power_max:
481 err = regmap_read(data->regmap, INA238_POWER_LIMIT, ®val);
482 if (err)
483 return err;
484
485 /*
486 * Truncated 24-bit compare register, lower 8-bits are
487 * truncated. Same conversion to/from uW as POWER register.
488 */
489 power = div_u64((regval << 8) * 1000ULL * INA238_FIXED_SHUNT * data->gain *
490 data->config->power_calculate_factor, 4 * 100 * data->rshunt);
491 /* Clamp value to maximum value of long */
492 *val = clamp_val(power, 0, LONG_MAX);
493 break;
494 case hwmon_power_max_alarm:
495 err = regmap_read(data->regmap, INA238_DIAG_ALERT, ®val);
496 if (err)
497 return err;
498
499 *val = !!(regval & INA238_DIAG_ALERT_POL);
500 break;
501 default:
502 return -EOPNOTSUPP;
503 }
504
505 return 0;
506}
507
508static int ina238_write_power(struct device *dev, u32 attr, long val)
509{
510 struct ina238_data *data = dev_get_drvdata(dev);
511 long regval;
512
513 if (attr != hwmon_power_max)
514 return -EOPNOTSUPP;
515
516 /*
517 * Unsigned postive values. Compared against the 24-bit power register,
518 * lower 8-bits are truncated. Same conversion to/from uW as POWER
519 * register.
520 * The first clamp_val() is to establish a baseline to avoid overflows.
521 */
522 regval = clamp_val(val, 0, LONG_MAX / 2);
523 regval = div_u64(regval * 4 * 100 * data->rshunt, data->config->power_calculate_factor *
524 1000ULL * INA238_FIXED_SHUNT * data->gain);
525 regval = clamp_val(regval >> 8, 0, U16_MAX);
526
527 return regmap_write(data->regmap, INA238_POWER_LIMIT, regval);
528}
529
530static int ina238_read_temp(struct device *dev, u32 attr, long *val)
531{
532 struct ina238_data *data = dev_get_drvdata(dev);
533 int regval;
534 int err;
535
536 switch (attr) {
537 case hwmon_temp_input:
538 err = regmap_read(data->regmap, INA238_DIE_TEMP, ®val);
539 if (err)
540 return err;
541 /* Signed, result in mC */
542 *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
543 (s64)data->config->temp_lsb, 10000);
544 break;
545 case hwmon_temp_max:
546 err = regmap_read(data->regmap, INA238_TEMP_LIMIT, ®val);
547 if (err)
548 return err;
549 /* Signed, result in mC */
550 *val = div_s64(((s64)((s16)regval) >> data->config->temp_shift) *
551 (s64)data->config->temp_lsb, 10000);
552 break;
553 case hwmon_temp_max_alarm:
554 err = regmap_read(data->regmap, INA238_DIAG_ALERT, ®val);
555 if (err)
556 return err;
557
558 *val = !!(regval & INA238_DIAG_ALERT_TMPOL);
559 break;
560 default:
561 return -EOPNOTSUPP;
562 }
563
564 return 0;
565}
566
567static int ina238_write_temp(struct device *dev, u32 attr, long val)
568{
569 struct ina238_data *data = dev_get_drvdata(dev);
570 int regval;
571
572 if (attr != hwmon_temp_max)
573 return -EOPNOTSUPP;
574
575 /* Signed */
576 val = clamp_val(val, -40000, 125000);
577 regval = div_s64(val * 10000, data->config->temp_lsb) << data->config->temp_shift;
578 regval = clamp_val(regval, S16_MIN, S16_MAX) & (0xffff << data->config->temp_shift);
579
580 return regmap_write(data->regmap, INA238_TEMP_LIMIT, regval);
581}
582
583static ssize_t energy1_input_show(struct device *dev,
584 struct device_attribute *da, char *buf)
585{
586 struct ina238_data *data = dev_get_drvdata(dev);
587 int ret;
588 u64 regval;
589 u64 energy;
590
591 ret = ina238_read_reg40(data->client, SQ52206_ENERGY, ®val);
592 if (ret)
593 return ret;
594
595 /* result in uJ */
596 energy = div_u64(regval * INA238_FIXED_SHUNT * data->gain * 16 * 10 *
597 data->config->power_calculate_factor, 4 * data->rshunt);
598
599 return sysfs_emit(buf, "%llu\n", energy);
600}
601
602static int ina238_read(struct device *dev, enum hwmon_sensor_types type,
603 u32 attr, int channel, long *val)
604{
605 switch (type) {
606 case hwmon_in:
607 return ina238_read_in(dev, attr, channel, val);
608 case hwmon_curr:
609 return ina238_read_current(dev, attr, val);
610 case hwmon_power:
611 return ina238_read_power(dev, attr, val);
612 case hwmon_temp:
613 return ina238_read_temp(dev, attr, val);
614 default:
615 return -EOPNOTSUPP;
616 }
617 return 0;
618}
619
620static int ina238_write(struct device *dev, enum hwmon_sensor_types type,
621 u32 attr, int channel, long val)
622{
623 struct ina238_data *data = dev_get_drvdata(dev);
624 int err;
625
626 mutex_lock(&data->config_lock);
627
628 switch (type) {
629 case hwmon_in:
630 err = ina238_write_in(dev, attr, channel, val);
631 break;
632 case hwmon_power:
633 err = ina238_write_power(dev, attr, val);
634 break;
635 case hwmon_temp:
636 err = ina238_write_temp(dev, attr, val);
637 break;
638 default:
639 err = -EOPNOTSUPP;
640 break;
641 }
642
643 mutex_unlock(&data->config_lock);
644 return err;
645}
646
647static umode_t ina238_is_visible(const void *drvdata,
648 enum hwmon_sensor_types type,
649 u32 attr, int channel)
650{
651 const struct ina238_data *data = drvdata;
652 bool has_power_highest = data->config->has_power_highest;
653
654 switch (type) {
655 case hwmon_in:
656 switch (attr) {
657 case hwmon_in_input:
658 case hwmon_in_max_alarm:
659 case hwmon_in_min_alarm:
660 return 0444;
661 case hwmon_in_max:
662 case hwmon_in_min:
663 return 0644;
664 default:
665 return 0;
666 }
667 case hwmon_curr:
668 switch (attr) {
669 case hwmon_curr_input:
670 return 0444;
671 default:
672 return 0;
673 }
674 case hwmon_power:
675 switch (attr) {
676 case hwmon_power_input:
677 case hwmon_power_max_alarm:
678 return 0444;
679 case hwmon_power_max:
680 return 0644;
681 case hwmon_power_input_highest:
682 if (has_power_highest)
683 return 0444;
684 return 0;
685 default:
686 return 0;
687 }
688 case hwmon_temp:
689 switch (attr) {
690 case hwmon_temp_input:
691 case hwmon_temp_max_alarm:
692 return 0444;
693 case hwmon_temp_max:
694 return 0644;
695 default:
696 return 0;
697 }
698 default:
699 return 0;
700 }
701}
702
703#define INA238_HWMON_IN_CONFIG (HWMON_I_INPUT | \
704 HWMON_I_MAX | HWMON_I_MAX_ALARM | \
705 HWMON_I_MIN | HWMON_I_MIN_ALARM)
706
707static const struct hwmon_channel_info * const ina238_info[] = {
708 HWMON_CHANNEL_INFO(in,
709 /* 0: shunt voltage */
710 INA238_HWMON_IN_CONFIG,
711 /* 1: bus voltage */
712 INA238_HWMON_IN_CONFIG),
713 HWMON_CHANNEL_INFO(curr,
714 /* 0: current through shunt */
715 HWMON_C_INPUT),
716 HWMON_CHANNEL_INFO(power,
717 /* 0: power */
718 HWMON_P_INPUT | HWMON_P_MAX |
719 HWMON_P_MAX_ALARM | HWMON_P_INPUT_HIGHEST),
720 HWMON_CHANNEL_INFO(temp,
721 /* 0: die temperature */
722 HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_ALARM),
723 NULL
724};
725
726static const struct hwmon_ops ina238_hwmon_ops = {
727 .is_visible = ina238_is_visible,
728 .read = ina238_read,
729 .write = ina238_write,
730};
731
732static const struct hwmon_chip_info ina238_chip_info = {
733 .ops = &ina238_hwmon_ops,
734 .info = ina238_info,
735};
736
737/* energy attributes are 5 bytes wide so we need u64 */
738static DEVICE_ATTR_RO(energy1_input);
739
740static struct attribute *ina238_attrs[] = {
741 &dev_attr_energy1_input.attr,
742 NULL,
743};
744ATTRIBUTE_GROUPS(ina238);
745
746static int ina238_probe(struct i2c_client *client)
747{
748 struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev);
749 struct device *dev = &client->dev;
750 struct device *hwmon_dev;
751 struct ina238_data *data;
752 enum ina238_ids chip;
753 int config;
754 int ret;
755
756 chip = (uintptr_t)i2c_get_match_data(client);
757
758 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
759 if (!data)
760 return -ENOMEM;
761
762 data->client = client;
763 /* set the device type */
764 data->config = &ina238_config[chip];
765
766 mutex_init(&data->config_lock);
767
768 data->regmap = devm_regmap_init_i2c(client, &ina238_regmap_config);
769 if (IS_ERR(data->regmap)) {
770 dev_err(dev, "failed to allocate register map\n");
771 return PTR_ERR(data->regmap);
772 }
773
774 /* load shunt value */
775 data->rshunt = INA238_RSHUNT_DEFAULT;
776 if (device_property_read_u32(dev, "shunt-resistor", &data->rshunt) < 0 && pdata)
777 data->rshunt = pdata->shunt_uohms;
778 if (data->rshunt == 0) {
779 dev_err(dev, "invalid shunt resister value %u\n", data->rshunt);
780 return -EINVAL;
781 }
782
783 /* load shunt gain value */
784 if (device_property_read_u32(dev, "ti,shunt-gain", &data->gain) < 0)
785 data->gain = 4; /* Default of ADCRANGE = 0 */
786 if (data->gain != 1 && data->gain != 2 && data->gain != 4) {
787 dev_err(dev, "invalid shunt gain value %u\n", data->gain);
788 return -EINVAL;
789 }
790
791 /* Setup CONFIG register */
792 config = data->config->config_default;
793 if (chip == sq52206) {
794 if (data->gain == 1)
795 config |= SQ52206_CONFIG_ADCRANGE_HIGH; /* ADCRANGE = 10/11 is /1 */
796 else if (data->gain == 2)
797 config |= SQ52206_CONFIG_ADCRANGE_LOW; /* ADCRANGE = 01 is /2 */
798 } else if (data->gain == 1) {
799 config |= INA238_CONFIG_ADCRANGE; /* ADCRANGE = 1 is /1 */
800 }
801 ret = regmap_write(data->regmap, INA238_CONFIG, config);
802 if (ret < 0) {
803 dev_err(dev, "error configuring the device: %d\n", ret);
804 return -ENODEV;
805 }
806
807 /* Setup ADC_CONFIG register */
808 ret = regmap_write(data->regmap, INA238_ADC_CONFIG,
809 INA238_ADC_CONFIG_DEFAULT);
810 if (ret < 0) {
811 dev_err(dev, "error configuring the device: %d\n", ret);
812 return -ENODEV;
813 }
814
815 /* Setup SHUNT_CALIBRATION register with fixed value */
816 ret = regmap_write(data->regmap, INA238_SHUNT_CALIBRATION,
817 INA238_CALIBRATION_VALUE);
818 if (ret < 0) {
819 dev_err(dev, "error configuring the device: %d\n", ret);
820 return -ENODEV;
821 }
822
823 /* Setup alert/alarm configuration */
824 ret = regmap_write(data->regmap, INA238_DIAG_ALERT,
825 INA238_DIAG_ALERT_DEFAULT);
826 if (ret < 0) {
827 dev_err(dev, "error configuring the device: %d\n", ret);
828 return -ENODEV;
829 }
830
831 hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
832 &ina238_chip_info,
833 data->config->has_energy ?
834 ina238_groups : NULL);
835 if (IS_ERR(hwmon_dev))
836 return PTR_ERR(hwmon_dev);
837
838 dev_info(dev, "power monitor %s (Rshunt = %u uOhm, gain = %u)\n",
839 client->name, data->rshunt, data->gain);
840
841 return 0;
842}
843
844static const struct i2c_device_id ina238_id[] = {
845 { "ina228", ina228 },
846 { "ina237", ina237 },
847 { "ina238", ina238 },
848 { "sq52206", sq52206 },
849 { }
850};
851MODULE_DEVICE_TABLE(i2c, ina238_id);
852
853static const struct of_device_id __maybe_unused ina238_of_match[] = {
854 {
855 .compatible = "ti,ina228",
856 .data = (void *)ina228
857 },
858 {
859 .compatible = "ti,ina237",
860 .data = (void *)ina237
861 },
862 {
863 .compatible = "ti,ina238",
864 .data = (void *)ina238
865 },
866 {
867 .compatible = "silergy,sq52206",
868 .data = (void *)sq52206
869 },
870 { }
871};
872MODULE_DEVICE_TABLE(of, ina238_of_match);
873
874static struct i2c_driver ina238_driver = {
875 .driver = {
876 .name = "ina238",
877 .of_match_table = of_match_ptr(ina238_of_match),
878 },
879 .probe = ina238_probe,
880 .id_table = ina238_id,
881};
882
883module_i2c_driver(ina238_driver);
884
885MODULE_AUTHOR("Nathan Rossi <nathan.rossi@digi.com>");
886MODULE_DESCRIPTION("ina238 driver");
887MODULE_LICENSE("GPL");