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 <asm/unaligned.h>
  28
  29#define DRIVER_VERSION                  "1.0.0"
  30
  31#define BQ27x00_REG_TEMP                0x06
  32#define BQ27x00_REG_VOLT                0x08
  33#define BQ27x00_REG_RSOC                0x0B /* Relative State-of-Charge */
  34#define BQ27x00_REG_AI                  0x14
  35#define BQ27x00_REG_FLAGS               0x0A
  36
  37/* If the system has several batteries we need a different name for each
  38 * of them...
  39 */
  40static DEFINE_IDR(battery_id);
  41static DEFINE_MUTEX(battery_mutex);
  42
  43struct bq27x00_device_info;
  44struct bq27x00_access_methods {
  45        int (*read)(u8 reg, int *rt_value, int b_single,
  46                struct bq27x00_device_info *di);
  47};
  48
  49struct bq27x00_device_info {
  50        struct device           *dev;
  51        int                     id;
  52        int                     voltage_uV;
  53        int                     current_uA;
  54        int                     temp_C;
  55        int                     charge_rsoc;
  56        struct bq27x00_access_methods   *bus;
  57        struct power_supply     bat;
  58
  59        struct i2c_client       *client;
  60};
  61
  62static enum power_supply_property bq27x00_battery_props[] = {
  63        POWER_SUPPLY_PROP_PRESENT,
  64        POWER_SUPPLY_PROP_VOLTAGE_NOW,
  65        POWER_SUPPLY_PROP_CURRENT_NOW,
  66        POWER_SUPPLY_PROP_CAPACITY,
  67        POWER_SUPPLY_PROP_TEMP,
  68};
  69
  70/*
  71 * Common code for BQ27x00 devices
  72 */
  73
  74static int bq27x00_read(u8 reg, int *rt_value, int b_single,
  75                        struct bq27x00_device_info *di)
  76{
  77        int ret;
  78
  79        ret = di->bus->read(reg, rt_value, b_single, di);
  80        *rt_value = be16_to_cpu(*rt_value);
  81
  82        return ret;
  83}
  84
  85/*
  86 * Return the battery temperature in Celcius degrees
  87 * Or < 0 if something fails.
  88 */
  89static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
  90{
  91        int ret;
  92        int temp = 0;
  93
  94        ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
  95        if (ret) {
  96                dev_err(di->dev, "error reading temperature\n");
  97                return ret;
  98        }
  99
 100        return (temp >> 2) - 273;
 101}
 102
 103/*
 104 * Return the battery Voltage in milivolts
 105 * Or < 0 if something fails.
 106 */
 107static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
 108{
 109        int ret;
 110        int volt = 0;
 111
 112        ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
 113        if (ret) {
 114                dev_err(di->dev, "error reading voltage\n");
 115                return ret;
 116        }
 117
 118        return volt;
 119}
 120
 121/*
 122 * Return the battery average current
 123 * Note that current can be negative signed as well
 124 * Or 0 if something fails.
 125 */
 126static int bq27x00_battery_current(struct bq27x00_device_info *di)
 127{
 128        int ret;
 129        int curr = 0;
 130        int flags = 0;
 131
 132        ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
 133        if (ret) {
 134                dev_err(di->dev, "error reading current\n");
 135                return 0;
 136        }
 137        ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
 138        if (ret < 0) {
 139                dev_err(di->dev, "error reading flags\n");
 140                return 0;
 141        }
 142        if ((flags & (1 << 7)) != 0) {
 143                dev_dbg(di->dev, "negative current!\n");
 144                return -curr;
 145        }
 146        return curr;
 147}
 148
 149/*
 150 * Return the battery Relative State-of-Charge
 151 * Or < 0 if something fails.
 152 */
 153static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
 154{
 155        int ret;
 156        int rsoc = 0;
 157
 158        ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
 159        if (ret) {
 160                dev_err(di->dev, "error reading relative State-of-Charge\n");
 161                return ret;
 162        }
 163
 164        return rsoc >> 8;
 165}
 166
 167#define to_bq27x00_device_info(x) container_of((x), \
 168                                struct bq27x00_device_info, bat);
 169
 170static int bq27x00_battery_get_property(struct power_supply *psy,
 171                                        enum power_supply_property psp,
 172                                        union power_supply_propval *val)
 173{
 174        struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
 175
 176        switch (psp) {
 177        case POWER_SUPPLY_PROP_VOLTAGE_NOW:
 178        case POWER_SUPPLY_PROP_PRESENT:
 179                val->intval = bq27x00_battery_voltage(di);
 180                if (psp == POWER_SUPPLY_PROP_PRESENT)
 181                        val->intval = val->intval <= 0 ? 0 : 1;
 182                break;
 183        case POWER_SUPPLY_PROP_CURRENT_NOW:
 184                val->intval = bq27x00_battery_current(di);
 185                break;
 186        case POWER_SUPPLY_PROP_CAPACITY:
 187                val->intval = bq27x00_battery_rsoc(di);
 188                break;
 189        case POWER_SUPPLY_PROP_TEMP:
 190                val->intval = bq27x00_battery_temperature(di);
 191                break;
 192        default:
 193                return -EINVAL;
 194        }
 195
 196        return 0;
 197}
 198
 199static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
 200{
 201        di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
 202        di->bat.properties = bq27x00_battery_props;
 203        di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
 204        di->bat.get_property = bq27x00_battery_get_property;
 205        di->bat.external_power_changed = NULL;
 206}
 207
 208/*
 209 * BQ27200 specific code
 210 */
 211
 212static int bq27200_read(u8 reg, int *rt_value, int b_single,
 213                        struct bq27x00_device_info *di)
 214{
 215        struct i2c_client *client = di->client;
 216        struct i2c_msg msg[1];
 217        unsigned char data[2];
 218        int err;
 219
 220        if (!client->adapter)
 221                return -ENODEV;
 222
 223        msg->addr = client->addr;
 224        msg->flags = 0;
 225        msg->len = 1;
 226        msg->buf = data;
 227
 228        data[0] = reg;
 229        err = i2c_transfer(client->adapter, msg, 1);
 230
 231        if (err >= 0) {
 232                if (!b_single)
 233                        msg->len = 2;
 234                else
 235                        msg->len = 1;
 236
 237                msg->flags = I2C_M_RD;
 238                err = i2c_transfer(client->adapter, msg, 1);
 239                if (err >= 0) {
 240                        if (!b_single)
 241                                *rt_value = get_unaligned_be16(data);
 242                        else
 243                                *rt_value = data[0];
 244
 245                        return 0;
 246                }
 247        }
 248        return err;
 249}
 250
 251static int bq27200_battery_probe(struct i2c_client *client,
 252                                 const struct i2c_device_id *id)
 253{
 254        char *name;
 255        struct bq27x00_device_info *di;
 256        struct bq27x00_access_methods *bus;
 257        int num;
 258        int retval = 0;
 259
 260        /* Get new ID for the new battery device */
 261        retval = idr_pre_get(&battery_id, GFP_KERNEL);
 262        if (retval == 0)
 263                return -ENOMEM;
 264        mutex_lock(&battery_mutex);
 265        retval = idr_get_new(&battery_id, client, &num);
 266        mutex_unlock(&battery_mutex);
 267        if (retval < 0)
 268                return retval;
 269
 270        name = kasprintf(GFP_KERNEL, "bq27200-%d", num);
 271        if (!name) {
 272                dev_err(&client->dev, "failed to allocate device name\n");
 273                retval = -ENOMEM;
 274                goto batt_failed_1;
 275        }
 276
 277        di = kzalloc(sizeof(*di), GFP_KERNEL);
 278        if (!di) {
 279                dev_err(&client->dev, "failed to allocate device info data\n");
 280                retval = -ENOMEM;
 281                goto batt_failed_2;
 282        }
 283        di->id = num;
 284
 285        bus = kzalloc(sizeof(*bus), GFP_KERNEL);
 286        if (!bus) {
 287                dev_err(&client->dev, "failed to allocate access method "
 288                                        "data\n");
 289                retval = -ENOMEM;
 290                goto batt_failed_3;
 291        }
 292
 293        i2c_set_clientdata(client, di);
 294        di->dev = &client->dev;
 295        di->bat.name = name;
 296        bus->read = &bq27200_read;
 297        di->bus = bus;
 298        di->client = client;
 299
 300        bq27x00_powersupply_init(di);
 301
 302        retval = power_supply_register(&client->dev, &di->bat);
 303        if (retval) {
 304                dev_err(&client->dev, "failed to register battery\n");
 305                goto batt_failed_4;
 306        }
 307
 308        dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 309
 310        return 0;
 311
 312batt_failed_4:
 313        kfree(bus);
 314batt_failed_3:
 315        kfree(di);
 316batt_failed_2:
 317        kfree(name);
 318batt_failed_1:
 319        mutex_lock(&battery_mutex);
 320        idr_remove(&battery_id, num);
 321        mutex_unlock(&battery_mutex);
 322
 323        return retval;
 324}
 325
 326static int bq27200_battery_remove(struct i2c_client *client)
 327{
 328        struct bq27x00_device_info *di = i2c_get_clientdata(client);
 329
 330        power_supply_unregister(&di->bat);
 331
 332        kfree(di->bat.name);
 333
 334        mutex_lock(&battery_mutex);
 335        idr_remove(&battery_id, di->id);
 336        mutex_unlock(&battery_mutex);
 337
 338        kfree(di);
 339
 340        return 0;
 341}
 342
 343/*
 344 * Module stuff
 345 */
 346
 347static const struct i2c_device_id bq27200_id[] = {
 348        { "bq27200", 0 },
 349        {},
 350};
 351
 352static struct i2c_driver bq27200_battery_driver = {
 353        .driver = {
 354                .name = "bq27200-battery",
 355        },
 356        .probe = bq27200_battery_probe,
 357        .remove = bq27200_battery_remove,
 358        .id_table = bq27200_id,
 359};
 360
 361static int __init bq27x00_battery_init(void)
 362{
 363        int ret;
 364
 365        ret = i2c_add_driver(&bq27200_battery_driver);
 366        if (ret)
 367                printk(KERN_ERR "Unable to register BQ27200 driver\n");
 368
 369        return ret;
 370}
 371module_init(bq27x00_battery_init);
 372
 373static void __exit bq27x00_battery_exit(void)
 374{
 375        i2c_del_driver(&bq27200_battery_driver);
 376}
 377module_exit(bq27x00_battery_exit);
 378
 379MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 380MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
 381MODULE_LICENSE("GPL");
 382
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.