Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: Driver for Texas Instruments INA238

The INA238 is a I2C power monitor similar to other INA2xx devices,
providing shunt voltage, bus voltage, current, power and temperature
measurements.

Signed-off-by: Nathan Rossi <nathan.rossi@digi.com>
Link: https://lore.kernel.org/r/20211102052754.817220-3-nathan@nathanrossi.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

Nathan Rossi and committed by
Guenter Roeck
eacb52f0 8be23b9b

+714
+56
Documentation/hwmon/ina238.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-only 2 + 3 + Kernel driver ina238 4 + ==================== 5 + 6 + Supported chips: 7 + 8 + * Texas Instruments INA238 9 + 10 + Prefix: 'ina238' 11 + 12 + Addresses: I2C 0x40 - 0x4f 13 + 14 + Datasheet: 15 + https://www.ti.com/lit/gpn/ina238 16 + 17 + Author: Nathan Rossi <nathan.rossi@digi.com> 18 + 19 + Description 20 + ----------- 21 + 22 + The INA238 is a current shunt, power and temperature monitor with an I2C 23 + interface. It includes a number of programmable functions including alerts, 24 + conversion rate, sample averaging and selectable shunt voltage accuracy. 25 + 26 + The shunt value in micro-ohms can be set via platform data or device tree at 27 + compile-time or via the shunt_resistor attribute in sysfs at run-time. Please 28 + refer to the Documentation/devicetree/bindings/hwmon/ti,ina2xx.yaml for bindings 29 + if the device tree is used. 30 + 31 + Sysfs entries 32 + ------------- 33 + 34 + ======================= ======================================================= 35 + in0_input Shunt voltage (mV) 36 + in0_min Minimum shunt voltage threshold (mV) 37 + in0_min_alarm Minimum shunt voltage alarm 38 + in0_max Maximum shunt voltage threshold (mV) 39 + in0_max_alarm Maximum shunt voltage alarm 40 + 41 + in1_input Bus voltage (mV) 42 + in1_min Minimum bus voltage threshold (mV) 43 + in1_min_alarm Minimum shunt voltage alarm 44 + in1_max Maximum bus voltage threshold (mV) 45 + in1_max_alarm Maximum shunt voltage alarm 46 + 47 + power1_input Power measurement (uW) 48 + power1_max Maximum power threshold (uW) 49 + power1_max_alarm Maximum power alarm 50 + 51 + curr1_input Current measurement (mA) 52 + 53 + temp1_input Die temperature measurement (mC) 54 + temp1_max Maximum die temperature threshold (mC) 55 + temp1_max_alarm Maximum die temperature alarm 56 + ======================= =======================================================
+1
Documentation/hwmon/index.rst
··· 76 76 ibmpowernv 77 77 ina209 78 78 ina2xx 79 + ina238 79 80 ina3221 80 81 intel-m10-bmc-hwmon 81 82 ir35221
+12
drivers/hwmon/Kconfig
··· 1872 1872 This driver can also be built as a module. If so, the module 1873 1873 will be called ina2xx. 1874 1874 1875 + config SENSORS_INA238 1876 + tristate "Texas Instruments INA238" 1877 + depends on I2C 1878 + select REGMAP_I2C 1879 + help 1880 + If you say yes here you get support for the INA238 power monitor 1881 + chip. This driver supports voltage, current, power and temperature 1882 + measurements as well as alarm configuration. 1883 + 1884 + This driver can also be built as a module. If so, the module 1885 + will be called ina238. 1886 + 1875 1887 config SENSORS_INA3221 1876 1888 tristate "Texas Instruments INA3221 Triple Power Monitor" 1877 1889 depends on I2C
+1
drivers/hwmon/Makefile
··· 90 90 obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o 91 91 obj-$(CONFIG_SENSORS_INA209) += ina209.o 92 92 obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o 93 + obj-$(CONFIG_SENSORS_INA238) += ina238.o 93 94 obj-$(CONFIG_SENSORS_INA3221) += ina3221.o 94 95 obj-$(CONFIG_SENSORS_INTEL_M10_BMC_HWMON) += intel-m10-bmc-hwmon.o 95 96 obj-$(CONFIG_SENSORS_IT87) += it87.o
+644
drivers/hwmon/ina238.c
··· 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");