linux/drivers/power/bq27x00_battery.c
<<
>>
Prefs
   1/*
   2 * BQ27x00 battery driver
   3 *
   4 * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
   5 * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
   6 *
   7 * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
   8 *
   9 * This package is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16 *
  17 */
  18#include <linux/module.h>
  19#include <linux/param.h>
  20#include <linux/jiffies.h>
  21#include <linux/workqueue.h>
  22#include <linux/delay.h>
  23#include <linux/platform_device.h>
  24#include <linux/power_supply.h>
  25#include <linux/idr.h>
  26#include <linux/i2c.h>
  27#include <linux/slab.h>
  28#include <asm/unaligned.h>
  29
  30#define DRIVER_VERSION                  "1.1.0"
  31
  32#define BQ27x00_REG_TEMP                0x06
  33#define BQ27x00_REG_VOLT                0x08
  34#define BQ27x00_REG_AI                  0x14
  35#define BQ27x00_REG_FLAGS               0x0A
  36#define BQ27x00_REG_TTE                 0x16
  37#define BQ27x00_REG_TTF                 0x18
  38#define BQ27x00_REG_TTECP               0x26
  39
  40#define BQ27000_REG_RSOC                0x0B /* Relative State-of-Charge */
  41#define BQ27000_FLAG_CHGS               BIT(7)
  42
  43#define BQ27500_REG_SOC                 0x2c
  44#define BQ27500_FLAG_DSC                BIT(0)
  45#define BQ27500_FLAG_FC                 BIT(9)
  46
  47/* If the system has several batteries we need a different name for each
  48 * of them...
  49 */
  50static DEFINE_IDR(battery_id);
  51static DEFINE_MUTEX(battery_mutex);
  52
  53struct bq27x00_device_info;
  54struct bq27x00_access_methods {
  55        int (*read)(u8 reg, int *rt_value, int b_single,
  56                struct bq27x00_device_info *di);
  57};
  58
  59enum bq27x00_chip { BQ27000, BQ27500 };
  60
  61struct bq27x00_device_info {
  62        struct device           *dev;
  63        int                     id;
  64        struct bq27x00_access_methods   *bus;
  65        struct power_supply     bat;
  66        enum bq27x00_chip       chip;
  67
  68        struct i2c_client       *client;
  69};
  70
  71static enum power_supply_property bq27x00_battery_props[] = {
  72        POWER_SUPPLY_PROP_STATUS,
  73        POWER_SUPPLY_PROP_PRESENT,
  74        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  75        POWER_SUPPLY_PROP_CURRENT_NOW,
  76        POWER_SUPPLY_PROP_CAPACITY,
  77        POWER_SUPPLY_PROP_TEMP,
  78        POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
  79        POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
  80        POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
  81};
  82
  83/*
  84 * Common code for BQ27x00 devices
  85 */
  86
  87static int bq27x00_read(u8 reg, int *rt_value, int b_single,
  88                        struct bq27x00_device_info *di)
  89{
  90        return di->bus->read(reg, rt_value, b_single, di);
  91}
  92
  93/*
  94 * Return the battery temperature in tenths of degree Celsius
  95 * Or < 0 if something fails.
  96 */
  97static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
  98{
  99        int ret;
 100        int temp = 0;
 101
 102        ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
 103        if (ret) {
 104                dev_err(di->dev, "error reading temperature\n");
 105                return ret;
 106        }
 107
 108        if (di->chip == BQ27500)
 109                return temp - 2731;
 110        else
 111                return ((temp >> 2) - 273) * 10;
 112}
 113
 114/*
 115 * Return the battery Voltage in milivolts
 116 * Or < 0 if something fails.
 117 */
 118static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
 119{
 120        int ret;
 121        int volt = 0;
 122
 123        ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
 124        if (ret) {
 125                dev_err(di->dev, "error reading voltage\n");
 126                return ret;
 127        }
 128
 129        return volt * 1000;
 130}
 131
 132/*
 133 * Return the battery average current
 134 * Note that current can be negative signed as well
 135 * Or 0 if something fails.
 136 */
 137static int bq27x00_battery_current(struct bq27x00_device_info *di)
 138{
 139        int ret;
 140        int curr = 0;
 141        int flags = 0;
 142
 143        ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
 144        if (ret) {
 145                dev_err(di->dev, "error reading current\n");
 146                return 0;
 147        }
 148
 149        if (di->chip == BQ27500) {
 150                /* bq27500 returns signed value */
 151                curr = (int)(s16)curr;
 152        } else {
 153                ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
 154                if (ret < 0) {
 155                        dev_err(di->dev, "error reading flags\n");
 156                        return 0;
 157                }
 158                if (flags & BQ27000_FLAG_CHGS) {
 159                        dev_dbg(di->dev, "negative current!\n");
 160                        curr = -curr;
 161                }
 162        }
 163
 164        return curr * 1000;
 165}
 166
 167/*
 168 * Return the battery Relative State-of-Charge
 169 * Or < 0 if something fails.
 170 */
 171static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
 172{
 173        int ret;
 174        int rsoc = 0;
 175
 176        if (di->chip == BQ27500)
 177                ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di);
 178        else
 179                ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di);
 180        if (ret) {
 181                dev_err(di->dev, "error reading relative State-of-Charge\n");
 182                return ret;
 183        }
 184
 185        return rsoc;
 186}
 187
 188static int bq27x00_battery_status(struct bq27x00_device_info *di,
 189                                  union power_supply_propval *val)
 190{
 191        int flags = 0;
 192        int status;
 193        int ret;
 194
 195        ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
 196        if (ret < 0) {
 197                dev_err(di->dev, "error reading flags\n");
 198                return ret;
 199        }
 200
 201        if (di->chip == BQ27500) {
 202                if (flags & BQ27500_FLAG_FC)
 203                        status = POWER_SUPPLY_STATUS_FULL;
 204                else if (flags & BQ27500_FLAG_DSC)
 205                        status = POWER_SUPPLY_STATUS_DISCHARGING;
 206                else
 207                        status = POWER_SUPPLY_STATUS_CHARGING;
 208        } else {
 209                if (flags & BQ27000_FLAG_CHGS)
 210                        status = POWER_SUPPLY_STATUS_CHARGING;
 211                else
 212                        status = POWER_SUPPLY_STATUS_DISCHARGING;
 213        }
 214
 215        val->intval = status;
 216        return 0;
 217}
 218
 219/*
 220 * Read a time register.
 221 * Return < 0 if something fails.
 222 */
 223static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
 224                                union power_supply_propval *val)
 225{
 226        int tval = 0;
 227        int ret;
 228
 229        ret = bq27x00_read(reg, &tval, 0, di);
 230        if (ret) {
 231                dev_err(di->dev, "error reading register %02x\n", reg);
 232                return ret;
 233        }
 234
 235        if (tval == 65535)
 236                return -ENODATA;
 237
 238        val->intval = tval * 60;
 239        return 0;
 240}
 241
 242#define to_bq27x00_device_info(x) container_of((x), \
 243                                struct bq27x00_device_info, bat);
 244
 245static int bq27x00_battery_get_property(struct power_supply *psy,
 246                                        enum power_supply_property psp,
 247                                        union power_supply_propval *val)
 248{
 249        int ret = 0;
 250        struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
 251
 252        switch (psp) {
 253        case POWER_SUPPLY_PROP_STATUS:
 254                ret = bq27x00_battery_status(di, val);
 255                break;
 256        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 257        case POWER_SUPPLY_PROP_PRESENT:
 258                val->intval = bq27x00_battery_voltage(di);
 259                if (psp == POWER_SUPPLY_PROP_PRESENT)
 260                        val->intval = val->intval <= 0 ? 0 : 1;
 261                break;
 262        case POWER_SUPPLY_PROP_CURRENT_NOW:
 263                val->intval = bq27x00_battery_current(di);
 264                break;
 265        case POWER_SUPPLY_PROP_CAPACITY:
 266                val->intval = bq27x00_battery_rsoc(di);
 267                break;
 268        case POWER_SUPPLY_PROP_TEMP:
 269                val->intval = bq27x00_battery_temperature(di);
 270                break;
 271        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
 272                ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val);
 273                break;
 274        case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
 275                ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val);
 276                break;
 277        case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
 278                ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val);
 279                break;
 280        default:
 281                return -EINVAL;
 282        }
 283
 284        return ret;
 285}
 286
 287static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
 288{
 289        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
 290        di->bat.properties = bq27x00_battery_props;
 291        di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
 292        di->bat.get_property = bq27x00_battery_get_property;
 293        di->bat.external_power_changed = NULL;
 294}
 295
 296/*
 297 * i2c specific code
 298 */
 299
 300static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single,
 301                        struct bq27x00_device_info *di)
 302{
 303        struct i2c_client *client = di->client;
 304        struct i2c_msg msg[1];
 305        unsigned char data[2];
 306        int err;
 307
 308        if (!client->adapter)
 309                return -ENODEV;
 310
 311        msg->addr = client->addr;
 312        msg->flags = 0;
 313        msg->len = 1;
 314        msg->buf = data;
 315
 316        data[0] = reg;
 317        err = i2c_transfer(client->adapter, msg, 1);
 318
 319        if (err >= 0) {
 320                if (!b_single)
 321                        msg->len = 2;
 322                else
 323                        msg->len = 1;
 324
 325                msg->flags = I2C_M_RD;
 326                err = i2c_transfer(client->adapter, msg, 1);
 327                if (err >= 0) {
 328                        if (!b_single)
 329                                *rt_value = get_unaligned_le16(data);
 330                        else
 331                                *rt_value = data[0];
 332
 333                        return 0;
 334                }
 335        }
 336        return err;
 337}
 338
 339static int bq27x00_battery_probe(struct i2c_client *client,
 340                                 const struct i2c_device_id *id)
 341{
 342        char *name;
 343        struct bq27x00_device_info *di;
 344        struct bq27x00_access_methods *bus;
 345        int num;
 346        int retval = 0;
 347
 348        /* Get new ID for the new battery device */
 349        retval = idr_pre_get(&battery_id, GFP_KERNEL);
 350        if (retval == 0)
 351                return -ENOMEM;
 352        mutex_lock(&battery_mutex);
 353        retval = idr_get_new(&battery_id, client, &num);
 354        mutex_unlock(&battery_mutex);
 355        if (retval < 0)
 356                return retval;
 357
 358        name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
 359        if (!name) {
 360                dev_err(&client->dev, "failed to allocate device name\n");
 361                retval = -ENOMEM;
 362                goto batt_failed_1;
 363        }
 364
 365        di = kzalloc(sizeof(*di), GFP_KERNEL);
 366        if (!di) {
 367                dev_err(&client->dev, "failed to allocate device info data\n");
 368                retval = -ENOMEM;
 369                goto batt_failed_2;
 370        }
 371        di->id = num;
 372        di->chip = id->driver_data;
 373
 374        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
 375        if (!bus) {
 376                dev_err(&client->dev, "failed to allocate access method "
 377                                        "data\n");
 378                retval = -ENOMEM;
 379                goto batt_failed_3;
 380        }
 381
 382        i2c_set_clientdata(client, di);
 383        di->dev = &client->dev;
 384        di->bat.name = name;
 385        bus->read = &bq27x00_read_i2c;
 386        di->bus = bus;
 387        di->client = client;
 388
 389        bq27x00_powersupply_init(di);
 390
 391        retval = power_supply_register(&client->dev, &di->bat);
 392        if (retval) {
 393                dev_err(&client->dev, "failed to register battery\n");
 394                goto batt_failed_4;
 395        }
 396
 397        dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 398
 399        return 0;
 400
 401batt_failed_4:
 402        kfree(bus);
 403batt_failed_3:
 404        kfree(di);
 405batt_failed_2:
 406        kfree(name);
 407batt_failed_1:
 408        mutex_lock(&battery_mutex);
 409        idr_remove(&battery_id, num);
 410        mutex_unlock(&battery_mutex);
 411
 412        return retval;
 413}
 414
 415static int bq27x00_battery_remove(struct i2c_client *client)
 416{
 417        struct bq27x00_device_info *di = i2c_get_clientdata(client);
 418
 419        power_supply_unregister(&di->bat);
 420
 421        kfree(di->bat.name);
 422
 423        mutex_lock(&battery_mutex);
 424        idr_remove(&battery_id, di->id);
 425        mutex_unlock(&battery_mutex);
 426
 427        kfree(di);
 428
 429        return 0;
 430}
 431
 432/*
 433 * Module stuff
 434 */
 435
 436static const struct i2c_device_id bq27x00_id[] = {
 437        { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */
 438        { "bq27500", BQ27500 },
 439        {},
 440};
 441
 442static struct i2c_driver bq27x00_battery_driver = {
 443        .driver = {
 444                .name = "bq27x00-battery",
 445        },
 446        .probe = bq27x00_battery_probe,
 447        .remove = bq27x00_battery_remove,
 448        .id_table = bq27x00_id,
 449};
 450
 451static int __init bq27x00_battery_init(void)
 452{
 453        int ret;
 454
 455        ret = i2c_add_driver(&bq27x00_battery_driver);
 456        if (ret)
 457                printk(KERN_ERR "Unable to register BQ27x00 driver\n");
 458
 459        return ret;
 460}
 461module_init(bq27x00_battery_init);
 462
 463static void __exit bq27x00_battery_exit(void)
 464{
 465        i2c_del_driver(&bq27x00_battery_driver);
 466}
 467module_exit(bq27x00_battery_exit);
 468
 469MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 470MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
 471MODULE_LICENSE("GPL");
 472
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.