• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/power/
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 <linux/slab.h>
28#include <asm/unaligned.h>
29
30#define DRIVER_VERSION			"1.1.0"
31
32#define BQ27x00_REG_TEMP		0x06
33#define BQ27x00_REG_VOLT		0x08
34#define BQ27x00_REG_AI			0x14
35#define BQ27x00_REG_FLAGS		0x0A
36#define BQ27x00_REG_TTE			0x16
37#define BQ27x00_REG_TTF			0x18
38#define BQ27x00_REG_TTECP		0x26
39
40#define BQ27000_REG_RSOC		0x0B /* Relative State-of-Charge */
41#define BQ27000_FLAG_CHGS		BIT(7)
42
43#define BQ27500_REG_SOC			0x2c
44#define BQ27500_FLAG_DSC		BIT(0)
45#define BQ27500_FLAG_FC			BIT(9)
46
47/* If the system has several batteries we need a different name for each
48 * of them...
49 */
50static DEFINE_IDR(battery_id);
51static DEFINE_MUTEX(battery_mutex);
52
53struct bq27x00_device_info;
54struct bq27x00_access_methods {
55	int (*read)(u8 reg, int *rt_value, int b_single,
56		struct bq27x00_device_info *di);
57};
58
59enum bq27x00_chip { BQ27000, BQ27500 };
60
61struct bq27x00_device_info {
62	struct device 		*dev;
63	int			id;
64	struct bq27x00_access_methods	*bus;
65	struct power_supply	bat;
66	enum bq27x00_chip	chip;
67
68	struct i2c_client	*client;
69};
70
71static enum power_supply_property bq27x00_battery_props[] = {
72	POWER_SUPPLY_PROP_STATUS,
73	POWER_SUPPLY_PROP_PRESENT,
74	POWER_SUPPLY_PROP_VOLTAGE_NOW,
75	POWER_SUPPLY_PROP_CURRENT_NOW,
76	POWER_SUPPLY_PROP_CAPACITY,
77	POWER_SUPPLY_PROP_TEMP,
78	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
79	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
80	POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
81};
82
83/*
84 * Common code for BQ27x00 devices
85 */
86
87static int bq27x00_read(u8 reg, int *rt_value, int b_single,
88			struct bq27x00_device_info *di)
89{
90	return di->bus->read(reg, rt_value, b_single, di);
91}
92
93/*
94 * Return the battery temperature in tenths of degree Celsius
95 * 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
102	ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
103	if (ret) {
104		dev_err(di->dev, "error reading temperature\n");
105		return ret;
106	}
107
108	if (di->chip == BQ27500)
109		return temp - 2731;
110	else
111		return ((temp >> 2) - 273) * 10;
112}
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
123	ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
124	if (ret) {
125		dev_err(di->dev, "error reading voltage\n");
126		return ret;
127	}
128
129	return volt * 1000;
130}
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
143	ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
144	if (ret) {
145		dev_err(di->dev, "error reading current\n");
146		return 0;
147	}
148
149	if (di->chip == BQ27500) {
150		/* bq27500 returns signed value */
151		curr = (int)(s16)curr;
152	} else {
153		ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
154		if (ret < 0) {
155			dev_err(di->dev, "error reading flags\n");
156			return 0;
157		}
158		if (flags & BQ27000_FLAG_CHGS) {
159			dev_dbg(di->dev, "negative current!\n");
160			curr = -curr;
161		}
162	}
163
164	return curr * 1000;
165}
166
167/*
168 * Return the battery Relative State-of-Charge
169 * Or < 0 if something fails.
170 */
171static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
172{
173	int ret;
174	int rsoc = 0;
175
176	if (di->chip == BQ27500)
177		ret = bq27x00_read(BQ27500_REG_SOC, &rsoc, 0, di);
178	else
179		ret = bq27x00_read(BQ27000_REG_RSOC, &rsoc, 1, di);
180	if (ret) {
181		dev_err(di->dev, "error reading relative State-of-Charge\n");
182		return ret;
183	}
184
185	return rsoc;
186}
187
188static int bq27x00_battery_status(struct bq27x00_device_info *di,
189				  union power_supply_propval *val)
190{
191	int flags = 0;
192	int status;
193	int ret;
194
195	ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
196	if (ret < 0) {
197		dev_err(di->dev, "error reading flags\n");
198		return ret;
199	}
200
201	if (di->chip == BQ27500) {
202		if (flags & BQ27500_FLAG_FC)
203			status = POWER_SUPPLY_STATUS_FULL;
204		else if (flags & BQ27500_FLAG_DSC)
205			status = POWER_SUPPLY_STATUS_DISCHARGING;
206		else
207			status = POWER_SUPPLY_STATUS_CHARGING;
208	} else {
209		if (flags & BQ27000_FLAG_CHGS)
210			status = POWER_SUPPLY_STATUS_CHARGING;
211		else
212			status = POWER_SUPPLY_STATUS_DISCHARGING;
213	}
214
215	val->intval = status;
216	return 0;
217}
218
219/*
220 * Read a time register.
221 * Return < 0 if something fails.
222 */
223static int bq27x00_battery_time(struct bq27x00_device_info *di, int reg,
224				union power_supply_propval *val)
225{
226	int tval = 0;
227	int ret;
228
229	ret = bq27x00_read(reg, &tval, 0, di);
230	if (ret) {
231		dev_err(di->dev, "error reading register %02x\n", reg);
232		return ret;
233	}
234
235	if (tval == 65535)
236		return -ENODATA;
237
238	val->intval = tval * 60;
239	return 0;
240}
241
242#define to_bq27x00_device_info(x) container_of((x), \
243				struct bq27x00_device_info, bat);
244
245static int bq27x00_battery_get_property(struct power_supply *psy,
246					enum power_supply_property psp,
247					union power_supply_propval *val)
248{
249	int ret = 0;
250	struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
251
252	switch (psp) {
253	case POWER_SUPPLY_PROP_STATUS:
254		ret = bq27x00_battery_status(di, val);
255		break;
256	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
257	case POWER_SUPPLY_PROP_PRESENT:
258		val->intval = bq27x00_battery_voltage(di);
259		if (psp == POWER_SUPPLY_PROP_PRESENT)
260			val->intval = val->intval <= 0 ? 0 : 1;
261		break;
262	case POWER_SUPPLY_PROP_CURRENT_NOW:
263		val->intval = bq27x00_battery_current(di);
264		break;
265	case POWER_SUPPLY_PROP_CAPACITY:
266		val->intval = bq27x00_battery_rsoc(di);
267		break;
268	case POWER_SUPPLY_PROP_TEMP:
269		val->intval = bq27x00_battery_temperature(di);
270		break;
271	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW:
272		ret = bq27x00_battery_time(di, BQ27x00_REG_TTE, val);
273		break;
274	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
275		ret = bq27x00_battery_time(di, BQ27x00_REG_TTECP, val);
276		break;
277	case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
278		ret = bq27x00_battery_time(di, BQ27x00_REG_TTF, val);
279		break;
280	default:
281		return -EINVAL;
282	}
283
284	return ret;
285}
286
287static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
288{
289	di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
290	di->bat.properties = bq27x00_battery_props;
291	di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
292	di->bat.get_property = bq27x00_battery_get_property;
293	di->bat.external_power_changed = NULL;
294}
295
296/*
297 * i2c specific code
298 */
299
300static int bq27x00_read_i2c(u8 reg, int *rt_value, int b_single,
301			struct bq27x00_device_info *di)
302{
303	struct i2c_client *client = di->client;
304	struct i2c_msg msg[1];
305	unsigned char data[2];
306	int err;
307
308	if (!client->adapter)
309		return -ENODEV;
310
311	msg->addr = client->addr;
312	msg->flags = 0;
313	msg->len = 1;
314	msg->buf = data;
315
316	data[0] = reg;
317	err = i2c_transfer(client->adapter, msg, 1);
318
319	if (err >= 0) {
320		if (!b_single)
321			msg->len = 2;
322		else
323			msg->len = 1;
324
325		msg->flags = I2C_M_RD;
326		err = i2c_transfer(client->adapter, msg, 1);
327		if (err >= 0) {
328			if (!b_single)
329				*rt_value = get_unaligned_le16(data);
330			else
331				*rt_value = data[0];
332
333			return 0;
334		}
335	}
336	return err;
337}
338
339static int bq27x00_battery_probe(struct i2c_client *client,
340				 const struct i2c_device_id *id)
341{
342	char *name;
343	struct bq27x00_device_info *di;
344	struct bq27x00_access_methods *bus;
345	int num;
346	int retval = 0;
347
348	/* Get new ID for the new battery device */
349	retval = idr_pre_get(&battery_id, GFP_KERNEL);
350	if (retval == 0)
351		return -ENOMEM;
352	mutex_lock(&battery_mutex);
353	retval = idr_get_new(&battery_id, client, &num);
354	mutex_unlock(&battery_mutex);
355	if (retval < 0)
356		return retval;
357
358	name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
359	if (!name) {
360		dev_err(&client->dev, "failed to allocate device name\n");
361		retval = -ENOMEM;
362		goto batt_failed_1;
363	}
364
365	di = kzalloc(sizeof(*di), GFP_KERNEL);
366	if (!di) {
367		dev_err(&client->dev, "failed to allocate device info data\n");
368		retval = -ENOMEM;
369		goto batt_failed_2;
370	}
371	di->id = num;
372	di->chip = id->driver_data;
373
374	bus = kzalloc(sizeof(*bus), GFP_KERNEL);
375	if (!bus) {
376		dev_err(&client->dev, "failed to allocate access method "
377					"data\n");
378		retval = -ENOMEM;
379		goto batt_failed_3;
380	}
381
382	i2c_set_clientdata(client, di);
383	di->dev = &client->dev;
384	di->bat.name = name;
385	bus->read = &bq27x00_read_i2c;
386	di->bus = bus;
387	di->client = client;
388
389	bq27x00_powersupply_init(di);
390
391	retval = power_supply_register(&client->dev, &di->bat);
392	if (retval) {
393		dev_err(&client->dev, "failed to register battery\n");
394		goto batt_failed_4;
395	}
396
397	dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
398
399	return 0;
400
401batt_failed_4:
402	kfree(bus);
403batt_failed_3:
404	kfree(di);
405batt_failed_2:
406	kfree(name);
407batt_failed_1:
408	mutex_lock(&battery_mutex);
409	idr_remove(&battery_id, num);
410	mutex_unlock(&battery_mutex);
411
412	return retval;
413}
414
415static int bq27x00_battery_remove(struct i2c_client *client)
416{
417	struct bq27x00_device_info *di = i2c_get_clientdata(client);
418
419	power_supply_unregister(&di->bat);
420
421	kfree(di->bat.name);
422
423	mutex_lock(&battery_mutex);
424	idr_remove(&battery_id, di->id);
425	mutex_unlock(&battery_mutex);
426
427	kfree(di);
428
429	return 0;
430}
431
432/*
433 * Module stuff
434 */
435
436static const struct i2c_device_id bq27x00_id[] = {
437	{ "bq27200", BQ27000 },	/* bq27200 is same as bq27000, but with i2c */
438	{ "bq27500", BQ27500 },
439	{},
440};
441
442static struct i2c_driver bq27x00_battery_driver = {
443	.driver = {
444		.name = "bq27x00-battery",
445	},
446	.probe = bq27x00_battery_probe,
447	.remove = bq27x00_battery_remove,
448	.id_table = bq27x00_id,
449};
450
451static int __init bq27x00_battery_init(void)
452{
453	int ret;
454
455	ret = i2c_add_driver(&bq27x00_battery_driver);
456	if (ret)
457		printk(KERN_ERR "Unable to register BQ27x00 driver\n");
458
459	return ret;
460}
461module_init(bq27x00_battery_init);
462
463static void __exit bq27x00_battery_exit(void)
464{
465	i2c_del_driver(&bq27x00_battery_driver);
466}
467module_exit(bq27x00_battery_exit);
468
469MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
470MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
471MODULE_LICENSE("GPL");
472