]>
Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f7c2fe38 FL |
2 | /* |
3 | * Driver for Texas Instruments INA219, INA226 power monitor chips | |
4 | * | |
5 | * INA219: | |
6 | * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface | |
49dc2fb0 | 7 | * Datasheet: https://www.ti.com/product/ina219 |
f7c2fe38 | 8 | * |
dc92cd0c GR |
9 | * INA220: |
10 | * Bi-Directional Current/Power Monitor with I2C Interface | |
49dc2fb0 | 11 | * Datasheet: https://www.ti.com/product/ina220 |
dc92cd0c | 12 | * |
f7c2fe38 FL |
13 | * INA226: |
14 | * Bi-Directional Current/Power Monitor with I2C Interface | |
49dc2fb0 | 15 | * Datasheet: https://www.ti.com/product/ina226 |
f7c2fe38 | 16 | * |
dc92cd0c GR |
17 | * INA230: |
18 | * Bi-directional Current/Power Monitor with I2C Interface | |
49dc2fb0 | 19 | * Datasheet: https://www.ti.com/product/ina230 |
dc92cd0c | 20 | * |
3ad86700 | 21 | * Copyright (C) 2012 Lothar Felten <lothar.felten@gmail.com> |
f7c2fe38 | 22 | * Thanks to Jan Volkering |
f7c2fe38 FL |
23 | */ |
24 | ||
25 | #include <linux/kernel.h> | |
26 | #include <linux/module.h> | |
27 | #include <linux/init.h> | |
28 | #include <linux/err.h> | |
29 | #include <linux/slab.h> | |
30 | #include <linux/i2c.h> | |
31 | #include <linux/hwmon.h> | |
32 | #include <linux/hwmon-sysfs.h> | |
dcd8f392 | 33 | #include <linux/jiffies.h> |
bd0ddd4d | 34 | #include <linux/of_device.h> |
31e7ad74 | 35 | #include <linux/of.h> |
509416a8 | 36 | #include <linux/delay.h> |
d38df34e | 37 | #include <linux/util_macros.h> |
a0de56c8 | 38 | #include <linux/regmap.h> |
f7c2fe38 FL |
39 | |
40 | #include <linux/platform_data/ina2xx.h> | |
41 | ||
42 | /* common register definitions */ | |
43 | #define INA2XX_CONFIG 0x00 | |
44 | #define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */ | |
45 | #define INA2XX_BUS_VOLTAGE 0x02 /* readonly */ | |
46 | #define INA2XX_POWER 0x03 /* readonly */ | |
47 | #define INA2XX_CURRENT 0x04 /* readonly */ | |
48 | #define INA2XX_CALIBRATION 0x05 | |
49 | ||
50 | /* INA226 register definitions */ | |
51 | #define INA226_MASK_ENABLE 0x06 | |
52 | #define INA226_ALERT_LIMIT 0x07 | |
53 | #define INA226_DIE_ID 0xFF | |
54 | ||
f7c2fe38 FL |
55 | /* register count */ |
56 | #define INA219_REGISTERS 6 | |
57 | #define INA226_REGISTERS 8 | |
58 | ||
59 | #define INA2XX_MAX_REGISTERS 8 | |
60 | ||
61 | /* settings - depend on use case */ | |
62 | #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ | |
63 | #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ | |
64 | ||
65 | /* worst case is 68.10 ms (~14.6Hz, ina219) */ | |
66 | #define INA2XX_CONVERSION_RATE 15 | |
509416a8 BG |
67 | #define INA2XX_MAX_DELAY 69 /* worst case delay in ms */ |
68 | ||
69 | #define INA2XX_RSHUNT_DEFAULT 10000 | |
f7c2fe38 | 70 | |
72a87a47 BG |
71 | /* bit mask for reading the averaging setting in the configuration register */ |
72 | #define INA226_AVG_RD_MASK 0x0E00 | |
73 | ||
74 | #define INA226_READ_AVG(reg) (((reg) & INA226_AVG_RD_MASK) >> 9) | |
75 | #define INA226_SHIFT_AVG(val) ((val) << 9) | |
76 | ||
5a56a39b AQ |
77 | /* bit number of alert functions in Mask/Enable Register */ |
78 | #define INA226_SHUNT_OVER_VOLTAGE_BIT 15 | |
79 | #define INA226_SHUNT_UNDER_VOLTAGE_BIT 14 | |
80 | #define INA226_BUS_OVER_VOLTAGE_BIT 13 | |
81 | #define INA226_BUS_UNDER_VOLTAGE_BIT 12 | |
82 | #define INA226_POWER_OVER_LIMIT_BIT 11 | |
83 | ||
84 | /* bit mask for alert config bits of Mask/Enable Register */ | |
85 | #define INA226_ALERT_CONFIG_MASK 0xFC00 | |
86 | #define INA226_ALERT_FUNCTION_FLAG BIT(4) | |
87 | ||
72a87a47 BG |
88 | /* common attrs, ina226 attrs and NULL */ |
89 | #define INA2XX_MAX_ATTRIBUTE_GROUPS 3 | |
90 | ||
91 | /* | |
92 | * Both bus voltage and shunt voltage conversion times for ina226 are set | |
93 | * to 0b0100 on POR, which translates to 2200 microseconds in total. | |
94 | */ | |
95 | #define INA226_TOTAL_CONV_TIME_DEFAULT 2200 | |
96 | ||
a0de56c8 MT |
97 | static struct regmap_config ina2xx_regmap_config = { |
98 | .reg_bits = 8, | |
99 | .val_bits = 16, | |
100 | }; | |
101 | ||
f7c2fe38 FL |
102 | enum ina2xx_ids { ina219, ina226 }; |
103 | ||
6106db25 GR |
104 | struct ina2xx_config { |
105 | u16 config_default; | |
5d389b12 | 106 | int calibration_value; |
6106db25 GR |
107 | int registers; |
108 | int shunt_div; | |
109 | int bus_voltage_shift; | |
110 | int bus_voltage_lsb; /* uV */ | |
5d389b12 | 111 | int power_lsb_factor; |
6106db25 GR |
112 | }; |
113 | ||
f7c2fe38 | 114 | struct ina2xx_data { |
6106db25 | 115 | const struct ina2xx_config *config; |
f7c2fe38 | 116 | |
509416a8 | 117 | long rshunt; |
5d389b12 MP |
118 | long current_lsb_uA; |
119 | long power_lsb_uW; | |
a0de56c8 MT |
120 | struct mutex config_lock; |
121 | struct regmap *regmap; | |
f7c2fe38 | 122 | |
72a87a47 | 123 | const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS]; |
f7c2fe38 FL |
124 | }; |
125 | ||
6106db25 GR |
126 | static const struct ina2xx_config ina2xx_config[] = { |
127 | [ina219] = { | |
128 | .config_default = INA219_CONFIG_DEFAULT, | |
5d389b12 | 129 | .calibration_value = 4096, |
6106db25 GR |
130 | .registers = INA219_REGISTERS, |
131 | .shunt_div = 100, | |
132 | .bus_voltage_shift = 3, | |
133 | .bus_voltage_lsb = 4000, | |
5d389b12 | 134 | .power_lsb_factor = 20, |
6106db25 GR |
135 | }, |
136 | [ina226] = { | |
137 | .config_default = INA226_CONFIG_DEFAULT, | |
5d389b12 | 138 | .calibration_value = 2048, |
6106db25 GR |
139 | .registers = INA226_REGISTERS, |
140 | .shunt_div = 400, | |
141 | .bus_voltage_shift = 0, | |
142 | .bus_voltage_lsb = 1250, | |
5d389b12 | 143 | .power_lsb_factor = 25, |
6106db25 GR |
144 | }, |
145 | }; | |
146 | ||
72a87a47 BG |
147 | /* |
148 | * Available averaging rates for ina226. The indices correspond with | |
149 | * the bit values expected by the chip (according to the ina226 datasheet, | |
150 | * table 3 AVG bit settings, found at | |
49dc2fb0 | 151 | * https://www.ti.com/lit/ds/symlink/ina226.pdf. |
72a87a47 BG |
152 | */ |
153 | static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 }; | |
154 | ||
72a87a47 BG |
155 | static int ina226_reg_to_interval(u16 config) |
156 | { | |
157 | int avg = ina226_avg_tab[INA226_READ_AVG(config)]; | |
158 | ||
159 | /* | |
160 | * Multiply the total conversion time by the number of averages. | |
161 | * Return the result in milliseconds. | |
162 | */ | |
163 | return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000); | |
164 | } | |
165 | ||
a0de56c8 MT |
166 | /* |
167 | * Return the new, shifted AVG field value of CONFIG register, | |
168 | * to use with regmap_update_bits | |
169 | */ | |
170 | static u16 ina226_interval_to_reg(int interval) | |
72a87a47 BG |
171 | { |
172 | int avg, avg_bits; | |
173 | ||
174 | avg = DIV_ROUND_CLOSEST(interval * 1000, | |
175 | INA226_TOTAL_CONV_TIME_DEFAULT); | |
d38df34e BG |
176 | avg_bits = find_closest(avg, ina226_avg_tab, |
177 | ARRAY_SIZE(ina226_avg_tab)); | |
72a87a47 | 178 | |
a0de56c8 | 179 | return INA226_SHIFT_AVG(avg_bits); |
72a87a47 BG |
180 | } |
181 | ||
5d389b12 MP |
182 | /* |
183 | * Calibration register is set to the best value, which eliminates | |
184 | * truncation errors on calculating current register in hardware. | |
185 | * According to datasheet (eq. 3) the best values are 2048 for | |
186 | * ina226 and 4096 for ina219. They are hardcoded as calibration_value. | |
187 | */ | |
8a5fc795 BG |
188 | static int ina2xx_calibrate(struct ina2xx_data *data) |
189 | { | |
5d389b12 MP |
190 | return regmap_write(data->regmap, INA2XX_CALIBRATION, |
191 | data->config->calibration_value); | |
8a5fc795 BG |
192 | } |
193 | ||
509416a8 BG |
194 | /* |
195 | * Initialize the configuration and calibration registers. | |
196 | */ | |
197 | static int ina2xx_init(struct ina2xx_data *data) | |
f7c2fe38 | 198 | { |
a0de56c8 MT |
199 | int ret = regmap_write(data->regmap, INA2XX_CONFIG, |
200 | data->config->config_default); | |
509416a8 BG |
201 | if (ret < 0) |
202 | return ret; | |
f7c2fe38 | 203 | |
8a5fc795 | 204 | return ina2xx_calibrate(data); |
509416a8 | 205 | } |
f7c2fe38 | 206 | |
a0de56c8 | 207 | static int ina2xx_read_reg(struct device *dev, int reg, unsigned int *regval) |
509416a8 BG |
208 | { |
209 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
a0de56c8 | 210 | int ret, retry; |
f7c2fe38 | 211 | |
a0de56c8 | 212 | dev_dbg(dev, "Starting register %d read\n", reg); |
f7c2fe38 | 213 | |
509416a8 | 214 | for (retry = 5; retry; retry--) { |
a0de56c8 MT |
215 | |
216 | ret = regmap_read(data->regmap, reg, regval); | |
217 | if (ret < 0) | |
218 | return ret; | |
219 | ||
220 | dev_dbg(dev, "read %d, val = 0x%04x\n", reg, *regval); | |
509416a8 BG |
221 | |
222 | /* | |
223 | * If the current value in the calibration register is 0, the | |
224 | * power and current registers will also remain at 0. In case | |
225 | * the chip has been reset let's check the calibration | |
226 | * register and reinitialize if needed. | |
a0de56c8 MT |
227 | * We do that extra read of the calibration register if there |
228 | * is some hint of a chip reset. | |
509416a8 | 229 | */ |
a0de56c8 MT |
230 | if (*regval == 0) { |
231 | unsigned int cal; | |
232 | ||
233 | ret = regmap_read(data->regmap, INA2XX_CALIBRATION, | |
234 | &cal); | |
235 | if (ret < 0) | |
236 | return ret; | |
237 | ||
238 | if (cal == 0) { | |
239 | dev_warn(dev, "chip not calibrated, reinitializing\n"); | |
240 | ||
241 | ret = ina2xx_init(data); | |
242 | if (ret < 0) | |
243 | return ret; | |
244 | /* | |
245 | * Let's make sure the power and current | |
246 | * registers have been updated before trying | |
247 | * again. | |
248 | */ | |
249 | msleep(INA2XX_MAX_DELAY); | |
250 | continue; | |
251 | } | |
509416a8 | 252 | } |
509416a8 | 253 | return 0; |
f7c2fe38 | 254 | } |
509416a8 BG |
255 | |
256 | /* | |
257 | * If we're here then although all write operations succeeded, the | |
258 | * chip still returns 0 in the calibration register. Nothing more we | |
259 | * can do here. | |
260 | */ | |
261 | dev_err(dev, "unable to reinitialize the chip\n"); | |
262 | return -ENODEV; | |
263 | } | |
264 | ||
a0de56c8 MT |
265 | static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, |
266 | unsigned int regval) | |
f7c2fe38 | 267 | { |
6106db25 | 268 | int val; |
f7c2fe38 FL |
269 | |
270 | switch (reg) { | |
271 | case INA2XX_SHUNT_VOLTAGE: | |
c0214f98 | 272 | /* signed register */ |
a0de56c8 | 273 | val = DIV_ROUND_CLOSEST((s16)regval, data->config->shunt_div); |
f7c2fe38 FL |
274 | break; |
275 | case INA2XX_BUS_VOLTAGE: | |
a0de56c8 | 276 | val = (regval >> data->config->bus_voltage_shift) |
6106db25 GR |
277 | * data->config->bus_voltage_lsb; |
278 | val = DIV_ROUND_CLOSEST(val, 1000); | |
f7c2fe38 FL |
279 | break; |
280 | case INA2XX_POWER: | |
5d389b12 | 281 | val = regval * data->power_lsb_uW; |
f7c2fe38 FL |
282 | break; |
283 | case INA2XX_CURRENT: | |
5d389b12 | 284 | /* signed register, result in mA */ |
38cd989e | 285 | val = (s16)regval * data->current_lsb_uA; |
5d389b12 | 286 | val = DIV_ROUND_CLOSEST(val, 1000); |
f7c2fe38 | 287 | break; |
8a5fc795 | 288 | case INA2XX_CALIBRATION: |
5d389b12 | 289 | val = regval; |
8a5fc795 | 290 | break; |
f7c2fe38 FL |
291 | default: |
292 | /* programmer goofed */ | |
293 | WARN_ON_ONCE(1); | |
294 | val = 0; | |
295 | break; | |
296 | } | |
297 | ||
298 | return val; | |
299 | } | |
300 | ||
6a0f234f | 301 | static ssize_t ina2xx_value_show(struct device *dev, |
f7c2fe38 FL |
302 | struct device_attribute *da, char *buf) |
303 | { | |
304 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | |
a0de56c8 MT |
305 | struct ina2xx_data *data = dev_get_drvdata(dev); |
306 | unsigned int regval; | |
f7c2fe38 | 307 | |
a0de56c8 MT |
308 | int err = ina2xx_read_reg(dev, attr->index, ®val); |
309 | ||
310 | if (err < 0) | |
311 | return err; | |
f7c2fe38 | 312 | |
6106db25 | 313 | return snprintf(buf, PAGE_SIZE, "%d\n", |
a0de56c8 | 314 | ina2xx_get_value(data, attr->index, regval)); |
f7c2fe38 FL |
315 | } |
316 | ||
5a56a39b AQ |
317 | static int ina226_reg_to_alert(struct ina2xx_data *data, u8 bit, u16 regval) |
318 | { | |
319 | int reg; | |
320 | ||
321 | switch (bit) { | |
322 | case INA226_SHUNT_OVER_VOLTAGE_BIT: | |
323 | case INA226_SHUNT_UNDER_VOLTAGE_BIT: | |
324 | reg = INA2XX_SHUNT_VOLTAGE; | |
325 | break; | |
326 | case INA226_BUS_OVER_VOLTAGE_BIT: | |
327 | case INA226_BUS_UNDER_VOLTAGE_BIT: | |
328 | reg = INA2XX_BUS_VOLTAGE; | |
329 | break; | |
330 | case INA226_POWER_OVER_LIMIT_BIT: | |
331 | reg = INA2XX_POWER; | |
332 | break; | |
333 | default: | |
334 | /* programmer goofed */ | |
335 | WARN_ON_ONCE(1); | |
336 | return 0; | |
337 | } | |
338 | ||
339 | return ina2xx_get_value(data, reg, regval); | |
340 | } | |
341 | ||
342 | /* | |
343 | * Turns alert limit values into register values. | |
344 | * Opposite of the formula in ina2xx_get_value(). | |
345 | */ | |
346 | static s16 ina226_alert_to_reg(struct ina2xx_data *data, u8 bit, int val) | |
347 | { | |
348 | switch (bit) { | |
349 | case INA226_SHUNT_OVER_VOLTAGE_BIT: | |
350 | case INA226_SHUNT_UNDER_VOLTAGE_BIT: | |
351 | val *= data->config->shunt_div; | |
352 | return clamp_val(val, SHRT_MIN, SHRT_MAX); | |
353 | case INA226_BUS_OVER_VOLTAGE_BIT: | |
354 | case INA226_BUS_UNDER_VOLTAGE_BIT: | |
355 | val = (val * 1000) << data->config->bus_voltage_shift; | |
356 | val = DIV_ROUND_CLOSEST(val, data->config->bus_voltage_lsb); | |
357 | return clamp_val(val, 0, SHRT_MAX); | |
358 | case INA226_POWER_OVER_LIMIT_BIT: | |
359 | val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW); | |
360 | return clamp_val(val, 0, USHRT_MAX); | |
361 | default: | |
362 | /* programmer goofed */ | |
363 | WARN_ON_ONCE(1); | |
364 | return 0; | |
365 | } | |
366 | } | |
367 | ||
368 | static ssize_t ina226_alert_show(struct device *dev, | |
369 | struct device_attribute *da, char *buf) | |
370 | { | |
371 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | |
372 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
373 | int regval; | |
374 | int val = 0; | |
375 | int ret; | |
376 | ||
377 | mutex_lock(&data->config_lock); | |
378 | ret = regmap_read(data->regmap, INA226_MASK_ENABLE, ®val); | |
379 | if (ret) | |
380 | goto abort; | |
381 | ||
382 | if (regval & BIT(attr->index)) { | |
383 | ret = regmap_read(data->regmap, INA226_ALERT_LIMIT, ®val); | |
384 | if (ret) | |
385 | goto abort; | |
386 | val = ina226_reg_to_alert(data, attr->index, regval); | |
387 | } | |
388 | ||
389 | ret = snprintf(buf, PAGE_SIZE, "%d\n", val); | |
390 | abort: | |
391 | mutex_unlock(&data->config_lock); | |
392 | return ret; | |
393 | } | |
394 | ||
395 | static ssize_t ina226_alert_store(struct device *dev, | |
396 | struct device_attribute *da, | |
397 | const char *buf, size_t count) | |
398 | { | |
399 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | |
400 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
401 | unsigned long val; | |
402 | int ret; | |
403 | ||
404 | ret = kstrtoul(buf, 10, &val); | |
405 | if (ret < 0) | |
406 | return ret; | |
407 | ||
408 | /* | |
409 | * Clear all alerts first to avoid accidentally triggering ALERT pin | |
410 | * due to register write sequence. Then, only enable the alert | |
411 | * if the value is non-zero. | |
412 | */ | |
413 | mutex_lock(&data->config_lock); | |
414 | ret = regmap_update_bits(data->regmap, INA226_MASK_ENABLE, | |
415 | INA226_ALERT_CONFIG_MASK, 0); | |
416 | if (ret < 0) | |
417 | goto abort; | |
418 | ||
419 | ret = regmap_write(data->regmap, INA226_ALERT_LIMIT, | |
420 | ina226_alert_to_reg(data, attr->index, val)); | |
421 | if (ret < 0) | |
422 | goto abort; | |
423 | ||
424 | if (val != 0) { | |
425 | ret = regmap_update_bits(data->regmap, INA226_MASK_ENABLE, | |
426 | INA226_ALERT_CONFIG_MASK, | |
427 | BIT(attr->index)); | |
428 | if (ret < 0) | |
429 | goto abort; | |
430 | } | |
431 | ||
432 | ret = count; | |
433 | abort: | |
434 | mutex_unlock(&data->config_lock); | |
435 | return ret; | |
436 | } | |
437 | ||
438 | static ssize_t ina226_alarm_show(struct device *dev, | |
439 | struct device_attribute *da, char *buf) | |
440 | { | |
441 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | |
442 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
443 | int regval; | |
444 | int alarm = 0; | |
445 | int ret; | |
446 | ||
447 | ret = regmap_read(data->regmap, INA226_MASK_ENABLE, ®val); | |
448 | if (ret) | |
449 | return ret; | |
450 | ||
451 | alarm = (regval & BIT(attr->index)) && | |
452 | (regval & INA226_ALERT_FUNCTION_FLAG); | |
453 | return snprintf(buf, PAGE_SIZE, "%d\n", alarm); | |
454 | } | |
455 | ||
5d389b12 MP |
456 | /* |
457 | * In order to keep calibration register value fixed, the product | |
458 | * of current_lsb and shunt_resistor should also be fixed and equal | |
459 | * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order | |
460 | * to keep the scale. | |
461 | */ | |
462 | static int ina2xx_set_shunt(struct ina2xx_data *data, long val) | |
463 | { | |
464 | unsigned int dividend = DIV_ROUND_CLOSEST(1000000000, | |
465 | data->config->shunt_div); | |
466 | if (val <= 0 || val > dividend) | |
467 | return -EINVAL; | |
468 | ||
469 | mutex_lock(&data->config_lock); | |
470 | data->rshunt = val; | |
471 | data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val); | |
472 | data->power_lsb_uW = data->config->power_lsb_factor * | |
473 | data->current_lsb_uA; | |
474 | mutex_unlock(&data->config_lock); | |
475 | ||
476 | return 0; | |
477 | } | |
478 | ||
6a0f234f GR |
479 | static ssize_t ina2xx_shunt_show(struct device *dev, |
480 | struct device_attribute *da, char *buf) | |
3ad86700 LF |
481 | { |
482 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
483 | ||
484 | return snprintf(buf, PAGE_SIZE, "%li\n", data->rshunt); | |
485 | } | |
486 | ||
6a0f234f | 487 | static ssize_t ina2xx_shunt_store(struct device *dev, |
5d389b12 MP |
488 | struct device_attribute *da, |
489 | const char *buf, size_t count) | |
8a5fc795 | 490 | { |
8a5fc795 BG |
491 | unsigned long val; |
492 | int status; | |
a0de56c8 | 493 | struct ina2xx_data *data = dev_get_drvdata(dev); |
8a5fc795 BG |
494 | |
495 | status = kstrtoul(buf, 10, &val); | |
496 | if (status < 0) | |
497 | return status; | |
498 | ||
5d389b12 | 499 | status = ina2xx_set_shunt(data, val); |
8a5fc795 BG |
500 | if (status < 0) |
501 | return status; | |
8a5fc795 BG |
502 | return count; |
503 | } | |
504 | ||
6a0f234f GR |
505 | static ssize_t ina226_interval_store(struct device *dev, |
506 | struct device_attribute *da, | |
507 | const char *buf, size_t count) | |
72a87a47 BG |
508 | { |
509 | struct ina2xx_data *data = dev_get_drvdata(dev); | |
510 | unsigned long val; | |
511 | int status; | |
512 | ||
72a87a47 BG |
513 | status = kstrtoul(buf, 10, &val); |
514 | if (status < 0) | |
515 | return status; | |
516 | ||
517 | if (val > INT_MAX || val == 0) | |
518 | return -EINVAL; | |
519 | ||
a0de56c8 MT |
520 | status = regmap_update_bits(data->regmap, INA2XX_CONFIG, |
521 | INA226_AVG_RD_MASK, | |
522 | ina226_interval_to_reg(val)); | |
72a87a47 BG |
523 | if (status < 0) |
524 | return status; | |
525 | ||
526 | return count; | |
527 | } | |
528 | ||
6a0f234f | 529 | static ssize_t ina226_interval_show(struct device *dev, |
72a87a47 BG |
530 | struct device_attribute *da, char *buf) |
531 | { | |
a0de56c8 MT |
532 | struct ina2xx_data *data = dev_get_drvdata(dev); |
533 | int status; | |
534 | unsigned int regval; | |
72a87a47 | 535 | |
a0de56c8 MT |
536 | status = regmap_read(data->regmap, INA2XX_CONFIG, ®val); |
537 | if (status) | |
538 | return status; | |
72a87a47 | 539 | |
a0de56c8 | 540 | return snprintf(buf, PAGE_SIZE, "%d\n", ina226_reg_to_interval(regval)); |
72a87a47 BG |
541 | } |
542 | ||
f7c2fe38 | 543 | /* shunt voltage */ |
6a0f234f | 544 | static SENSOR_DEVICE_ATTR_RO(in0_input, ina2xx_value, INA2XX_SHUNT_VOLTAGE); |
5a56a39b AQ |
545 | /* shunt voltage over/under voltage alert setting and alarm */ |
546 | static SENSOR_DEVICE_ATTR_RW(in0_crit, ina226_alert, | |
547 | INA226_SHUNT_OVER_VOLTAGE_BIT); | |
548 | static SENSOR_DEVICE_ATTR_RW(in0_lcrit, ina226_alert, | |
549 | INA226_SHUNT_UNDER_VOLTAGE_BIT); | |
550 | static SENSOR_DEVICE_ATTR_RO(in0_crit_alarm, ina226_alarm, | |
551 | INA226_SHUNT_OVER_VOLTAGE_BIT); | |
552 | static SENSOR_DEVICE_ATTR_RO(in0_lcrit_alarm, ina226_alarm, | |
553 | INA226_SHUNT_UNDER_VOLTAGE_BIT); | |
f7c2fe38 FL |
554 | |
555 | /* bus voltage */ | |
6a0f234f | 556 | static SENSOR_DEVICE_ATTR_RO(in1_input, ina2xx_value, INA2XX_BUS_VOLTAGE); |
5a56a39b AQ |
557 | /* bus voltage over/under voltage alert setting and alarm */ |
558 | static SENSOR_DEVICE_ATTR_RW(in1_crit, ina226_alert, | |
559 | INA226_BUS_OVER_VOLTAGE_BIT); | |
560 | static SENSOR_DEVICE_ATTR_RW(in1_lcrit, ina226_alert, | |
561 | INA226_BUS_UNDER_VOLTAGE_BIT); | |
562 | static SENSOR_DEVICE_ATTR_RO(in1_crit_alarm, ina226_alarm, | |
563 | INA226_BUS_OVER_VOLTAGE_BIT); | |
564 | static SENSOR_DEVICE_ATTR_RO(in1_lcrit_alarm, ina226_alarm, | |
565 | INA226_BUS_UNDER_VOLTAGE_BIT); | |
f7c2fe38 FL |
566 | |
567 | /* calculated current */ | |
6a0f234f | 568 | static SENSOR_DEVICE_ATTR_RO(curr1_input, ina2xx_value, INA2XX_CURRENT); |
f7c2fe38 FL |
569 | |
570 | /* calculated power */ | |
6a0f234f | 571 | static SENSOR_DEVICE_ATTR_RO(power1_input, ina2xx_value, INA2XX_POWER); |
5a56a39b AQ |
572 | /* over-limit power alert setting and alarm */ |
573 | static SENSOR_DEVICE_ATTR_RW(power1_crit, ina226_alert, | |
574 | INA226_POWER_OVER_LIMIT_BIT); | |
575 | static SENSOR_DEVICE_ATTR_RO(power1_crit_alarm, ina226_alarm, | |
576 | INA226_POWER_OVER_LIMIT_BIT); | |
f7c2fe38 | 577 | |
8a5fc795 | 578 | /* shunt resistance */ |
6a0f234f | 579 | static SENSOR_DEVICE_ATTR_RW(shunt_resistor, ina2xx_shunt, INA2XX_CALIBRATION); |
8a5fc795 | 580 | |
72a87a47 | 581 | /* update interval (ina226 only) */ |
6a0f234f | 582 | static SENSOR_DEVICE_ATTR_RW(update_interval, ina226_interval, 0); |
72a87a47 | 583 | |
f7c2fe38 | 584 | /* pointers to created device attributes */ |
468bf0e3 | 585 | static struct attribute *ina2xx_attrs[] = { |
f7c2fe38 FL |
586 | &sensor_dev_attr_in0_input.dev_attr.attr, |
587 | &sensor_dev_attr_in1_input.dev_attr.attr, | |
588 | &sensor_dev_attr_curr1_input.dev_attr.attr, | |
589 | &sensor_dev_attr_power1_input.dev_attr.attr, | |
8a5fc795 | 590 | &sensor_dev_attr_shunt_resistor.dev_attr.attr, |
f7c2fe38 FL |
591 | NULL, |
592 | }; | |
72a87a47 BG |
593 | |
594 | static const struct attribute_group ina2xx_group = { | |
595 | .attrs = ina2xx_attrs, | |
596 | }; | |
597 | ||
598 | static struct attribute *ina226_attrs[] = { | |
5a56a39b AQ |
599 | &sensor_dev_attr_in0_crit.dev_attr.attr, |
600 | &sensor_dev_attr_in0_lcrit.dev_attr.attr, | |
601 | &sensor_dev_attr_in0_crit_alarm.dev_attr.attr, | |
602 | &sensor_dev_attr_in0_lcrit_alarm.dev_attr.attr, | |
603 | &sensor_dev_attr_in1_crit.dev_attr.attr, | |
604 | &sensor_dev_attr_in1_lcrit.dev_attr.attr, | |
605 | &sensor_dev_attr_in1_crit_alarm.dev_attr.attr, | |
606 | &sensor_dev_attr_in1_lcrit_alarm.dev_attr.attr, | |
607 | &sensor_dev_attr_power1_crit.dev_attr.attr, | |
608 | &sensor_dev_attr_power1_crit_alarm.dev_attr.attr, | |
72a87a47 BG |
609 | &sensor_dev_attr_update_interval.dev_attr.attr, |
610 | NULL, | |
611 | }; | |
612 | ||
613 | static const struct attribute_group ina226_group = { | |
614 | .attrs = ina226_attrs, | |
615 | }; | |
f7c2fe38 | 616 | |
67487038 SK |
617 | static const struct i2c_device_id ina2xx_id[]; |
618 | ||
619 | static int ina2xx_probe(struct i2c_client *client) | |
f7c2fe38 | 620 | { |
468bf0e3 GR |
621 | struct device *dev = &client->dev; |
622 | struct ina2xx_data *data; | |
623 | struct device *hwmon_dev; | |
468bf0e3 | 624 | u32 val; |
72a87a47 | 625 | int ret, group = 0; |
bd0ddd4d JMC |
626 | enum ina2xx_ids chip; |
627 | ||
628 | if (client->dev.of_node) | |
629 | chip = (enum ina2xx_ids)of_device_get_match_data(&client->dev); | |
630 | else | |
67487038 | 631 | chip = i2c_match_id(ina2xx_id, client)->driver_data; |
f7c2fe38 | 632 | |
468bf0e3 | 633 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
f7c2fe38 FL |
634 | if (!data) |
635 | return -ENOMEM; | |
636 | ||
f7c2fe38 | 637 | /* set the device type */ |
bd0ddd4d | 638 | data->config = &ina2xx_config[chip]; |
0c4c5860 | 639 | mutex_init(&data->config_lock); |
72a87a47 | 640 | |
001e2e73 MT |
641 | if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) { |
642 | struct ina2xx_platform_data *pdata = dev_get_platdata(dev); | |
643 | ||
644 | if (pdata) | |
645 | val = pdata->shunt_uohms; | |
646 | else | |
647 | val = INA2XX_RSHUNT_DEFAULT; | |
648 | } | |
649 | ||
5d389b12 | 650 | ina2xx_set_shunt(data, val); |
001e2e73 | 651 | |
a0de56c8 MT |
652 | ina2xx_regmap_config.max_register = data->config->registers; |
653 | ||
654 | data->regmap = devm_regmap_init_i2c(client, &ina2xx_regmap_config); | |
655 | if (IS_ERR(data->regmap)) { | |
656 | dev_err(dev, "failed to allocate register map\n"); | |
657 | return PTR_ERR(data->regmap); | |
658 | } | |
659 | ||
509416a8 | 660 | ret = ina2xx_init(data); |
f975b339 | 661 | if (ret < 0) { |
509416a8 | 662 | dev_err(dev, "error configuring the device: %d\n", ret); |
f975b339 BG |
663 | return -ENODEV; |
664 | } | |
f7c2fe38 | 665 | |
72a87a47 | 666 | data->groups[group++] = &ina2xx_group; |
70df9ebb | 667 | if (chip == ina226) |
72a87a47 BG |
668 | data->groups[group++] = &ina226_group; |
669 | ||
468bf0e3 | 670 | hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, |
72a87a47 | 671 | data, data->groups); |
468bf0e3 GR |
672 | if (IS_ERR(hwmon_dev)) |
673 | return PTR_ERR(hwmon_dev); | |
f7c2fe38 | 674 | |
468bf0e3 | 675 | dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n", |
70df9ebb | 676 | client->name, data->rshunt); |
6106db25 | 677 | |
f7c2fe38 | 678 | return 0; |
f7c2fe38 FL |
679 | } |
680 | ||
681 | static const struct i2c_device_id ina2xx_id[] = { | |
682 | { "ina219", ina219 }, | |
dc92cd0c | 683 | { "ina220", ina219 }, |
f7c2fe38 | 684 | { "ina226", ina226 }, |
dc92cd0c | 685 | { "ina230", ina226 }, |
add513be | 686 | { "ina231", ina226 }, |
f7c2fe38 FL |
687 | { } |
688 | }; | |
689 | MODULE_DEVICE_TABLE(i2c, ina2xx_id); | |
690 | ||
df6b8c70 | 691 | static const struct of_device_id __maybe_unused ina2xx_of_match[] = { |
bd0ddd4d JMC |
692 | { |
693 | .compatible = "ti,ina219", | |
694 | .data = (void *)ina219 | |
695 | }, | |
696 | { | |
697 | .compatible = "ti,ina220", | |
698 | .data = (void *)ina219 | |
699 | }, | |
700 | { | |
701 | .compatible = "ti,ina226", | |
702 | .data = (void *)ina226 | |
703 | }, | |
704 | { | |
705 | .compatible = "ti,ina230", | |
706 | .data = (void *)ina226 | |
707 | }, | |
708 | { | |
709 | .compatible = "ti,ina231", | |
710 | .data = (void *)ina226 | |
711 | }, | |
712 | { }, | |
713 | }; | |
714 | MODULE_DEVICE_TABLE(of, ina2xx_of_match); | |
715 | ||
f7c2fe38 FL |
716 | static struct i2c_driver ina2xx_driver = { |
717 | .driver = { | |
718 | .name = "ina2xx", | |
bd0ddd4d | 719 | .of_match_table = of_match_ptr(ina2xx_of_match), |
f7c2fe38 | 720 | }, |
67487038 | 721 | .probe_new = ina2xx_probe, |
f7c2fe38 FL |
722 | .id_table = ina2xx_id, |
723 | }; | |
724 | ||
d835ca0f | 725 | module_i2c_driver(ina2xx_driver); |
f7c2fe38 FL |
726 | |
727 | MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>"); | |
728 | MODULE_DESCRIPTION("ina2xx driver"); | |
729 | MODULE_LICENSE("GPL"); |