linux/drivers/hwmon/ina2xx.c
<<
>>
Prefs
   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
  58enum ina2xx_ids { ina219, ina226 };
  59
  60struct 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
  72static struct ina2xx_data *ina2xx_update_device(struct device *dev)
  73{
  74        struct i2c_client *client = to_i2c_client(dev);
  75        struct ina2xx_data *data = i2c_get_clientdata(client);
  76        struct ina2xx_data *ret = data;
  77
  78        mutex_lock(&data->update_lock);
  79
  80        if (time_after(jiffies, data->last_updated +
  81                       HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
  82
  83                int i;
  84
  85                dev_dbg(&client->dev, "Starting ina2xx update\n");
  86
  87                /* Read all registers */
  88                for (i = 0; i < data->registers; i++) {
  89                        int rv = i2c_smbus_read_word_swapped(client, i);
  90                        if (rv < 0) {
  91                                ret = ERR_PTR(rv);
  92                                goto abort;
  93                        }
  94                        data->regs[i] = rv;
  95                }
  96                data->last_updated = jiffies;
  97                data->valid = 1;
  98        }
  99abort:
 100        mutex_unlock(&data->update_lock);
 101        return ret;
 102}
 103
 104static int ina219_get_value(struct ina2xx_data *data, u8 reg)
 105{
 106        /*
 107         * calculate exact value for the given register
 108         * we assume default power-on reset settings:
 109         * bus voltage range 32V
 110         * gain = /8
 111         * adc 1 & 2 -> conversion time 532uS
 112         * mode is continuous shunt and bus
 113         * calibration value is INA219_CALIBRATION_VALUE
 114         */
 115        int val = data->regs[reg];
 116
 117        switch (reg) {
 118        case INA2XX_SHUNT_VOLTAGE:
 119                /* LSB=10uV. Convert to mV. */
 120                val = DIV_ROUND_CLOSEST(val, 100);
 121                break;
 122        case INA2XX_BUS_VOLTAGE:
 123                /* LSB=4mV. Register is not right aligned, convert to mV. */
 124                val = (val >> 3) * 4;
 125                break;
 126        case INA2XX_POWER:
 127                /* LSB=20mW. Convert to uW */
 128                val = val * 20 * 1000;
 129                break;
 130        case INA2XX_CURRENT:
 131                /* LSB=1mA (selected). Is in mA */
 132                break;
 133        default:
 134                /* programmer goofed */
 135                WARN_ON_ONCE(1);
 136                val = 0;
 137                break;
 138        }
 139
 140        return val;
 141}
 142
 143static int ina226_get_value(struct ina2xx_data *data, u8 reg)
 144{
 145        /*
 146         * calculate exact value for the given register
 147         * we assume default power-on reset settings:
 148         * bus voltage range 32V
 149         * gain = /8
 150         * adc 1 & 2 -> conversion time 532uS
 151         * mode is continuous shunt and bus
 152         * calibration value is INA226_CALIBRATION_VALUE
 153         */
 154        int val = data->regs[reg];
 155
 156        switch (reg) {
 157        case INA2XX_SHUNT_VOLTAGE:
 158                /* LSB=2.5uV. Convert to mV. */
 159                val = DIV_ROUND_CLOSEST(val, 400);
 160                break;
 161        case INA2XX_BUS_VOLTAGE:
 162                /* LSB=1.25mV. Convert to mV. */
 163                val = val + DIV_ROUND_CLOSEST(val, 4);
 164                break;
 165        case INA2XX_POWER:
 166                /* LSB=25mW. Convert to uW */
 167                val = val * 25 * 1000;
 168                break;
 169        case INA2XX_CURRENT:
 170                /* LSB=1mA (selected). Is in mA */
 171                break;
 172        default:
 173                /* programmer goofed */
 174                WARN_ON_ONCE(1);
 175                val = 0;
 176                break;
 177        }
 178
 179        return val;
 180}
 181
 182static ssize_t ina2xx_show_value(struct device *dev,
 183                                 struct device_attribute *da, char *buf)
 184{
 185        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
 186        struct ina2xx_data *data = ina2xx_update_device(dev);
 187        int value = 0;
 188
 189        if (IS_ERR(data))
 190                return PTR_ERR(data);
 191
 192        switch (data->kind) {
 193        case ina219:
 194                value = ina219_get_value(data, attr->index);
 195                break;
 196        case ina226:
 197                value = ina226_get_value(data, attr->index);
 198                break;
 199        default:
 200                WARN_ON_ONCE(1);
 201                break;
 202        }
 203        return snprintf(buf, PAGE_SIZE, "%d\n", value);
 204}
 205
 206/* shunt voltage */
 207static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
 208        ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
 209
 210/* bus voltage */
 211static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
 212        ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
 213
 214/* calculated current */
 215static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
 216        ina2xx_show_value, NULL, INA2XX_CURRENT);
 217
 218/* calculated power */
 219static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
 220        ina2xx_show_value, NULL, INA2XX_POWER);
 221
 222/* pointers to created device attributes */
 223static struct attribute *ina2xx_attributes[] = {
 224        &sensor_dev_attr_in0_input.dev_attr.attr,
 225        &sensor_dev_attr_in1_input.dev_attr.attr,
 226        &sensor_dev_attr_curr1_input.dev_attr.attr,
 227        &sensor_dev_attr_power1_input.dev_attr.attr,
 228        NULL,
 229};
 230
 231static const struct attribute_group ina2xx_group = {
 232        .attrs = ina2xx_attributes,
 233};
 234
 235static int ina2xx_probe(struct i2c_client *client,
 236                        const struct i2c_device_id *id)
 237{
 238        struct i2c_adapter *adapter = client->adapter;
 239        struct ina2xx_data *data;
 240        struct ina2xx_platform_data *pdata;
 241        int ret = 0;
 242        long shunt = 10000; /* default shunt value 10mOhms */
 243
 244        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
 245                return -ENODEV;
 246
 247        data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 248        if (!data)
 249                return -ENOMEM;
 250
 251        if (client->dev.platform_data) {
 252                pdata =
 253                  (struct ina2xx_platform_data *)client->dev.platform_data;
 254                shunt = pdata->shunt_uohms;
 255        }
 256
 257        if (shunt <= 0)
 258                return -ENODEV;
 259
 260        /* set the device type */
 261        data->kind = id->driver_data;
 262
 263        switch (data->kind) {
 264        case ina219:
 265                /* device configuration */
 266                i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
 267                                             INA219_CONFIG_DEFAULT);
 268
 269                /* set current LSB to 1mA, shunt is in uOhms */
 270                /* (equation 13 in datasheet) */
 271                i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
 272                                             40960000 / shunt);
 273                dev_info(&client->dev,
 274                         "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
 275                data->registers = INA219_REGISTERS;
 276                break;
 277        case ina226:
 278                /* device configuration */
 279                i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
 280                                             INA226_CONFIG_DEFAULT);
 281
 282                /* set current LSB to 1mA, shunt is in uOhms */
 283                /* (equation 1 in datasheet)*/
 284                i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
 285                                             5120000 / shunt);
 286                dev_info(&client->dev,
 287                         "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
 288                data->registers = INA226_REGISTERS;
 289                break;
 290        default:
 291                /* unknown device id */
 292                return -ENODEV;
 293        }
 294
 295        i2c_set_clientdata(client, data);
 296        mutex_init(&data->update_lock);
 297
 298        ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
 299        if (ret)
 300                return ret;
 301
 302        data->hwmon_dev = hwmon_device_register(&client->dev);
 303        if (IS_ERR(data->hwmon_dev)) {
 304                ret = PTR_ERR(data->hwmon_dev);
 305                goto out_err_hwmon;
 306        }
 307
 308        return 0;
 309
 310out_err_hwmon:
 311        sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
 312        return ret;
 313}
 314
 315static int ina2xx_remove(struct i2c_client *client)
 316{
 317        struct ina2xx_data *data = i2c_get_clientdata(client);
 318
 319        hwmon_device_unregister(data->hwmon_dev);
 320        sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
 321
 322        return 0;
 323}
 324
 325static const struct i2c_device_id ina2xx_id[] = {
 326        { "ina219", ina219 },
 327        { "ina226", ina226 },
 328        { }
 329};
 330MODULE_DEVICE_TABLE(i2c, ina2xx_id);
 331
 332static struct i2c_driver ina2xx_driver = {
 333        .driver = {
 334                .name   = "ina2xx",
 335        },
 336        .probe          = ina2xx_probe,
 337        .remove         = ina2xx_remove,
 338        .id_table       = ina2xx_id,
 339};
 340
 341static int __init ina2xx_init(void)
 342{
 343        return i2c_add_driver(&ina2xx_driver);
 344}
 345
 346static void __exit ina2xx_exit(void)
 347{
 348        i2c_del_driver(&ina2xx_driver);
 349}
 350
 351MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
 352MODULE_DESCRIPTION("ina2xx driver");
 353MODULE_LICENSE("GPL");
 354
 355module_init(ina2xx_init);
 356module_exit(ina2xx_exit);
 357
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.