blob: 44bc76be0780ba3934683912911eff7ebfeedee1 [file] [log] [blame]
Rodolfo Giomettib996ad02008-08-20 16:52:58 -07001/*
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>
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +02006 * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
Rodolfo Giomettib996ad02008-08-20 16:52:58 -07007 *
8 * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 */
19#include <linux/module.h>
20#include <linux/param.h>
21#include <linux/jiffies.h>
22#include <linux/workqueue.h>
23#include <linux/delay.h>
24#include <linux/platform_device.h>
25#include <linux/power_supply.h>
26#include <linux/idr.h>
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070027#include <linux/i2c.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Harvey Harrison8aef7e82008-09-22 14:53:50 -070029#include <asm/unaligned.h>
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070030
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +020031#include <linux/power/bq27x00_battery.h>
32
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020033#define DRIVER_VERSION "1.1.0"
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070034
35#define BQ27x00_REG_TEMP 0x06
36#define BQ27x00_REG_VOLT 0x08
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070037#define BQ27x00_REG_AI 0x14
38#define BQ27x00_REG_FLAGS 0x0A
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +020039#define BQ27x00_REG_TTE 0x16
40#define BQ27x00_REG_TTF 0x18
41#define BQ27x00_REG_TTECP 0x26
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070042
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020043#define BQ27000_REG_RSOC 0x0B /* Relative State-of-Charge */
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +020044#define BQ27000_FLAG_CHGS BIT(7)
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020045
46#define BQ27500_REG_SOC 0x2c
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +020047#define BQ27500_FLAG_DSC BIT(0)
48#define BQ27500_FLAG_FC BIT(9)
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020049
Pali Rohára2e51182010-05-24 20:52:13 +020050#define BQ27000_RS 20 /* Resistor sense */
51
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070052struct bq27x00_device_info;
53struct bq27x00_access_methods {
Lars-Peter Clausena40402e2010-05-24 19:37:58 +020054 int (*read)(struct bq27x00_device_info *, u8 reg, int *rt_value,
55 bool single);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070056};
57
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020058enum bq27x00_chip { BQ27000, BQ27500 };
59
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070060struct bq27x00_device_info {
61 struct device *dev;
62 int id;
Grazvydas Ignotase20908d2010-02-12 23:57:23 +020063 enum bq27x00_chip chip;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070064
Lars-Peter Clausena40402e2010-05-24 19:37:58 +020065 struct power_supply bat;
66
67 struct bq27x00_access_methods bus;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070068};
69
70static enum power_supply_property bq27x00_battery_props[] = {
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +020071 POWER_SUPPLY_PROP_STATUS,
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070072 POWER_SUPPLY_PROP_PRESENT,
73 POWER_SUPPLY_PROP_VOLTAGE_NOW,
74 POWER_SUPPLY_PROP_CURRENT_NOW,
75 POWER_SUPPLY_PROP_CAPACITY,
76 POWER_SUPPLY_PROP_TEMP,
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +020077 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
78 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
79 POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
Lars-Peter Clausen5661f332010-05-24 20:36:52 +020080 POWER_SUPPLY_PROP_TECHNOLOGY,
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070081};
82
83/*
84 * Common code for BQ27x00 devices
85 */
86
Lars-Peter Clausena40402e2010-05-24 19:37:58 +020087static inline int bq27x00_read(struct bq27x00_device_info *di, u8 reg,
88 int *rt_value, bool single)
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070089{
Lars-Peter Clausena40402e2010-05-24 19:37:58 +020090 return di->bus.read(di, reg, rt_value, single);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070091}
92
93/*
Grazvydas Ignotasb4de3602010-02-12 23:57:13 +020094 * Return the battery temperature in tenths of degree Celsius
Rodolfo Giomettib996ad02008-08-20 16:52:58 -070095 * 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
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200102 ret = bq27x00_read(di, BQ27x00_REG_TEMP, &temp, false);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700103 if (ret) {
104 dev_err(di->dev, "error reading temperature\n");
105 return ret;
106 }
107
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200108 if (di->chip == BQ27500)
109 return temp - 2731;
110 else
Lars-Peter Clausen0e9f3042010-05-24 20:20:57 +0200111 return ((temp * 5) - 5463) / 2;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700112}
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
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200123 ret = bq27x00_read(di, BQ27x00_REG_VOLT, &volt, false);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700124 if (ret) {
125 dev_err(di->dev, "error reading voltage\n");
126 return ret;
127 }
128
Grazvydas Ignotasafbc74f2010-02-27 17:06:44 +0200129 return volt * 1000;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700130}
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
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200143 ret = bq27x00_read(di, BQ27x00_REG_AI, &curr, false);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700144 if (ret) {
145 dev_err(di->dev, "error reading current\n");
146 return 0;
147 }
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200148
149 if (di->chip == BQ27500) {
150 /* bq27500 returns signed value */
Pali Rohára2e51182010-05-24 20:52:13 +0200151 curr = (int)((s16)curr) * 1000;
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200152 } else {
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200153 ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false);
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200154 if (ret < 0) {
155 dev_err(di->dev, "error reading flags\n");
156 return 0;
157 }
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200158 if (flags & BQ27000_FLAG_CHGS) {
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200159 dev_dbg(di->dev, "negative current!\n");
Grazvydas Ignotasafbc74f2010-02-27 17:06:44 +0200160 curr = -curr;
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200161 }
Pali Rohára2e51182010-05-24 20:52:13 +0200162 curr = curr * 3570 / BQ27000_RS;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700163 }
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200164
Pali Rohára2e51182010-05-24 20:52:13 +0200165 return curr;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700166}
167
168/*
169 * Return the battery Relative State-of-Charge
170 * Or < 0 if something fails.
171 */
172static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
173{
174 int ret;
175 int rsoc = 0;
176
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200177 if (di->chip == BQ27500)
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200178 ret = bq27x00_read(di, BQ27500_REG_SOC, &rsoc, false);
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200179 else
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200180 ret = bq27x00_read(di, BQ27000_REG_RSOC, &rsoc, true);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700181 if (ret) {
182 dev_err(di->dev, "error reading relative State-of-Charge\n");
183 return ret;
184 }
185
Grazvydas Ignotas97f70c22010-02-12 23:56:46 +0200186 return rsoc;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700187}
188
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200189static int bq27x00_battery_status(struct bq27x00_device_info *di,
190 union power_supply_propval *val)
191{
192 int flags = 0;
193 int status;
194 int ret;
195
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200196 ret = bq27x00_read(di, BQ27x00_REG_FLAGS, &flags, false);
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200197 if (ret < 0) {
198 dev_err(di->dev, "error reading flags\n");
199 return ret;
200 }
201
202 if (di->chip == BQ27500) {
203 if (flags & BQ27500_FLAG_FC)
204 status = POWER_SUPPLY_STATUS_FULL;
205 else if (flags & BQ27500_FLAG_DSC)
206 status = POWER_SUPPLY_STATUS_DISCHARGING;
207 else
208 status = POWER_SUPPLY_STATUS_CHARGING;
209 } else {
210 if (flags & BQ27000_FLAG_CHGS)
211 status = POWER_SUPPLY_STATUS_CHARGING;
212 else
213 status = POWER_SUPPLY_STATUS_DISCHARGING;
214 }
215
216 val->intval = status;
217 return 0;
218}
219
220/*
221 * Read a time register.
222 * Return < 0 if something fails.
223 */
224static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
225 union power_supply_propval *val)
226{
227 int tval = 0;
228 int ret;
229
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200230 ret = bq27x00_read(di, reg, &tval, false);
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200231 if (ret) {
232 dev_err(di->dev, "error reading register %02x\n", reg);
233 return ret;
234 }
235
236 if (tval == 65535)
237 return -ENODATA;
238
239 val->intval = tval * 60;
240 return 0;
241}
242
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700243#define to_bq27x00_device_info(x) container_of((x), \
244 struct bq27x00_device_info, bat);
245
246static int bq27x00_battery_get_property(struct power_supply *psy,
247 enum power_supply_property psp,
248 union power_supply_propval *val)
249{
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200250 int ret = 0;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700251 struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
Lars-Peter Clausen3413b4e2010-05-24 21:57:33 +0200252 int voltage = bq27x00_battery_voltage(di);
253
254 if (psp != POWER_SUPPLY_PROP_PRESENT && voltage <= 0)
255 return -ENODEV;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700256
257 switch (psp) {
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200258 case POWER_SUPPLY_PROP_STATUS:
259 ret = bq27x00_battery_status(di, val);
260 break;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700261 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
Lars-Peter Clausen3413b4e2010-05-24 21:57:33 +0200262 val->intval = voltage;
263 break;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700264 case POWER_SUPPLY_PROP_PRESENT:
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700265 if (psp == POWER_SUPPLY_PROP_PRESENT)
Lars-Peter Clausen3413b4e2010-05-24 21:57:33 +0200266 val->intval = voltage <= 0 ? 0 : 1;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700267 break;
268 case POWER_SUPPLY_PROP_CURRENT_NOW:
269 val->intval = bq27x00_battery_current(di);
270 break;
271 case POWER_SUPPLY_PROP_CAPACITY:
272 val->intval = bq27x00_battery_rsoc(di);
273 break;
274 case POWER_SUPPLY_PROP_TEMP:
275 val->intval = bq27x00_battery_temperature(di);
276 break;
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200277 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
278 ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val);
279 break;
280 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
281 ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val);
282 break;
283 case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
284 ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val);
285 break;
Lars-Peter Clausen5661f332010-05-24 20:36:52 +0200286 case POWER_SUPPLY_PROP_TECHNOLOGY:
287 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
288 break;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700289 default:
290 return -EINVAL;
291 }
292
Grazvydas Ignotas4e924a82010-02-27 17:06:09 +0200293 return ret;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700294}
295
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200296static int bq27x00_powersupply_init(struct bq27x00_device_info *di)
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700297{
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200298 int ret;
299
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700300 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
301 di->bat.properties = bq27x00_battery_props;
302 di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
303 di->bat.get_property = bq27x00_battery_get_property;
304 di->bat.external_power_changed = NULL;
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200305
306 ret = power_supply_register(di->dev, &di->bat);
307 if (ret) {
308 dev_err(di->dev, "failed to register battery: %d\n", ret);
309 return ret;
310 }
311
312 dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
313
314 return 0;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700315}
316
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200317
318/* i2c specific code */
319#ifdef CONFIG_BATTERY_BQ27X00_I2C
320
321/* If the system has several batteries we need a different name for each
322 * of them...
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700323 */
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200324static DEFINE_IDR(battery_id);
325static DEFINE_MUTEX(battery_mutex);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700326
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200327static int bq27x00_read_i2c(struct bq27x00_device_info *di, u8 reg,
328 int *rt_value, bool single)
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700329{
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200330 struct i2c_client *client = to_i2c_client(di->dev);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700331 struct i2c_msg msg[1];
332 unsigned char data[2];
333 int err;
334
335 if (!client->adapter)
336 return -ENODEV;
337
338 msg->addr = client->addr;
339 msg->flags = 0;
340 msg->len = 1;
341 msg->buf = data;
342
343 data[0] = reg;
344 err = i2c_transfer(client->adapter, msg, 1);
345
346 if (err >= 0) {
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200347 if (!single)
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700348 msg->len = 2;
349 else
350 msg->len = 1;
351
352 msg->flags = I2C_M_RD;
353 err = i2c_transfer(client->adapter, msg, 1);
354 if (err >= 0) {
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200355 if (!single)
Grazvydas Ignotas97f70c22010-02-12 23:56:46 +0200356 *rt_value = get_unaligned_le16(data);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700357 else
358 *rt_value = data[0];
359
360 return 0;
361 }
362 }
363 return err;
364}
365
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200366static int bq27x00_battery_probe(struct i2c_client *client,
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700367 const struct i2c_device_id *id)
368{
369 char *name;
370 struct bq27x00_device_info *di;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700371 int num;
372 int retval = 0;
373
374 /* Get new ID for the new battery device */
375 retval = idr_pre_get(&battery_id, GFP_KERNEL);
376 if (retval == 0)
377 return -ENOMEM;
378 mutex_lock(&battery_mutex);
379 retval = idr_get_new(&battery_id, client, &num);
380 mutex_unlock(&battery_mutex);
381 if (retval < 0)
382 return retval;
383
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200384 name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700385 if (!name) {
386 dev_err(&client->dev, "failed to allocate device name\n");
387 retval = -ENOMEM;
388 goto batt_failed_1;
389 }
390
391 di = kzalloc(sizeof(*di), GFP_KERNEL);
392 if (!di) {
393 dev_err(&client->dev, "failed to allocate device info data\n");
394 retval = -ENOMEM;
395 goto batt_failed_2;
396 }
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700397
Lars-Peter Clausena40402e2010-05-24 19:37:58 +0200398 di->id = num;
399 di->dev = &client->dev;
400 di->chip = id->driver_data;
401 di->bat.name = name;
402 di->bus.read = &bq27x00_read_i2c;
403
404 if (bq27x00_powersupply_init(di))
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700405 goto batt_failed_3;
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700406
407 i2c_set_clientdata(client, di);
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700408
409 return 0;
410
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700411batt_failed_3:
412 kfree(di);
413batt_failed_2:
414 kfree(name);
415batt_failed_1:
416 mutex_lock(&battery_mutex);
417 idr_remove(&battery_id, num);
418 mutex_unlock(&battery_mutex);
419
420 return retval;
421}
422
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200423static int bq27x00_battery_remove(struct i2c_client *client)
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700424{
425 struct bq27x00_device_info *di = i2c_get_clientdata(client);
426
427 power_supply_unregister(&di->bat);
428
429 kfree(di->bat.name);
430
431 mutex_lock(&battery_mutex);
432 idr_remove(&battery_id, di->id);
433 mutex_unlock(&battery_mutex);
434
435 kfree(di);
436
437 return 0;
438}
439
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200440static const struct i2c_device_id bq27x00_id[] = {
441 { "bq27200", BQ27000 }, /* bq27200 is same as bq27000, but with i2c */
442 { "bq27500", BQ27500 },
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700443 {},
444};
445
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200446static struct i2c_driver bq27x00_battery_driver = {
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700447 .driver = {
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200448 .name = "bq27x00-battery",
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700449 },
Grazvydas Ignotase20908d2010-02-12 23:57:23 +0200450 .probe = bq27x00_battery_probe,
451 .remove = bq27x00_battery_remove,
452 .id_table = bq27x00_id,
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700453};
454
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200455static inline int bq27x00_battery_i2c_init(void)
456{
457 int ret = i2c_add_driver(&bq27x00_battery_driver);
458 if (ret)
459 printk(KERN_ERR "Unable to register BQ27x00 i2c driver\n");
460
461 return ret;
462}
463
464static inline void bq27x00_battery_i2c_exit(void)
465{
466 i2c_del_driver(&bq27x00_battery_driver);
467}
468
469#else
470
471static inline int bq27x00_battery_i2c_init(void) { return 0; }
472static inline void bq27x00_battery_i2c_exit(void) {};
473
474#endif
475
476/* platform specific code */
477#ifdef CONFIG_BATTERY_BQ27X00_PLATFORM
478
479static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg,
480 int *rt_value, bool single)
481{
482 struct device *dev = di->dev;
483 struct bq27000_platform_data *pdata = dev->platform_data;
484 unsigned int timeout = 3;
485 int upper, lower;
486 int temp;
487
488 if (!single) {
489 /* Make sure the value has not changed in between reading the
490 * lower and the upper part */
491 upper = pdata->read(dev, reg + 1);
492 do {
493 temp = upper;
494 if (upper < 0)
495 return upper;
496
497 lower = pdata->read(dev, reg);
498 if (lower < 0)
499 return lower;
500
501 upper = pdata->read(dev, reg + 1);
502 } while (temp != upper && --timeout);
503
504 if (timeout == 0)
505 return -EIO;
506
507 *rt_value = (upper << 8) | lower;
508 } else {
509 lower = pdata->read(dev, reg);
510 if (lower < 0)
511 return lower;
512 *rt_value = lower;
513 }
514 return 0;
515}
516
517static int __devinit bq27000_battery_probe(struct platform_device *pdev)
518{
519 struct bq27x00_device_info *di;
520 struct bq27000_platform_data *pdata = pdev->dev.platform_data;
521 int ret;
522
523 if (!pdata) {
524 dev_err(&pdev->dev, "no platform_data supplied\n");
525 return -EINVAL;
526 }
527
528 if (!pdata->read) {
529 dev_err(&pdev->dev, "no hdq read callback supplied\n");
530 return -EINVAL;
531 }
532
533 di = kzalloc(sizeof(*di), GFP_KERNEL);
534 if (!di) {
535 dev_err(&pdev->dev, "failed to allocate device info data\n");
536 return -ENOMEM;
537 }
538
539 platform_set_drvdata(pdev, di);
540
541 di->dev = &pdev->dev;
542 di->chip = BQ27000;
543
544 di->bat.name = pdata->name ?: dev_name(&pdev->dev);
545 di->bus.read = &bq27000_read_platform;
546
547 ret = bq27x00_powersupply_init(di);
548 if (ret)
549 goto err_free;
550
551 return 0;
552
553err_free:
554 platform_set_drvdata(pdev, NULL);
555 kfree(di);
556
557 return ret;
558}
559
560static int __devexit bq27000_battery_remove(struct platform_device *pdev)
561{
562 struct bq27x00_device_info *di = platform_get_drvdata(pdev);
563
564 power_supply_unregister(&di->bat);
565 platform_set_drvdata(pdev, NULL);
566 kfree(di);
567
568 return 0;
569}
570
571static struct platform_driver bq27000_battery_driver = {
572 .probe = bq27000_battery_probe,
573 .remove = __devexit_p(bq27000_battery_remove),
574 .driver = {
575 .name = "bq27000-battery",
576 .owner = THIS_MODULE,
577 },
578};
579
580static inline int bq27x00_battery_platform_init(void)
581{
582 int ret = platform_driver_register(&bq27000_battery_driver);
583 if (ret)
584 printk(KERN_ERR "Unable to register BQ27000 platform driver\n");
585
586 return ret;
587}
588
589static inline void bq27x00_battery_platform_exit(void)
590{
591 platform_driver_unregister(&bq27000_battery_driver);
592}
593
594#else
595
596static inline int bq27x00_battery_platform_init(void) { return 0; }
597static inline void bq27x00_battery_platform_exit(void) {};
598
599#endif
600
601/*
602 * Module stuff
603 */
604
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700605static int __init bq27x00_battery_init(void)
606{
607 int ret;
608
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200609 ret = bq27x00_battery_i2c_init();
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700610 if (ret)
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200611 return ret;
612
613 ret = bq27x00_battery_platform_init();
614 if (ret)
615 bq27x00_battery_i2c_exit();
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700616
617 return ret;
618}
619module_init(bq27x00_battery_init);
620
621static void __exit bq27x00_battery_exit(void)
622{
Lars-Peter Clausen7fb7ba52010-05-24 19:55:27 +0200623 bq27x00_battery_platform_exit();
624 bq27x00_battery_i2c_exit();
Rodolfo Giomettib996ad02008-08-20 16:52:58 -0700625}
626module_exit(bq27x00_battery_exit);
627
628MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
629MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
630MODULE_LICENSE("GPL");