linux/drivers/power/supply/ltc2941-battery-gauge.c
<<
>>
Prefs
   1/*
   2 * I2C client/driver for the Linear Technology LTC2941 and LTC2943
   3 * Battery Gas Gauge IC
   4 *
   5 * Copyright (C) 2014 Topic Embedded Systems
   6 *
   7 * Author: Auryn Verwegen
   8 * Author: Mike Looijmans
   9 */
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/of_device.h>
  13#include <linux/types.h>
  14#include <linux/errno.h>
  15#include <linux/swab.h>
  16#include <linux/i2c.h>
  17#include <linux/delay.h>
  18#include <linux/power_supply.h>
  19#include <linux/slab.h>
  20
  21#define I16_MSB(x)                      ((x >> 8) & 0xFF)
  22#define I16_LSB(x)                      (x & 0xFF)
  23
  24#define LTC294X_WORK_DELAY              10      /* Update delay in seconds */
  25
  26#define LTC294X_MAX_VALUE               0xFFFF
  27#define LTC294X_MID_SUPPLY              0x7FFF
  28
  29#define LTC2941_MAX_PRESCALER_EXP       7
  30#define LTC2943_MAX_PRESCALER_EXP       6
  31
  32enum ltc294x_reg {
  33        LTC294X_REG_STATUS              = 0x00,
  34        LTC294X_REG_CONTROL             = 0x01,
  35        LTC294X_REG_ACC_CHARGE_MSB      = 0x02,
  36        LTC294X_REG_ACC_CHARGE_LSB      = 0x03,
  37        LTC294X_REG_THRESH_HIGH_MSB     = 0x04,
  38        LTC294X_REG_THRESH_HIGH_LSB     = 0x05,
  39        LTC294X_REG_THRESH_LOW_MSB      = 0x06,
  40        LTC294X_REG_THRESH_LOW_LSB      = 0x07,
  41        LTC294X_REG_VOLTAGE_MSB = 0x08,
  42        LTC294X_REG_VOLTAGE_LSB = 0x09,
  43        LTC294X_REG_CURRENT_MSB = 0x0E,
  44        LTC294X_REG_CURRENT_LSB = 0x0F,
  45        LTC294X_REG_TEMPERATURE_MSB     = 0x14,
  46        LTC294X_REG_TEMPERATURE_LSB     = 0x15,
  47};
  48
  49#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6))
  50#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7)
  51#define LTC294X_REG_CONTROL_PRESCALER_MASK      (BIT(5) | BIT(4) | BIT(3))
  52#define LTC294X_REG_CONTROL_SHUTDOWN_MASK       (BIT(0))
  53#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \
  54        ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK)
  55#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED        0
  56
  57#define LTC2941_NUM_REGS        0x08
  58#define LTC2943_NUM_REGS        0x18
  59
  60struct ltc294x_info {
  61        struct i2c_client *client;      /* I2C Client pointer */
  62        struct power_supply *supply;    /* Supply pointer */
  63        struct power_supply_desc supply_desc;   /* Supply description */
  64        struct delayed_work work;       /* Work scheduler */
  65        unsigned long num_regs; /* Number of registers (chip type) */
  66        int charge;     /* Last charge register content */
  67        int r_sense;    /* mOhm */
  68        int Qlsb;       /* nAh */
  69};
  70
  71static inline int convert_bin_to_uAh(
  72        const struct ltc294x_info *info, int Q)
  73{
  74        return ((Q * (info->Qlsb / 10))) / 100;
  75}
  76
  77static inline int convert_uAh_to_bin(
  78        const struct ltc294x_info *info, int uAh)
  79{
  80        int Q;
  81
  82        Q = (uAh * 100) / (info->Qlsb/10);
  83        return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE;
  84}
  85
  86static int ltc294x_read_regs(struct i2c_client *client,
  87        enum ltc294x_reg reg, u8 *buf, int num_regs)
  88{
  89        int ret;
  90        struct i2c_msg msgs[2] = { };
  91        u8 reg_start = reg;
  92
  93        msgs[0].addr    = client->addr;
  94        msgs[0].len     = 1;
  95        msgs[0].buf     = &reg_start;
  96
  97        msgs[1].addr    = client->addr;
  98        msgs[1].len     = num_regs;
  99        msgs[1].buf     = buf;
 100        msgs[1].flags   = I2C_M_RD;
 101
 102        ret = i2c_transfer(client->adapter, &msgs[0], 2);
 103        if (ret < 0) {
 104                dev_err(&client->dev, "ltc2941 read_reg failed!\n");
 105                return ret;
 106        }
 107
 108        dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
 109                __func__, reg, num_regs, *buf);
 110
 111        return 0;
 112}
 113
 114static int ltc294x_write_regs(struct i2c_client *client,
 115        enum ltc294x_reg reg, const u8 *buf, int num_regs)
 116{
 117        int ret;
 118        u8 reg_start = reg;
 119
 120        ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf);
 121        if (ret < 0) {
 122                dev_err(&client->dev, "ltc2941 write_reg failed!\n");
 123                return ret;
 124        }
 125
 126        dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
 127                __func__, reg, num_regs, *buf);
 128
 129        return 0;
 130}
 131
 132static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
 133{
 134        int ret;
 135        u8 value;
 136        u8 control;
 137
 138        /* Read status and control registers */
 139        ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
 140        if (ret < 0) {
 141                dev_err(&info->client->dev,
 142                        "Could not read registers from device\n");
 143                goto error_exit;
 144        }
 145
 146        control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
 147                                LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
 148        /* Put the 2943 into "monitor" mode, so it measures every 10 sec */
 149        if (info->num_regs == LTC2943_NUM_REGS)
 150                control |= LTC2943_REG_CONTROL_MODE_SCAN;
 151
 152        if (value != control) {
 153                ret = ltc294x_write_regs(info->client,
 154                        LTC294X_REG_CONTROL, &control, 1);
 155                if (ret < 0) {
 156                        dev_err(&info->client->dev,
 157                                "Could not write register\n");
 158                        goto error_exit;
 159                }
 160        }
 161
 162        return 0;
 163
 164error_exit:
 165        return ret;
 166}
 167
 168static int ltc294x_read_charge_register(const struct ltc294x_info *info)
 169{
 170        int ret;
 171        u8 datar[2];
 172
 173        ret = ltc294x_read_regs(info->client,
 174                LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2);
 175        if (ret < 0)
 176                return ret;
 177        return (datar[0] << 8) + datar[1];
 178}
 179
 180static int ltc294x_get_charge_now(const struct ltc294x_info *info, int *val)
 181{
 182        int value = ltc294x_read_charge_register(info);
 183
 184        if (value < 0)
 185                return value;
 186        /* When r_sense < 0, this counts up when the battery discharges */
 187        if (info->Qlsb < 0)
 188                value -= 0xFFFF;
 189        *val = convert_bin_to_uAh(info, value);
 190        return 0;
 191}
 192
 193static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
 194{
 195        int ret;
 196        u8 dataw[2];
 197        u8 ctrl_reg;
 198        s32 value;
 199
 200        value = convert_uAh_to_bin(info, val);
 201        /* Direction depends on how sense+/- were connected */
 202        if (info->Qlsb < 0)
 203                value += 0xFFFF;
 204        if ((value < 0) || (value > 0xFFFF)) /* input validation */
 205                return -EINVAL;
 206
 207        /* Read control register */
 208        ret = ltc294x_read_regs(info->client,
 209                LTC294X_REG_CONTROL, &ctrl_reg, 1);
 210        if (ret < 0)
 211                return ret;
 212        /* Disable analog section */
 213        ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK;
 214        ret = ltc294x_write_regs(info->client,
 215                LTC294X_REG_CONTROL, &ctrl_reg, 1);
 216        if (ret < 0)
 217                return ret;
 218        /* Set new charge value */
 219        dataw[0] = I16_MSB(value);
 220        dataw[1] = I16_LSB(value);
 221        ret = ltc294x_write_regs(info->client,
 222                LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2);
 223        if (ret < 0)
 224                goto error_exit;
 225        /* Enable analog section */
 226error_exit:
 227        ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK;
 228        ret = ltc294x_write_regs(info->client,
 229                LTC294X_REG_CONTROL, &ctrl_reg, 1);
 230
 231        return ret < 0 ? ret : 0;
 232}
 233
 234static int ltc294x_get_charge_counter(
 235        const struct ltc294x_info *info, int *val)
 236{
 237        int value = ltc294x_read_charge_register(info);
 238
 239        if (value < 0)
 240                return value;
 241        value -= LTC294X_MID_SUPPLY;
 242        *val = convert_bin_to_uAh(info, value);
 243        return 0;
 244}
 245
 246static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
 247{
 248        int ret;
 249        u8 datar[2];
 250        u32 value;
 251
 252        ret = ltc294x_read_regs(info->client,
 253                LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
 254        value = (datar[0] << 8) | datar[1];
 255        *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */
 256        return ret;
 257}
 258
 259static int ltc294x_get_current(const struct ltc294x_info *info, int *val)
 260{
 261        int ret;
 262        u8 datar[2];
 263        s32 value;
 264
 265        ret = ltc294x_read_regs(info->client,
 266                LTC294X_REG_CURRENT_MSB, &datar[0], 2);
 267        value = (datar[0] << 8) | datar[1];
 268        value -= 0x7FFF;
 269        /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
 270         * the formula below keeps everything in s32 range while preserving
 271         * enough digits */
 272        *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */
 273        return ret;
 274}
 275
 276static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
 277{
 278        int ret;
 279        u8 datar[2];
 280        u32 value;
 281
 282        ret = ltc294x_read_regs(info->client,
 283                LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2);
 284        value = (datar[0] << 8) | datar[1];
 285        /* Full-scale is 510 Kelvin, convert to centidegrees  */
 286        *val = (((51000 * value) / 0xFFFF) - 27215);
 287        return ret;
 288}
 289
 290static int ltc294x_get_property(struct power_supply *psy,
 291                                enum power_supply_property prop,
 292                                union power_supply_propval *val)
 293{
 294        struct ltc294x_info *info = power_supply_get_drvdata(psy);
 295
 296        switch (prop) {
 297        case POWER_SUPPLY_PROP_CHARGE_NOW:
 298                return ltc294x_get_charge_now(info, &val->intval);
 299        case POWER_SUPPLY_PROP_CHARGE_COUNTER:
 300                return ltc294x_get_charge_counter(info, &val->intval);
 301        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 302                return ltc294x_get_voltage(info, &val->intval);
 303        case POWER_SUPPLY_PROP_CURRENT_NOW:
 304                return ltc294x_get_current(info, &val->intval);
 305        case POWER_SUPPLY_PROP_TEMP:
 306                return ltc294x_get_temperature(info, &val->intval);
 307        default:
 308                return -EINVAL;
 309        }
 310}
 311
 312static int ltc294x_set_property(struct power_supply *psy,
 313        enum power_supply_property psp,
 314        const union power_supply_propval *val)
 315{
 316        struct ltc294x_info *info = power_supply_get_drvdata(psy);
 317
 318        switch (psp) {
 319        case POWER_SUPPLY_PROP_CHARGE_NOW:
 320                return ltc294x_set_charge_now(info, val->intval);
 321        default:
 322                return -EPERM;
 323        }
 324}
 325
 326static int ltc294x_property_is_writeable(
 327        struct power_supply *psy, enum power_supply_property psp)
 328{
 329        switch (psp) {
 330        case POWER_SUPPLY_PROP_CHARGE_NOW:
 331                return 1;
 332        default:
 333                return 0;
 334        }
 335}
 336
 337static void ltc294x_update(struct ltc294x_info *info)
 338{
 339        int charge = ltc294x_read_charge_register(info);
 340
 341        if (charge != info->charge) {
 342                info->charge = charge;
 343                power_supply_changed(info->supply);
 344        }
 345}
 346
 347static void ltc294x_work(struct work_struct *work)
 348{
 349        struct ltc294x_info *info;
 350
 351        info = container_of(work, struct ltc294x_info, work.work);
 352        ltc294x_update(info);
 353        schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
 354}
 355
 356static enum power_supply_property ltc294x_properties[] = {
 357        POWER_SUPPLY_PROP_CHARGE_COUNTER,
 358        POWER_SUPPLY_PROP_CHARGE_NOW,
 359        POWER_SUPPLY_PROP_VOLTAGE_NOW,
 360        POWER_SUPPLY_PROP_CURRENT_NOW,
 361        POWER_SUPPLY_PROP_TEMP,
 362};
 363
 364static int ltc294x_i2c_remove(struct i2c_client *client)
 365{
 366        struct ltc294x_info *info = i2c_get_clientdata(client);
 367
 368        cancel_delayed_work(&info->work);
 369        power_supply_unregister(info->supply);
 370        return 0;
 371}
 372
 373static int ltc294x_i2c_probe(struct i2c_client *client,
 374        const struct i2c_device_id *id)
 375{
 376        struct power_supply_config psy_cfg = {};
 377        struct ltc294x_info *info;
 378        int ret;
 379        u32 prescaler_exp;
 380        s32 r_sense;
 381        struct device_node *np;
 382
 383        info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
 384        if (info == NULL)
 385                return -ENOMEM;
 386
 387        i2c_set_clientdata(client, info);
 388
 389        np = of_node_get(client->dev.of_node);
 390
 391        info->num_regs = (unsigned long)of_device_get_match_data(&client->dev);
 392        info->supply_desc.name = np->name;
 393
 394        /* r_sense can be negative, when sense+ is connected to the battery
 395         * instead of the sense-. This results in reversed measurements. */
 396        ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense);
 397        if (ret < 0) {
 398                dev_err(&client->dev,
 399                        "Could not find lltc,resistor-sense in devicetree\n");
 400                return ret;
 401        }
 402        info->r_sense = r_sense;
 403
 404        ret = of_property_read_u32(np, "lltc,prescaler-exponent",
 405                &prescaler_exp);
 406        if (ret < 0) {
 407                dev_warn(&client->dev,
 408                        "lltc,prescaler-exponent not in devicetree\n");
 409                prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
 410        }
 411
 412        if (info->num_regs == LTC2943_NUM_REGS) {
 413                if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
 414                        prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
 415                info->Qlsb = ((340 * 50000) / r_sense) /
 416                                (4096 / (1 << (2*prescaler_exp)));
 417        } else {
 418                if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
 419                        prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
 420                info->Qlsb = ((85 * 50000) / r_sense) /
 421                                (128 / (1 << prescaler_exp));
 422        }
 423
 424        info->client = client;
 425        info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY;
 426        info->supply_desc.properties = ltc294x_properties;
 427        if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB)
 428                info->supply_desc.num_properties =
 429                        ARRAY_SIZE(ltc294x_properties);
 430        else if (info->num_regs >= LTC294X_REG_CURRENT_LSB)
 431                info->supply_desc.num_properties =
 432                        ARRAY_SIZE(ltc294x_properties) - 1;
 433        else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB)
 434                info->supply_desc.num_properties =
 435                        ARRAY_SIZE(ltc294x_properties) - 2;
 436        else
 437                info->supply_desc.num_properties =
 438                        ARRAY_SIZE(ltc294x_properties) - 3;
 439        info->supply_desc.get_property = ltc294x_get_property;
 440        info->supply_desc.set_property = ltc294x_set_property;
 441        info->supply_desc.property_is_writeable = ltc294x_property_is_writeable;
 442        info->supply_desc.external_power_changed        = NULL;
 443
 444        psy_cfg.drv_data = info;
 445
 446        INIT_DELAYED_WORK(&info->work, ltc294x_work);
 447
 448        ret = ltc294x_reset(info, prescaler_exp);
 449        if (ret < 0) {
 450                dev_err(&client->dev, "Communication with chip failed\n");
 451                return ret;
 452        }
 453
 454        info->supply = power_supply_register(&client->dev, &info->supply_desc,
 455                                             &psy_cfg);
 456        if (IS_ERR(info->supply)) {
 457                dev_err(&client->dev, "failed to register ltc2941\n");
 458                return PTR_ERR(info->supply);
 459        } else {
 460                schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
 461        }
 462
 463        return 0;
 464}
 465
 466#ifdef CONFIG_PM_SLEEP
 467
 468static int ltc294x_suspend(struct device *dev)
 469{
 470        struct i2c_client *client = to_i2c_client(dev);
 471        struct ltc294x_info *info = i2c_get_clientdata(client);
 472
 473        cancel_delayed_work(&info->work);
 474        return 0;
 475}
 476
 477static int ltc294x_resume(struct device *dev)
 478{
 479        struct i2c_client *client = to_i2c_client(dev);
 480        struct ltc294x_info *info = i2c_get_clientdata(client);
 481
 482        schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
 483        return 0;
 484}
 485
 486static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume);
 487#define LTC294X_PM_OPS (&ltc294x_pm_ops)
 488
 489#else
 490#define LTC294X_PM_OPS NULL
 491#endif /* CONFIG_PM_SLEEP */
 492
 493
 494static const struct i2c_device_id ltc294x_i2c_id[] = {
 495        {"ltc2941", LTC2941_NUM_REGS},
 496        {"ltc2943", LTC2943_NUM_REGS},
 497        { },
 498};
 499MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
 500
 501static const struct of_device_id ltc294x_i2c_of_match[] = {
 502        {
 503                .compatible = "lltc,ltc2941",
 504                .data = (void *)LTC2941_NUM_REGS
 505        },
 506        {
 507                .compatible = "lltc,ltc2943",
 508                .data = (void *)LTC2943_NUM_REGS
 509        },
 510        { },
 511};
 512MODULE_DEVICE_TABLE(of, ltc294x_i2c_of_match);
 513
 514static struct i2c_driver ltc294x_driver = {
 515        .driver = {
 516                .name   = "LTC2941",
 517                .of_match_table = ltc294x_i2c_of_match,
 518                .pm     = LTC294X_PM_OPS,
 519        },
 520        .probe          = ltc294x_i2c_probe,
 521        .remove         = ltc294x_i2c_remove,
 522        .id_table       = ltc294x_i2c_id,
 523};
 524module_i2c_driver(ltc294x_driver);
 525
 526MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems");
 527MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products");
 528MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver");
 529MODULE_LICENSE("GPL");
 530