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