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