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

hwmon: Driver for Texas Instruments INA209

Add support for the TI / Burr-Brown INA209 voltage / current / power
monitor.

Cc: Paul Hays <haysp@magma.net>
Cc: Ira W. Snyder <iws@ovro.caltech.edu>
Tested-by: Ira W. Snyder <iws@ovro.caltech.edu>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

+758
+18
Documentation/devicetree/bindings/i2c/ina209.txt
··· 1 + ina209 properties 2 + 3 + Required properties: 4 + - compatible: Must be "ti,ina209" 5 + - reg: I2C address 6 + 7 + Optional properties: 8 + 9 + - shunt-resistor 10 + Shunt resistor value in micro-Ohm 11 + 12 + Example: 13 + 14 + temp-sensor@4c { 15 + compatible = "ti,ina209"; 16 + reg = <0x4c>; 17 + shunt-resistor = <5000>; 18 + };
+93
Documentation/hwmon/ina209
··· 1 + Kernel driver ina209 2 + ===================== 3 + 4 + Supported chips: 5 + * Burr-Brown / Texas Instruments INA209 6 + Prefix: 'ina209' 7 + Addresses scanned: - 8 + Datasheet: 9 + http://www.ti.com/lit/gpn/ina209 10 + 11 + Author: Paul Hays <Paul.Hays@cattail.ca> 12 + Author: Ira W. Snyder <iws@ovro.caltech.edu> 13 + Author: Guenter Roeck <linux@roeck-us.net> 14 + 15 + 16 + Description 17 + ----------- 18 + 19 + The TI / Burr-Brown INA209 monitors voltage, current, and power on the high side 20 + of a D.C. power supply. It can perform measurements and calculations in the 21 + background to supply readings at any time. It includes a programmable 22 + calibration multiplier to scale the displayed current and power values. 23 + 24 + 25 + Sysfs entries 26 + ------------- 27 + 28 + The INA209 chip is highly configurable both via hardwiring and via 29 + the I2C bus. See the datasheet for details. 30 + 31 + This tries to expose most monitoring features of the hardware via 32 + sysfs. It does not support every feature of this chip. 33 + 34 + 35 + in0_input shunt voltage (mV) 36 + in0_input_highest shunt voltage historical maximum reading (mV) 37 + in0_input_lowest shunt voltage historical minimum reading (mV) 38 + in0_reset_history reset shunt voltage history 39 + in0_max shunt voltage max alarm limit (mV) 40 + in0_min shunt voltage min alarm limit (mV) 41 + in0_crit_max shunt voltage crit max alarm limit (mV) 42 + in0_crit_min shunt voltage crit min alarm limit (mV) 43 + in0_max_alarm shunt voltage max alarm limit exceeded 44 + in0_min_alarm shunt voltage min alarm limit exceeded 45 + in0_crit_max_alarm shunt voltage crit max alarm limit exceeded 46 + in0_crit_min_alarm shunt voltage crit min alarm limit exceeded 47 + 48 + in1_input bus voltage (mV) 49 + in1_input_highest bus voltage historical maximum reading (mV) 50 + in1_input_lowest bus voltage historical minimum reading (mV) 51 + in1_reset_history reset bus voltage history 52 + in1_max bus voltage max alarm limit (mV) 53 + in1_min bus voltage min alarm limit (mV) 54 + in1_crit_max bus voltage crit max alarm limit (mV) 55 + in1_crit_min bus voltage crit min alarm limit (mV) 56 + in1_max_alarm bus voltage max alarm limit exceeded 57 + in1_min_alarm bus voltage min alarm limit exceeded 58 + in1_crit_max_alarm bus voltage crit max alarm limit exceeded 59 + in1_crit_min_alarm bus voltage crit min alarm limit exceeded 60 + 61 + power1_input power measurement (uW) 62 + power1_input_highest power historical maximum reading (uW) 63 + power1_reset_history reset power history 64 + power1_max power max alarm limit (uW) 65 + power1_crit power crit alarm limit (uW) 66 + power1_max_alarm power max alarm limit exceeded 67 + power1_crit_alarm power crit alarm limit exceeded 68 + 69 + curr1_input current measurement (mA) 70 + 71 + update_interval data conversion time; affects number of samples used 72 + to average results for shunt and bus voltages. 73 + 74 + General Remarks 75 + --------------- 76 + 77 + The power and current registers in this chip require that the calibration 78 + register is programmed correctly before they are used. Normally this is expected 79 + to be done in the BIOS. In the absence of BIOS programming, the shunt resistor 80 + voltage can be provided using platform data. The driver uses platform data from 81 + the ina2xx driver for this purpose. If calibration register data is not provided 82 + via platform data, the driver checks if the calibration register has been 83 + programmed (ie has a value not equal to zero). If so, this value is retained. 84 + Otherwise, a default value reflecting a shunt resistor value of 10 mOhm is 85 + programmed into the calibration register. 86 + 87 + 88 + Output Pins 89 + ----------- 90 + 91 + Output pin programming is a board feature which depends on the BIOS. It is 92 + outside the scope of a hardware monitoring driver to enable or disable output 93 + pins.
+10
drivers/hwmon/Kconfig
··· 1157 1157 This driver can also be build as a module. If so, the module 1158 1158 will be called amc6821. 1159 1159 1160 + config SENSORS_INA209 1161 + tristate "TI / Burr Brown INA209" 1162 + depends on I2C 1163 + help 1164 + If you say yes here you get support for the TI / Burr Brown INA209 1165 + voltage / current / power monitor I2C interface. 1166 + 1167 + This driver can also be built as a module. If so, the module will 1168 + be called ina209. 1169 + 1160 1170 config SENSORS_INA2XX 1161 1171 tristate "Texas Instruments INA219 and compatibles" 1162 1172 depends on I2C
+1
drivers/hwmon/Makefile
··· 65 65 obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o 66 66 obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o 67 67 obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o 68 + obj-$(CONFIG_SENSORS_INA209) += ina209.o 68 69 obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o 69 70 obj-$(CONFIG_SENSORS_IT87) += it87.o 70 71 obj-$(CONFIG_SENSORS_JC42) += jc42.o
+636
drivers/hwmon/ina209.c
··· 1 + /* 2 + * Driver for the Texas Instruments / Burr Brown INA209 3 + * Bidirectional Current/Power Monitor 4 + * 5 + * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net> 6 + * 7 + * Derived from Ira W. Snyder's original driver submission 8 + * Copyright (C) 2008 Paul Hays <Paul.Hays@cattail.ca> 9 + * Copyright (C) 2008-2009 Ira W. Snyder <iws@ovro.caltech.edu> 10 + * 11 + * Aligned with ina2xx driver 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 + * Datasheet: 20 + * http://www.ti.com/lit/gpn/ina209 21 + */ 22 + 23 + #include <linux/kernel.h> 24 + #include <linux/module.h> 25 + #include <linux/init.h> 26 + #include <linux/err.h> 27 + #include <linux/slab.h> 28 + #include <linux/bug.h> 29 + #include <linux/i2c.h> 30 + #include <linux/hwmon.h> 31 + #include <linux/hwmon-sysfs.h> 32 + 33 + #include <linux/platform_data/ina2xx.h> 34 + 35 + /* register definitions */ 36 + #define INA209_CONFIGURATION 0x00 37 + #define INA209_STATUS 0x01 38 + #define INA209_STATUS_MASK 0x02 39 + #define INA209_SHUNT_VOLTAGE 0x03 40 + #define INA209_BUS_VOLTAGE 0x04 41 + #define INA209_POWER 0x05 42 + #define INA209_CURRENT 0x06 43 + #define INA209_SHUNT_VOLTAGE_POS_PEAK 0x07 44 + #define INA209_SHUNT_VOLTAGE_NEG_PEAK 0x08 45 + #define INA209_BUS_VOLTAGE_MAX_PEAK 0x09 46 + #define INA209_BUS_VOLTAGE_MIN_PEAK 0x0a 47 + #define INA209_POWER_PEAK 0x0b 48 + #define INA209_SHUNT_VOLTAGE_POS_WARN 0x0c 49 + #define INA209_SHUNT_VOLTAGE_NEG_WARN 0x0d 50 + #define INA209_POWER_WARN 0x0e 51 + #define INA209_BUS_VOLTAGE_OVER_WARN 0x0f 52 + #define INA209_BUS_VOLTAGE_UNDER_WARN 0x10 53 + #define INA209_POWER_OVER_LIMIT 0x11 54 + #define INA209_BUS_VOLTAGE_OVER_LIMIT 0x12 55 + #define INA209_BUS_VOLTAGE_UNDER_LIMIT 0x13 56 + #define INA209_CRITICAL_DAC_POS 0x14 57 + #define INA209_CRITICAL_DAC_NEG 0x15 58 + #define INA209_CALIBRATION 0x16 59 + 60 + #define INA209_REGISTERS 0x17 61 + 62 + #define INA209_CONFIG_DEFAULT 0x3c47 /* PGA=8, full range */ 63 + #define INA209_SHUNT_DEFAULT 10000 /* uOhm */ 64 + 65 + struct ina209_data { 66 + struct device *hwmon_dev; 67 + 68 + struct mutex update_lock; 69 + bool valid; 70 + unsigned long last_updated; /* in jiffies */ 71 + 72 + u16 regs[INA209_REGISTERS]; /* All chip registers */ 73 + 74 + u16 config_orig; /* Original configuration */ 75 + u16 calibration_orig; /* Original calibration */ 76 + u16 update_interval; 77 + }; 78 + 79 + static struct ina209_data *ina209_update_device(struct device *dev) 80 + { 81 + struct i2c_client *client = to_i2c_client(dev); 82 + struct ina209_data *data = i2c_get_clientdata(client); 83 + struct ina209_data *ret = data; 84 + s32 val; 85 + int i; 86 + 87 + mutex_lock(&data->update_lock); 88 + 89 + if (!data->valid || 90 + time_after(jiffies, data->last_updated + data->update_interval)) { 91 + for (i = 0; i < ARRAY_SIZE(data->regs); i++) { 92 + val = i2c_smbus_read_word_swapped(client, i); 93 + if (val < 0) { 94 + ret = ERR_PTR(val); 95 + goto abort; 96 + } 97 + data->regs[i] = val; 98 + } 99 + data->last_updated = jiffies; 100 + data->valid = true; 101 + } 102 + abort: 103 + mutex_unlock(&data->update_lock); 104 + return ret; 105 + } 106 + 107 + /* 108 + * Read a value from a device register and convert it to the 109 + * appropriate sysfs units 110 + */ 111 + static long ina209_from_reg(const u8 reg, const u16 val) 112 + { 113 + switch (reg) { 114 + case INA209_SHUNT_VOLTAGE: 115 + case INA209_SHUNT_VOLTAGE_POS_PEAK: 116 + case INA209_SHUNT_VOLTAGE_NEG_PEAK: 117 + case INA209_SHUNT_VOLTAGE_POS_WARN: 118 + case INA209_SHUNT_VOLTAGE_NEG_WARN: 119 + /* LSB=10 uV. Convert to mV. */ 120 + return DIV_ROUND_CLOSEST(val, 100); 121 + 122 + case INA209_BUS_VOLTAGE: 123 + case INA209_BUS_VOLTAGE_MAX_PEAK: 124 + case INA209_BUS_VOLTAGE_MIN_PEAK: 125 + case INA209_BUS_VOLTAGE_OVER_WARN: 126 + case INA209_BUS_VOLTAGE_UNDER_WARN: 127 + case INA209_BUS_VOLTAGE_OVER_LIMIT: 128 + case INA209_BUS_VOLTAGE_UNDER_LIMIT: 129 + /* LSB=4 mV, last 3 bits unused */ 130 + return (val >> 3) * 4; 131 + 132 + case INA209_CRITICAL_DAC_POS: 133 + /* LSB=1 mV, in the upper 8 bits */ 134 + return val >> 8; 135 + 136 + case INA209_CRITICAL_DAC_NEG: 137 + /* LSB=1 mV, in the upper 8 bits */ 138 + return -1 * (val >> 8); 139 + 140 + case INA209_POWER: 141 + case INA209_POWER_PEAK: 142 + case INA209_POWER_WARN: 143 + case INA209_POWER_OVER_LIMIT: 144 + /* LSB=20 mW. Convert to uW */ 145 + return val * 20 * 1000L; 146 + 147 + case INA209_CURRENT: 148 + /* LSB=1 mA (selected). Is in mA */ 149 + return val; 150 + } 151 + 152 + /* programmer goofed */ 153 + WARN_ON_ONCE(1); 154 + return 0; 155 + } 156 + 157 + /* 158 + * Take a value and convert it to register format, clamping the value 159 + * to the appropriate range. 160 + */ 161 + static int ina209_to_reg(u8 reg, u16 old, long val) 162 + { 163 + switch (reg) { 164 + case INA209_SHUNT_VOLTAGE_POS_WARN: 165 + case INA209_SHUNT_VOLTAGE_NEG_WARN: 166 + /* Limit to +- 320 mV, 10 uV LSB */ 167 + return clamp_val(val, -320, 320) * 100; 168 + 169 + case INA209_BUS_VOLTAGE_OVER_WARN: 170 + case INA209_BUS_VOLTAGE_UNDER_WARN: 171 + case INA209_BUS_VOLTAGE_OVER_LIMIT: 172 + case INA209_BUS_VOLTAGE_UNDER_LIMIT: 173 + /* 174 + * Limit to 0-32000 mV, 4 mV LSB 175 + * 176 + * The last three bits aren't part of the value, but we'll 177 + * preserve them in their original state. 178 + */ 179 + return (DIV_ROUND_CLOSEST(clamp_val(val, 0, 32000), 4) << 3) 180 + | (old & 0x7); 181 + 182 + case INA209_CRITICAL_DAC_NEG: 183 + /* 184 + * Limit to -255-0 mV, 1 mV LSB 185 + * Convert the value to a positive value for the register 186 + * 187 + * The value lives in the top 8 bits only, be careful 188 + * and keep original value of other bits. 189 + */ 190 + return (clamp_val(-val, 0, 255) << 8) | (old & 0xff); 191 + 192 + case INA209_CRITICAL_DAC_POS: 193 + /* 194 + * Limit to 0-255 mV, 1 mV LSB 195 + * 196 + * The value lives in the top 8 bits only, be careful 197 + * and keep original value of other bits. 198 + */ 199 + return (clamp_val(val, 0, 255) << 8) | (old & 0xff); 200 + 201 + case INA209_POWER_WARN: 202 + case INA209_POWER_OVER_LIMIT: 203 + /* 20 mW LSB */ 204 + return DIV_ROUND_CLOSEST(val, 20 * 1000); 205 + } 206 + 207 + /* Other registers are read-only, return access error */ 208 + return -EACCES; 209 + } 210 + 211 + static int ina209_interval_from_reg(u16 reg) 212 + { 213 + return 68 >> (15 - ((reg >> 3) & 0x0f)); 214 + } 215 + 216 + static u16 ina209_reg_from_interval(u16 config, long interval) 217 + { 218 + int i, adc; 219 + 220 + if (interval <= 0) { 221 + adc = 8; 222 + } else { 223 + adc = 15; 224 + for (i = 34 + 34 / 2; i; i >>= 1) { 225 + if (i < interval) 226 + break; 227 + adc--; 228 + } 229 + } 230 + return (config & 0xf807) | (adc << 3) | (adc << 7); 231 + } 232 + 233 + static ssize_t ina209_set_interval(struct device *dev, 234 + struct device_attribute *da, 235 + const char *buf, size_t count) 236 + { 237 + struct i2c_client *client = to_i2c_client(dev); 238 + struct ina209_data *data = ina209_update_device(dev); 239 + long val; 240 + u16 regval; 241 + int ret; 242 + 243 + if (IS_ERR(data)) 244 + return PTR_ERR(data); 245 + 246 + ret = kstrtol(buf, 10, &val); 247 + if (ret < 0) 248 + return ret; 249 + 250 + mutex_lock(&data->update_lock); 251 + regval = ina209_reg_from_interval(data->regs[INA209_CONFIGURATION], 252 + val); 253 + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, regval); 254 + data->regs[INA209_CONFIGURATION] = regval; 255 + data->update_interval = ina209_interval_from_reg(regval); 256 + mutex_unlock(&data->update_lock); 257 + return count; 258 + } 259 + 260 + static ssize_t ina209_show_interval(struct device *dev, 261 + struct device_attribute *da, char *buf) 262 + { 263 + struct i2c_client *client = to_i2c_client(dev); 264 + struct ina209_data *data = i2c_get_clientdata(client); 265 + 266 + return snprintf(buf, PAGE_SIZE, "%d\n", data->update_interval); 267 + } 268 + 269 + /* 270 + * History is reset by writing 1 into bit 0 of the respective peak register. 271 + * Since more than one peak register may be affected by the scope of a 272 + * reset_history attribute write, use a bit mask in attr->index to identify 273 + * which registers are affected. 274 + */ 275 + static u16 ina209_reset_history_regs[] = { 276 + INA209_SHUNT_VOLTAGE_POS_PEAK, 277 + INA209_SHUNT_VOLTAGE_NEG_PEAK, 278 + INA209_BUS_VOLTAGE_MAX_PEAK, 279 + INA209_BUS_VOLTAGE_MIN_PEAK, 280 + INA209_POWER_PEAK 281 + }; 282 + 283 + static ssize_t ina209_reset_history(struct device *dev, 284 + struct device_attribute *da, 285 + const char *buf, 286 + size_t count) 287 + { 288 + struct i2c_client *client = to_i2c_client(dev); 289 + struct ina209_data *data = i2c_get_clientdata(client); 290 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 291 + u32 mask = attr->index; 292 + long val; 293 + int i, ret; 294 + 295 + ret = kstrtol(buf, 10, &val); 296 + if (ret < 0) 297 + return ret; 298 + 299 + mutex_lock(&data->update_lock); 300 + for (i = 0; i < ARRAY_SIZE(ina209_reset_history_regs); i++) { 301 + if (mask & (1 << i)) 302 + i2c_smbus_write_word_swapped(client, 303 + ina209_reset_history_regs[i], 1); 304 + } 305 + data->valid = false; 306 + mutex_unlock(&data->update_lock); 307 + return count; 308 + } 309 + 310 + static ssize_t ina209_set_value(struct device *dev, 311 + struct device_attribute *da, 312 + const char *buf, 313 + size_t count) 314 + { 315 + struct i2c_client *client = to_i2c_client(dev); 316 + struct ina209_data *data = ina209_update_device(dev); 317 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 318 + int reg = attr->index; 319 + long val; 320 + int ret; 321 + 322 + if (IS_ERR(data)) 323 + return PTR_ERR(data); 324 + 325 + ret = kstrtol(buf, 10, &val); 326 + if (ret < 0) 327 + return ret; 328 + 329 + mutex_lock(&data->update_lock); 330 + ret = ina209_to_reg(reg, data->regs[reg], val); 331 + if (ret < 0) { 332 + count = ret; 333 + goto abort; 334 + } 335 + i2c_smbus_write_word_swapped(client, reg, ret); 336 + data->regs[reg] = ret; 337 + abort: 338 + mutex_unlock(&data->update_lock); 339 + return count; 340 + } 341 + 342 + static ssize_t ina209_show_value(struct device *dev, 343 + struct device_attribute *da, 344 + char *buf) 345 + { 346 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 347 + struct ina209_data *data = ina209_update_device(dev); 348 + long val; 349 + 350 + if (IS_ERR(data)) 351 + return PTR_ERR(data); 352 + 353 + val = ina209_from_reg(attr->index, data->regs[attr->index]); 354 + return snprintf(buf, PAGE_SIZE, "%ld\n", val); 355 + } 356 + 357 + static ssize_t ina209_show_alarm(struct device *dev, 358 + struct device_attribute *da, 359 + char *buf) 360 + { 361 + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 362 + struct ina209_data *data = ina209_update_device(dev); 363 + const unsigned int mask = attr->index; 364 + u16 status; 365 + 366 + if (IS_ERR(data)) 367 + return PTR_ERR(data); 368 + 369 + status = data->regs[INA209_STATUS]; 370 + 371 + /* 372 + * All alarms are in the INA209_STATUS register. To avoid a long 373 + * switch statement, the mask is passed in attr->index 374 + */ 375 + return snprintf(buf, PAGE_SIZE, "%u\n", !!(status & mask)); 376 + } 377 + 378 + /* Shunt voltage, history, limits, alarms */ 379 + static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina209_show_value, NULL, 380 + INA209_SHUNT_VOLTAGE); 381 + static SENSOR_DEVICE_ATTR(in0_input_highest, S_IRUGO, ina209_show_value, NULL, 382 + INA209_SHUNT_VOLTAGE_POS_PEAK); 383 + static SENSOR_DEVICE_ATTR(in0_input_lowest, S_IRUGO, ina209_show_value, NULL, 384 + INA209_SHUNT_VOLTAGE_NEG_PEAK); 385 + static SENSOR_DEVICE_ATTR(in0_reset_history, S_IWUSR, NULL, 386 + ina209_reset_history, (1 << 0) | (1 << 1)); 387 + static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, ina209_show_value, 388 + ina209_set_value, INA209_SHUNT_VOLTAGE_POS_WARN); 389 + static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, ina209_show_value, 390 + ina209_set_value, INA209_SHUNT_VOLTAGE_NEG_WARN); 391 + static SENSOR_DEVICE_ATTR(in0_crit_max, S_IRUGO | S_IWUSR, ina209_show_value, 392 + ina209_set_value, INA209_CRITICAL_DAC_POS); 393 + static SENSOR_DEVICE_ATTR(in0_crit_min, S_IRUGO | S_IWUSR, ina209_show_value, 394 + ina209_set_value, INA209_CRITICAL_DAC_NEG); 395 + 396 + static SENSOR_DEVICE_ATTR(in0_min_alarm, S_IRUGO, ina209_show_alarm, NULL, 397 + 1 << 11); 398 + static SENSOR_DEVICE_ATTR(in0_max_alarm, S_IRUGO, ina209_show_alarm, NULL, 399 + 1 << 12); 400 + static SENSOR_DEVICE_ATTR(in0_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL, 401 + 1 << 6); 402 + static SENSOR_DEVICE_ATTR(in0_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL, 403 + 1 << 7); 404 + 405 + /* Bus voltage, history, limits, alarms */ 406 + static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ina209_show_value, NULL, 407 + INA209_BUS_VOLTAGE); 408 + static SENSOR_DEVICE_ATTR(in1_input_highest, S_IRUGO, ina209_show_value, NULL, 409 + INA209_BUS_VOLTAGE_MAX_PEAK); 410 + static SENSOR_DEVICE_ATTR(in1_input_lowest, S_IRUGO, ina209_show_value, NULL, 411 + INA209_BUS_VOLTAGE_MIN_PEAK); 412 + static SENSOR_DEVICE_ATTR(in1_reset_history, S_IWUSR, NULL, 413 + ina209_reset_history, (1 << 2) | (1 << 3)); 414 + static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR, ina209_show_value, 415 + ina209_set_value, INA209_BUS_VOLTAGE_OVER_WARN); 416 + static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR, ina209_show_value, 417 + ina209_set_value, INA209_BUS_VOLTAGE_UNDER_WARN); 418 + static SENSOR_DEVICE_ATTR(in1_crit_max, S_IRUGO | S_IWUSR, ina209_show_value, 419 + ina209_set_value, INA209_BUS_VOLTAGE_OVER_LIMIT); 420 + static SENSOR_DEVICE_ATTR(in1_crit_min, S_IRUGO | S_IWUSR, ina209_show_value, 421 + ina209_set_value, INA209_BUS_VOLTAGE_UNDER_LIMIT); 422 + 423 + static SENSOR_DEVICE_ATTR(in1_min_alarm, S_IRUGO, ina209_show_alarm, NULL, 424 + 1 << 14); 425 + static SENSOR_DEVICE_ATTR(in1_max_alarm, S_IRUGO, ina209_show_alarm, NULL, 426 + 1 << 15); 427 + static SENSOR_DEVICE_ATTR(in1_crit_min_alarm, S_IRUGO, ina209_show_alarm, NULL, 428 + 1 << 9); 429 + static SENSOR_DEVICE_ATTR(in1_crit_max_alarm, S_IRUGO, ina209_show_alarm, NULL, 430 + 1 << 10); 431 + 432 + /* Power */ 433 + static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina209_show_value, NULL, 434 + INA209_POWER); 435 + static SENSOR_DEVICE_ATTR(power1_input_highest, S_IRUGO, ina209_show_value, 436 + NULL, INA209_POWER_PEAK); 437 + static SENSOR_DEVICE_ATTR(power1_reset_history, S_IWUSR, NULL, 438 + ina209_reset_history, 1 << 4); 439 + static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO | S_IWUSR, ina209_show_value, 440 + ina209_set_value, INA209_POWER_WARN); 441 + static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO | S_IWUSR, ina209_show_value, 442 + ina209_set_value, INA209_POWER_OVER_LIMIT); 443 + 444 + static SENSOR_DEVICE_ATTR(power1_max_alarm, S_IRUGO, ina209_show_alarm, NULL, 445 + 1 << 13); 446 + static SENSOR_DEVICE_ATTR(power1_crit_alarm, S_IRUGO, ina209_show_alarm, NULL, 447 + 1 << 8); 448 + 449 + /* Current */ 450 + static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina209_show_value, NULL, 451 + INA209_CURRENT); 452 + 453 + static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, 454 + ina209_show_interval, ina209_set_interval, 0); 455 + 456 + /* 457 + * Finally, construct an array of pointers to members of the above objects, 458 + * as required for sysfs_create_group() 459 + */ 460 + static struct attribute *ina209_attributes[] = { 461 + &sensor_dev_attr_in0_input.dev_attr.attr, 462 + &sensor_dev_attr_in0_input_highest.dev_attr.attr, 463 + &sensor_dev_attr_in0_input_lowest.dev_attr.attr, 464 + &sensor_dev_attr_in0_reset_history.dev_attr.attr, 465 + &sensor_dev_attr_in0_max.dev_attr.attr, 466 + &sensor_dev_attr_in0_min.dev_attr.attr, 467 + &sensor_dev_attr_in0_crit_max.dev_attr.attr, 468 + &sensor_dev_attr_in0_crit_min.dev_attr.attr, 469 + &sensor_dev_attr_in0_max_alarm.dev_attr.attr, 470 + &sensor_dev_attr_in0_min_alarm.dev_attr.attr, 471 + &sensor_dev_attr_in0_crit_max_alarm.dev_attr.attr, 472 + &sensor_dev_attr_in0_crit_min_alarm.dev_attr.attr, 473 + 474 + &sensor_dev_attr_in1_input.dev_attr.attr, 475 + &sensor_dev_attr_in1_input_highest.dev_attr.attr, 476 + &sensor_dev_attr_in1_input_lowest.dev_attr.attr, 477 + &sensor_dev_attr_in1_reset_history.dev_attr.attr, 478 + &sensor_dev_attr_in1_max.dev_attr.attr, 479 + &sensor_dev_attr_in1_min.dev_attr.attr, 480 + &sensor_dev_attr_in1_crit_max.dev_attr.attr, 481 + &sensor_dev_attr_in1_crit_min.dev_attr.attr, 482 + &sensor_dev_attr_in1_max_alarm.dev_attr.attr, 483 + &sensor_dev_attr_in1_min_alarm.dev_attr.attr, 484 + &sensor_dev_attr_in1_crit_max_alarm.dev_attr.attr, 485 + &sensor_dev_attr_in1_crit_min_alarm.dev_attr.attr, 486 + 487 + &sensor_dev_attr_power1_input.dev_attr.attr, 488 + &sensor_dev_attr_power1_input_highest.dev_attr.attr, 489 + &sensor_dev_attr_power1_reset_history.dev_attr.attr, 490 + &sensor_dev_attr_power1_max.dev_attr.attr, 491 + &sensor_dev_attr_power1_crit.dev_attr.attr, 492 + &sensor_dev_attr_power1_max_alarm.dev_attr.attr, 493 + &sensor_dev_attr_power1_crit_alarm.dev_attr.attr, 494 + 495 + &sensor_dev_attr_curr1_input.dev_attr.attr, 496 + 497 + &sensor_dev_attr_update_interval.dev_attr.attr, 498 + 499 + NULL, 500 + }; 501 + 502 + static const struct attribute_group ina209_group = { 503 + .attrs = ina209_attributes, 504 + }; 505 + 506 + static void ina209_restore_conf(struct i2c_client *client, 507 + struct ina209_data *data) 508 + { 509 + /* Restore initial configuration */ 510 + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, 511 + data->config_orig); 512 + i2c_smbus_write_word_swapped(client, INA209_CALIBRATION, 513 + data->calibration_orig); 514 + } 515 + 516 + static int ina209_init_client(struct i2c_client *client, 517 + struct ina209_data *data) 518 + { 519 + struct ina2xx_platform_data *pdata = dev_get_platdata(&client->dev); 520 + u32 shunt; 521 + int reg; 522 + 523 + reg = i2c_smbus_read_word_swapped(client, INA209_CALIBRATION); 524 + if (reg < 0) 525 + return reg; 526 + data->calibration_orig = reg; 527 + 528 + reg = i2c_smbus_read_word_swapped(client, INA209_CONFIGURATION); 529 + if (reg < 0) 530 + return reg; 531 + data->config_orig = reg; 532 + 533 + if (pdata) { 534 + if (pdata->shunt_uohms <= 0) 535 + return -EINVAL; 536 + shunt = pdata->shunt_uohms; 537 + } else if (!of_property_read_u32(client->dev.of_node, "shunt-resistor", 538 + &shunt)) { 539 + if (shunt == 0) 540 + return -EINVAL; 541 + } else { 542 + shunt = data->calibration_orig ? 543 + 40960000 / data->calibration_orig : INA209_SHUNT_DEFAULT; 544 + } 545 + 546 + i2c_smbus_write_word_swapped(client, INA209_CONFIGURATION, 547 + INA209_CONFIG_DEFAULT); 548 + data->update_interval = ina209_interval_from_reg(INA209_CONFIG_DEFAULT); 549 + 550 + /* 551 + * Calibrate current LSB to 1mA. Shunt is in uOhms. 552 + * See equation 13 in datasheet. 553 + */ 554 + i2c_smbus_write_word_swapped(client, INA209_CALIBRATION, 555 + clamp_val(40960000 / shunt, 1, 65535)); 556 + 557 + /* Clear status register */ 558 + i2c_smbus_read_word_swapped(client, INA209_STATUS); 559 + 560 + return 0; 561 + } 562 + 563 + static int ina209_probe(struct i2c_client *client, 564 + const struct i2c_device_id *id) 565 + { 566 + struct i2c_adapter *adapter = client->adapter; 567 + struct ina209_data *data; 568 + int ret; 569 + 570 + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) 571 + return -ENODEV; 572 + 573 + data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 574 + if (!data) 575 + return -ENOMEM; 576 + 577 + i2c_set_clientdata(client, data); 578 + mutex_init(&data->update_lock); 579 + 580 + ret = ina209_init_client(client, data); 581 + if (ret) 582 + return ret; 583 + 584 + /* Register sysfs hooks */ 585 + ret = sysfs_create_group(&client->dev.kobj, &ina209_group); 586 + if (ret) 587 + goto out_restore_conf; 588 + 589 + data->hwmon_dev = hwmon_device_register(&client->dev); 590 + if (IS_ERR(data->hwmon_dev)) { 591 + ret = PTR_ERR(data->hwmon_dev); 592 + goto out_hwmon_device_register; 593 + } 594 + 595 + return 0; 596 + 597 + out_hwmon_device_register: 598 + sysfs_remove_group(&client->dev.kobj, &ina209_group); 599 + out_restore_conf: 600 + ina209_restore_conf(client, data); 601 + return ret; 602 + } 603 + 604 + static int ina209_remove(struct i2c_client *client) 605 + { 606 + struct ina209_data *data = i2c_get_clientdata(client); 607 + 608 + hwmon_device_unregister(data->hwmon_dev); 609 + sysfs_remove_group(&client->dev.kobj, &ina209_group); 610 + ina209_restore_conf(client, data); 611 + 612 + return 0; 613 + } 614 + 615 + static const struct i2c_device_id ina209_id[] = { 616 + { "ina209", 0 }, 617 + { } 618 + }; 619 + MODULE_DEVICE_TABLE(i2c, ina209_id); 620 + 621 + /* This is the driver that will be inserted */ 622 + static struct i2c_driver ina209_driver = { 623 + .class = I2C_CLASS_HWMON, 624 + .driver = { 625 + .name = "ina209", 626 + }, 627 + .probe = ina209_probe, 628 + .remove = ina209_remove, 629 + .id_table = ina209_id, 630 + }; 631 + 632 + module_i2c_driver(ina209_driver); 633 + 634 + MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>, Paul Hays <Paul.Hays@cattail.ca>, Guenter Roeck <linux@roeck-us.net>"); 635 + MODULE_DESCRIPTION("INA209 driver"); 636 + MODULE_LICENSE("GPL");