Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.32 381 lines 8.3 kB view raw
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 Celsius 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");