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

hwmon: INA219 and INA226 support

Add support for the Texas Instruments INA219 and INA226 power monitors.

Signed-off-by: Lothar Felten <l-felten@ti.com>
[guenter.roeck@ericsson.com: formatting cleanup; check for smbus word data;
select PGA=8 for INA219]
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>

authored by

Felten, Lothar and committed by
Guenter Roeck
f7c2fe38 9172b5d1

+430
+29
Documentation/hwmon/ina2xx
··· 1 + Kernel driver ina2xx 2 + ==================== 3 + 4 + Supported chips: 5 + * Texas Instruments INA219 6 + Prefix: 'ina219' 7 + Addresses: I2C 0x40 - 0x4f 8 + Datasheet: Publicly available at the Texas Instruments website 9 + http://www.ti.com/ 10 + 11 + * Texas Instruments INA226 12 + Prefix: 'ina226' 13 + Addresses: I2C 0x40 - 0x4f 14 + Datasheet: Publicly available at the Texas Instruments website 15 + http://www.ti.com/ 16 + 17 + Author: Lothar Felten <l-felten@ti.com> 18 + 19 + Description 20 + ----------- 21 + 22 + The INA219 is a high-side current shunt and power monitor with an I2C 23 + interface. The INA219 monitors both shunt drop and supply voltage, with 24 + programmable conversion times and filtering. 25 + 26 + The INA226 is a current shunt and power monitor with an I2C interface. 27 + The INA226 monitors both a shunt voltage drop and bus supply voltage. 28 + 29 + The shunt value in micro-ohms can be set via platform data.
+13
drivers/hwmon/Kconfig
··· 1102 1102 This driver can also be build as a module. If so, the module 1103 1103 will be called amc6821. 1104 1104 1105 + config SENSORS_INA2XX 1106 + tristate "Texas Instruments INA219, INA226" 1107 + depends on I2C && EXPERIMENTAL 1108 + help 1109 + If you say yes here you get support for INA219 and INA226 power 1110 + monitor chips. 1111 + 1112 + The INA2xx driver is configured for the default configuration of 1113 + the part as described in the datasheet. 1114 + Default value for Rshunt is 10 mOhms. 1115 + This driver can also be built as a module. If so, the module 1116 + will be called ina2xx. 1117 + 1105 1118 config SENSORS_THMC50 1106 1119 tristate "Texas Instruments THMC50 / Analog Devices ADM1022" 1107 1120 depends on I2C
+1
drivers/hwmon/Makefile
··· 62 62 obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 63 63 obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 64 64 obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 65 + obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o 65 66 obj-$(CONFIG_SENSORS_IT87) += it87.o 66 67 obj-$(CONFIG_SENSORS_JC42) += jc42.o 67 68 obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
+368
drivers/hwmon/ina2xx.c
··· 1 + /* 2 + * Driver for Texas Instruments INA219, INA226 power monitor chips 3 + * 4 + * INA219: 5 + * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface 6 + * Datasheet: http://www.ti.com/product/ina219 7 + * 8 + * INA226: 9 + * Bi-Directional Current/Power Monitor with I2C Interface 10 + * Datasheet: http://www.ti.com/product/ina226 11 + * 12 + * Copyright (C) 2012 Lothar Felten <l-felten@ti.com> 13 + * Thanks to Jan Volkering 14 + * 15 + * This program is free software; you can redistribute it and/or modify 16 + * it under the terms of the GNU General Public License as published by 17 + * the Free Software Foundation; version 2 of the License. 18 + */ 19 + 20 + #include <linux/kernel.h> 21 + #include <linux/module.h> 22 + #include <linux/init.h> 23 + #include <linux/err.h> 24 + #include <linux/slab.h> 25 + #include <linux/i2c.h> 26 + #include <linux/hwmon.h> 27 + #include <linux/hwmon-sysfs.h> 28 + 29 + #include <linux/platform_data/ina2xx.h> 30 + 31 + /* common register definitions */ 32 + #define INA2XX_CONFIG 0x00 33 + #define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */ 34 + #define INA2XX_BUS_VOLTAGE 0x02 /* readonly */ 35 + #define INA2XX_POWER 0x03 /* readonly */ 36 + #define INA2XX_CURRENT 0x04 /* readonly */ 37 + #define INA2XX_CALIBRATION 0x05 38 + 39 + /* INA226 register definitions */ 40 + #define INA226_MASK_ENABLE 0x06 41 + #define INA226_ALERT_LIMIT 0x07 42 + #define INA226_DIE_ID 0xFF 43 + 44 + 45 + /* register count */ 46 + #define INA219_REGISTERS 6 47 + #define INA226_REGISTERS 8 48 + 49 + #define INA2XX_MAX_REGISTERS 8 50 + 51 + /* settings - depend on use case */ 52 + #define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */ 53 + #define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */ 54 + 55 + /* worst case is 68.10 ms (~14.6Hz, ina219) */ 56 + #define INA2XX_CONVERSION_RATE 15 57 + 58 + enum ina2xx_ids { ina219, ina226 }; 59 + 60 + struct ina2xx_data { 61 + struct device *hwmon_dev; 62 + 63 + struct mutex update_lock; 64 + bool valid; 65 + unsigned long last_updated; 66 + 67 + int kind; 68 + int registers; 69 + u16 regs[INA2XX_MAX_REGISTERS]; 70 + }; 71 + 72 + int ina2xx_read_word(struct i2c_client *client, int reg) 73 + { 74 + int val = i2c_smbus_read_word_data(client, reg); 75 + if (unlikely(val < 0)) { 76 + dev_dbg(&client->dev, 77 + "Failed to read register: %d\n", reg); 78 + return val; 79 + } 80 + return be16_to_cpu(val); 81 + } 82 + 83 + void ina2xx_write_word(struct i2c_client *client, int reg, int data) 84 + { 85 + i2c_smbus_write_word_data(client, reg, cpu_to_be16(data)); 86 + } 87 + 88 + static struct ina2xx_data *ina2xx_update_device(struct device *dev) 89 + { 90 + struct i2c_client *client = to_i2c_client(dev); 91 + struct ina2xx_data *data = i2c_get_clientdata(client); 92 + struct ina2xx_data *ret = data; 93 + 94 + mutex_lock(&data->update_lock); 95 + 96 + if (time_after(jiffies, data->last_updated + 97 + HZ / INA2XX_CONVERSION_RATE) || !data->valid) { 98 + 99 + int i; 100 + 101 + dev_dbg(&client->dev, "Starting ina2xx update\n"); 102 + 103 + /* Read all registers */ 104 + for (i = 0; i < data->registers; i++) { 105 + int rv = ina2xx_read_word(client, i); 106 + if (rv < 0) { 107 + ret = ERR_PTR(rv); 108 + goto abort; 109 + } 110 + data->regs[i] = rv; 111 + } 112 + data->last_updated = jiffies; 113 + data->valid = 1; 114 + } 115 + abort: 116 + mutex_unlock(&data->update_lock); 117 + return ret; 118 + } 119 + 120 + static int ina219_get_value(struct ina2xx_data *data, u8 reg) 121 + { 122 + /* 123 + * calculate exact value for the given register 124 + * we assume default power-on reset settings: 125 + * bus voltage range 32V 126 + * gain = /8 127 + * adc 1 & 2 -> conversion time 532uS 128 + * mode is continuous shunt and bus 129 + * calibration value is INA219_CALIBRATION_VALUE 130 + */ 131 + int val = data->regs[reg]; 132 + 133 + switch (reg) { 134 + case INA2XX_SHUNT_VOLTAGE: 135 + /* LSB=10uV. Convert to mV. */ 136 + val = DIV_ROUND_CLOSEST(val, 100); 137 + break; 138 + case INA2XX_BUS_VOLTAGE: 139 + /* LSB=4mV. Register is not right aligned, convert to mV. */ 140 + val = (val >> 3) * 4; 141 + break; 142 + case INA2XX_POWER: 143 + /* LSB=20mW. Convert to uW */ 144 + val = val * 20 * 1000; 145 + break; 146 + case INA2XX_CURRENT: 147 + /* LSB=1mA (selected). Is in mA */ 148 + break; 149 + default: 150 + /* programmer goofed */ 151 + WARN_ON_ONCE(1); 152 + val = 0; 153 + break; 154 + } 155 + 156 + return val; 157 + } 158 + 159 + static int ina226_get_value(struct ina2xx_data *data, u8 reg) 160 + { 161 + /* 162 + * calculate exact value for the given register 163 + * we assume default power-on reset settings: 164 + * bus voltage range 32V 165 + * gain = /8 166 + * adc 1 & 2 -> conversion time 532uS 167 + * mode is continuous shunt and bus 168 + * calibration value is INA226_CALIBRATION_VALUE 169 + */ 170 + int val = data->regs[reg]; 171 + 172 + switch (reg) { 173 + case INA2XX_SHUNT_VOLTAGE: 174 + /* LSB=2.5uV. Convert to mV. */ 175 + val = DIV_ROUND_CLOSEST(val, 400); 176 + break; 177 + case INA2XX_BUS_VOLTAGE: 178 + /* LSB=1.25mV. Convert to mV. */ 179 + val = val + DIV_ROUND_CLOSEST(val, 4); 180 + break; 181 + case INA2XX_POWER: 182 + /* LSB=25mW. Convert to uW */ 183 + val = val * 25 * 1000; 184 + break; 185 + case INA2XX_CURRENT: 186 + /* LSB=1mA (selected). Is in mA */ 187 + break; 188 + default: 189 + /* programmer goofed */ 190 + WARN_ON_ONCE(1); 191 + val = 0; 192 + break; 193 + } 194 + 195 + return val; 196 + } 197 + 198 + static ssize_t ina2xx_show_value(struct device *dev, 199 + struct device_attribute *da, char *buf) 200 + { 201 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 202 + struct ina2xx_data *data = ina2xx_update_device(dev); 203 + int value = 0; 204 + 205 + if (IS_ERR(data)) 206 + return PTR_ERR(data); 207 + 208 + switch (data->kind) { 209 + case ina219: 210 + value = ina219_get_value(data, attr->index); 211 + break; 212 + case ina226: 213 + value = ina226_get_value(data, attr->index); 214 + break; 215 + default: 216 + WARN_ON_ONCE(1); 217 + break; 218 + } 219 + return snprintf(buf, PAGE_SIZE, "%d\n", value); 220 + } 221 + 222 + /* shunt voltage */ 223 + static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \ 224 + ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE); 225 + 226 + /* bus voltage */ 227 + static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \ 228 + ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE); 229 + 230 + /* calculated current */ 231 + static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \ 232 + ina2xx_show_value, NULL, INA2XX_CURRENT); 233 + 234 + /* calculated power */ 235 + static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \ 236 + ina2xx_show_value, NULL, INA2XX_POWER); 237 + 238 + /* pointers to created device attributes */ 239 + static struct attribute *ina2xx_attributes[] = { 240 + &sensor_dev_attr_in0_input.dev_attr.attr, 241 + &sensor_dev_attr_in1_input.dev_attr.attr, 242 + &sensor_dev_attr_curr1_input.dev_attr.attr, 243 + &sensor_dev_attr_power1_input.dev_attr.attr, 244 + NULL, 245 + }; 246 + 247 + static const struct attribute_group ina2xx_group = { 248 + .attrs = ina2xx_attributes, 249 + }; 250 + 251 + static int ina2xx_probe(struct i2c_client *client, 252 + const struct i2c_device_id *id) 253 + { 254 + struct i2c_adapter *adapter = client->adapter; 255 + struct ina2xx_data *data; 256 + struct ina2xx_platform_data *pdata; 257 + int ret = 0; 258 + long shunt = 10000; /* default shunt value 10mOhms */ 259 + 260 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) 261 + return -ENODEV; 262 + 263 + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 264 + if (!data) 265 + return -ENOMEM; 266 + 267 + if (client->dev.platform_data) { 268 + pdata = 269 + (struct ina2xx_platform_data *)client->dev.platform_data; 270 + shunt = pdata->shunt_uohms; 271 + } 272 + 273 + if (shunt <= 0) 274 + return -ENODEV; 275 + 276 + /* set the device type */ 277 + data->kind = id->driver_data; 278 + 279 + switch (data->kind) { 280 + case ina219: 281 + /* device configuration */ 282 + ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT); 283 + 284 + /* set current LSB to 1mA, shunt is in uOhms */ 285 + /* (equation 13 in datasheet) */ 286 + ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt); 287 + dev_info(&client->dev, 288 + "power monitor INA219 (Rshunt = %li uOhm)\n", shunt); 289 + data->registers = INA219_REGISTERS; 290 + break; 291 + case ina226: 292 + /* device configuration */ 293 + ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT); 294 + 295 + /* set current LSB to 1mA, shunt is in uOhms */ 296 + /* (equation 1 in datasheet)*/ 297 + ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt); 298 + dev_info(&client->dev, 299 + "power monitor INA226 (Rshunt = %li uOhm)\n", shunt); 300 + data->registers = INA226_REGISTERS; 301 + break; 302 + default: 303 + /* unknown device id */ 304 + return -ENODEV; 305 + } 306 + 307 + i2c_set_clientdata(client, data); 308 + mutex_init(&data->update_lock); 309 + 310 + ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group); 311 + if (ret) 312 + return ret; 313 + 314 + data->hwmon_dev = hwmon_device_register(&client->dev); 315 + if (IS_ERR(data->hwmon_dev)) { 316 + ret = PTR_ERR(data->hwmon_dev); 317 + goto out_err_hwmon; 318 + } 319 + 320 + return 0; 321 + 322 + out_err_hwmon: 323 + sysfs_remove_group(&client->dev.kobj, &ina2xx_group); 324 + return ret; 325 + } 326 + 327 + static int ina2xx_remove(struct i2c_client *client) 328 + { 329 + struct ina2xx_data *data = i2c_get_clientdata(client); 330 + 331 + hwmon_device_unregister(data->hwmon_dev); 332 + sysfs_remove_group(&client->dev.kobj, &ina2xx_group); 333 + 334 + return 0; 335 + } 336 + 337 + static const struct i2c_device_id ina2xx_id[] = { 338 + { "ina219", ina219 }, 339 + { "ina226", ina226 }, 340 + { } 341 + }; 342 + MODULE_DEVICE_TABLE(i2c, ina2xx_id); 343 + 344 + static struct i2c_driver ina2xx_driver = { 345 + .driver = { 346 + .name = "ina2xx", 347 + }, 348 + .probe = ina2xx_probe, 349 + .remove = ina2xx_remove, 350 + .id_table = ina2xx_id, 351 + }; 352 + 353 + static int __init ina2xx_init(void) 354 + { 355 + return i2c_add_driver(&ina2xx_driver); 356 + } 357 + 358 + static void __exit ina2xx_exit(void) 359 + { 360 + i2c_del_driver(&ina2xx_driver); 361 + } 362 + 363 + MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>"); 364 + MODULE_DESCRIPTION("ina2xx driver"); 365 + MODULE_LICENSE("GPL"); 366 + 367 + module_init(ina2xx_init); 368 + module_exit(ina2xx_exit);
+19
include/linux/platform_data/ina2xx.h
··· 1 + /* 2 + * Driver for Texas Instruments INA219, INA226 power monitor chips 3 + * 4 + * Copyright (C) 2012 Lothar Felten <l-felten@ti.com> 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + * 10 + * For further information, see the Documentation/hwmon/ina2xx file. 11 + */ 12 + 13 + /** 14 + * struct ina2xx_platform_data - ina2xx info 15 + * @shunt_uohms shunt resistance in microohms 16 + */ 17 + struct ina2xx_platform_data { 18 + long shunt_uohms; 19 + };