linux/drivers/power/supply/bq27xxx_battery_i2c.c
<<
>>
Prefs
   1/*
   2 * BQ27xxx battery monitor I2C driver
   3 *
   4 * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
   5 *      Andrew F. Davis <afd@ti.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12 * kind, whether express or implied; without even the implied warranty
  13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/i2c.h>
  18#include <linux/interrupt.h>
  19#include <linux/module.h>
  20#include <asm/unaligned.h>
  21
  22#include <linux/power/bq27xxx_battery.h>
  23
  24static DEFINE_IDR(battery_id);
  25static DEFINE_MUTEX(battery_mutex);
  26
  27static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
  28{
  29        struct bq27xxx_device_info *di = data;
  30
  31        bq27xxx_battery_update(di);
  32
  33        return IRQ_HANDLED;
  34}
  35
  36static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
  37                                    bool single)
  38{
  39        struct i2c_client *client = to_i2c_client(di->dev);
  40        struct i2c_msg msg[2];
  41        u8 data[2];
  42        int ret;
  43
  44        if (!client->adapter)
  45                return -ENODEV;
  46
  47        msg[0].addr = client->addr;
  48        msg[0].flags = 0;
  49        msg[0].buf = &reg;
  50        msg[0].len = sizeof(reg);
  51        msg[1].addr = client->addr;
  52        msg[1].flags = I2C_M_RD;
  53        msg[1].buf = data;
  54        if (single)
  55                msg[1].len = 1;
  56        else
  57                msg[1].len = 2;
  58
  59        ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
  60        if (ret < 0)
  61                return ret;
  62
  63        if (!single)
  64                ret = get_unaligned_le16(data);
  65        else
  66                ret = data[0];
  67
  68        return ret;
  69}
  70
  71static int bq27xxx_battery_i2c_write(struct bq27xxx_device_info *di, u8 reg,
  72                                     int value, bool single)
  73{
  74        struct i2c_client *client = to_i2c_client(di->dev);
  75        struct i2c_msg msg;
  76        u8 data[4];
  77        int ret;
  78
  79        if (!client->adapter)
  80                return -ENODEV;
  81
  82        data[0] = reg;
  83        if (single) {
  84                data[1] = (u8) value;
  85                msg.len = 2;
  86        } else {
  87                put_unaligned_le16(value, &data[1]);
  88                msg.len = 3;
  89        }
  90
  91        msg.buf = data;
  92        msg.addr = client->addr;
  93        msg.flags = 0;
  94
  95        ret = i2c_transfer(client->adapter, &msg, 1);
  96        if (ret < 0)
  97                return ret;
  98        if (ret != 1)
  99                return -EINVAL;
 100        return 0;
 101}
 102
 103static int bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info *di, u8 reg,
 104                                         u8 *data, int len)
 105{
 106        struct i2c_client *client = to_i2c_client(di->dev);
 107        int ret;
 108
 109        if (!client->adapter)
 110                return -ENODEV;
 111
 112        ret = i2c_smbus_read_i2c_block_data(client, reg, len, data);
 113        if (ret < 0)
 114                return ret;
 115        if (ret != len)
 116                return -EINVAL;
 117        return 0;
 118}
 119
 120static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
 121                                          u8 reg, u8 *data, int len)
 122{
 123        struct i2c_client *client = to_i2c_client(di->dev);
 124        struct i2c_msg msg;
 125        u8 buf[33];
 126        int ret;
 127
 128        if (!client->adapter)
 129                return -ENODEV;
 130
 131        buf[0] = reg;
 132        memcpy(&buf[1], data, len);
 133
 134        msg.buf = buf;
 135        msg.addr = client->addr;
 136        msg.flags = 0;
 137        msg.len = len + 1;
 138
 139        ret = i2c_transfer(client->adapter, &msg, 1);
 140        if (ret < 0)
 141                return ret;
 142        if (ret != 1)
 143                return -EINVAL;
 144        return 0;
 145}
 146
 147static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
 148                                     const struct i2c_device_id *id)
 149{
 150        struct bq27xxx_device_info *di;
 151        int ret;
 152        char *name;
 153        int num;
 154
 155        /* Get new ID for the new battery device */
 156        mutex_lock(&battery_mutex);
 157        num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
 158        mutex_unlock(&battery_mutex);
 159        if (num < 0)
 160                return num;
 161
 162        name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
 163        if (!name)
 164                goto err_mem;
 165
 166        di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
 167        if (!di)
 168                goto err_mem;
 169
 170        di->id = num;
 171        di->dev = &client->dev;
 172        di->chip = id->driver_data;
 173        di->name = name;
 174
 175        di->bus.read = bq27xxx_battery_i2c_read;
 176        di->bus.write = bq27xxx_battery_i2c_write;
 177        di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read;
 178        di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write;
 179
 180        ret = bq27xxx_battery_setup(di);
 181        if (ret)
 182                goto err_failed;
 183
 184        /* Schedule a polling after about 1 min */
 185        schedule_delayed_work(&di->work, 60 * HZ);
 186
 187        i2c_set_clientdata(client, di);
 188
 189        if (client->irq) {
 190                ret = devm_request_threaded_irq(&client->dev, client->irq,
 191                                NULL, bq27xxx_battery_irq_handler_thread,
 192                                IRQF_ONESHOT,
 193                                di->name, di);
 194                if (ret) {
 195                        dev_err(&client->dev,
 196                                "Unable to register IRQ %d error %d\n",
 197                                client->irq, ret);
 198                        return ret;
 199                }
 200        }
 201
 202        return 0;
 203
 204err_mem:
 205        ret = -ENOMEM;
 206
 207err_failed:
 208        mutex_lock(&battery_mutex);
 209        idr_remove(&battery_id, num);
 210        mutex_unlock(&battery_mutex);
 211
 212        return ret;
 213}
 214
 215static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
 216{
 217        struct bq27xxx_device_info *di = i2c_get_clientdata(client);
 218
 219        bq27xxx_battery_teardown(di);
 220
 221        mutex_lock(&battery_mutex);
 222        idr_remove(&battery_id, di->id);
 223        mutex_unlock(&battery_mutex);
 224
 225        return 0;
 226}
 227
 228static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
 229        { "bq27200", BQ27000 },
 230        { "bq27210", BQ27010 },
 231        { "bq27500", BQ2750X },
 232        { "bq27510", BQ2751X },
 233        { "bq27520", BQ2752X },
 234        { "bq27500-1", BQ27500 },
 235        { "bq27510g1", BQ27510G1 },
 236        { "bq27510g2", BQ27510G2 },
 237        { "bq27510g3", BQ27510G3 },
 238        { "bq27520g1", BQ27520G1 },
 239        { "bq27520g2", BQ27520G2 },
 240        { "bq27520g3", BQ27520G3 },
 241        { "bq27520g4", BQ27520G4 },
 242        { "bq27521", BQ27521 },
 243        { "bq27530", BQ27530 },
 244        { "bq27531", BQ27531 },
 245        { "bq27541", BQ27541 },
 246        { "bq27542", BQ27542 },
 247        { "bq27546", BQ27546 },
 248        { "bq27742", BQ27742 },
 249        { "bq27545", BQ27545 },
 250        { "bq27411", BQ27411 },
 251        { "bq27421", BQ27421 },
 252        { "bq27425", BQ27425 },
 253        { "bq27426", BQ27426 },
 254        { "bq27441", BQ27441 },
 255        { "bq27621", BQ27621 },
 256        { "bq27z561", BQ27Z561 },
 257        { "bq28z610", BQ28Z610 },
 258        {},
 259};
 260MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
 261
 262#ifdef CONFIG_OF
 263static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
 264        { .compatible = "ti,bq27200" },
 265        { .compatible = "ti,bq27210" },
 266        { .compatible = "ti,bq27500" },
 267        { .compatible = "ti,bq27510" },
 268        { .compatible = "ti,bq27520" },
 269        { .compatible = "ti,bq27500-1" },
 270        { .compatible = "ti,bq27510g1" },
 271        { .compatible = "ti,bq27510g2" },
 272        { .compatible = "ti,bq27510g3" },
 273        { .compatible = "ti,bq27520g1" },
 274        { .compatible = "ti,bq27520g2" },
 275        { .compatible = "ti,bq27520g3" },
 276        { .compatible = "ti,bq27520g4" },
 277        { .compatible = "ti,bq27521" },
 278        { .compatible = "ti,bq27530" },
 279        { .compatible = "ti,bq27531" },
 280        { .compatible = "ti,bq27541" },
 281        { .compatible = "ti,bq27542" },
 282        { .compatible = "ti,bq27546" },
 283        { .compatible = "ti,bq27742" },
 284        { .compatible = "ti,bq27545" },
 285        { .compatible = "ti,bq27411" },
 286        { .compatible = "ti,bq27421" },
 287        { .compatible = "ti,bq27425" },
 288        { .compatible = "ti,bq27426" },
 289        { .compatible = "ti,bq27441" },
 290        { .compatible = "ti,bq27621" },
 291        { .compatible = "ti,bq27z561" },
 292        { .compatible = "ti,bq28z610" },
 293        {},
 294};
 295MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
 296#endif
 297
 298static struct i2c_driver bq27xxx_battery_i2c_driver = {
 299        .driver = {
 300                .name = "bq27xxx-battery",
 301                .of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table),
 302        },
 303        .probe = bq27xxx_battery_i2c_probe,
 304        .remove = bq27xxx_battery_i2c_remove,
 305        .id_table = bq27xxx_i2c_id_table,
 306};
 307module_i2c_driver(bq27xxx_battery_i2c_driver);
 308
 309MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
 310MODULE_DESCRIPTION("BQ27xxx battery monitor i2c driver");
 311MODULE_LICENSE("GPL");
 312