power_supply: bq27x00: fix temperature conversion
[linux-2.6-block.git] / drivers / power / bq27x00_battery.c
CommitLineData
b996ad0e
RG
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>
b996ad0e 26#include <linux/i2c.h>
8aef7e8f 27#include <asm/unaligned.h>
b996ad0e
RG
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
b996ad0e
RG
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;
b996ad0e
RG
52 struct bq27x00_access_methods *bus;
53 struct power_supply bat;
54
55 struct i2c_client *client;
56};
57
58static enum power_supply_property bq27x00_battery_props[] = {
59 POWER_SUPPLY_PROP_PRESENT,
60 POWER_SUPPLY_PROP_VOLTAGE_NOW,
61 POWER_SUPPLY_PROP_CURRENT_NOW,
62 POWER_SUPPLY_PROP_CAPACITY,
63 POWER_SUPPLY_PROP_TEMP,
64};
65
66/*
67 * Common code for BQ27x00 devices
68 */
69
70static int bq27x00_read(u8 reg, int *rt_value, int b_single,
71 struct bq27x00_device_info *di)
72{
97f70c23 73 return di->bus->read(reg, rt_value, b_single, di);
b996ad0e
RG
74}
75
76/*
b4de3608 77 * Return the battery temperature in tenths of degree Celsius
b996ad0e
RG
78 * Or < 0 if something fails.
79 */
80static int bq27x00_battery_temperature(struct bq27x00_device_info *di)
81{
82 int ret;
83 int temp = 0;
84
85 ret = bq27x00_read(BQ27x00_REG_TEMP, &temp, 0, di);
86 if (ret) {
87 dev_err(di->dev, "error reading temperature\n");
88 return ret;
89 }
90
b4de3608 91 return ((temp >> 2) - 273) * 10;
b996ad0e
RG
92}
93
94/*
95 * Return the battery Voltage in milivolts
96 * Or < 0 if something fails.
97 */
98static int bq27x00_battery_voltage(struct bq27x00_device_info *di)
99{
100 int ret;
101 int volt = 0;
102
103 ret = bq27x00_read(BQ27x00_REG_VOLT, &volt, 0, di);
104 if (ret) {
105 dev_err(di->dev, "error reading voltage\n");
106 return ret;
107 }
108
109 return volt;
110}
111
112/*
113 * Return the battery average current
114 * Note that current can be negative signed as well
115 * Or 0 if something fails.
116 */
117static int bq27x00_battery_current(struct bq27x00_device_info *di)
118{
119 int ret;
120 int curr = 0;
121 int flags = 0;
122
123 ret = bq27x00_read(BQ27x00_REG_AI, &curr, 0, di);
124 if (ret) {
125 dev_err(di->dev, "error reading current\n");
126 return 0;
127 }
128 ret = bq27x00_read(BQ27x00_REG_FLAGS, &flags, 0, di);
129 if (ret < 0) {
130 dev_err(di->dev, "error reading flags\n");
131 return 0;
132 }
133 if ((flags & (1 << 7)) != 0) {
134 dev_dbg(di->dev, "negative current!\n");
135 return -curr;
136 }
137 return curr;
138}
139
140/*
141 * Return the battery Relative State-of-Charge
142 * Or < 0 if something fails.
143 */
144static int bq27x00_battery_rsoc(struct bq27x00_device_info *di)
145{
146 int ret;
147 int rsoc = 0;
148
149 ret = bq27x00_read(BQ27x00_REG_RSOC, &rsoc, 1, di);
150 if (ret) {
151 dev_err(di->dev, "error reading relative State-of-Charge\n");
152 return ret;
153 }
154
97f70c23 155 return rsoc;
b996ad0e
RG
156}
157
158#define to_bq27x00_device_info(x) container_of((x), \
159 struct bq27x00_device_info, bat);
160
161static int bq27x00_battery_get_property(struct power_supply *psy,
162 enum power_supply_property psp,
163 union power_supply_propval *val)
164{
165 struct bq27x00_device_info *di = to_bq27x00_device_info(psy);
166
167 switch (psp) {
168 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
169 case POWER_SUPPLY_PROP_PRESENT:
170 val->intval = bq27x00_battery_voltage(di);
171 if (psp == POWER_SUPPLY_PROP_PRESENT)
172 val->intval = val->intval <= 0 ? 0 : 1;
173 break;
174 case POWER_SUPPLY_PROP_CURRENT_NOW:
175 val->intval = bq27x00_battery_current(di);
176 break;
177 case POWER_SUPPLY_PROP_CAPACITY:
178 val->intval = bq27x00_battery_rsoc(di);
179 break;
180 case POWER_SUPPLY_PROP_TEMP:
181 val->intval = bq27x00_battery_temperature(di);
182 break;
183 default:
184 return -EINVAL;
185 }
186
187 return 0;
188}
189
190static void bq27x00_powersupply_init(struct bq27x00_device_info *di)
191{
192 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
193 di->bat.properties = bq27x00_battery_props;
194 di->bat.num_properties = ARRAY_SIZE(bq27x00_battery_props);
195 di->bat.get_property = bq27x00_battery_get_property;
196 di->bat.external_power_changed = NULL;
197}
198
199/*
200 * BQ27200 specific code
201 */
202
203static int bq27200_read(u8 reg, int *rt_value, int b_single,
204 struct bq27x00_device_info *di)
205{
206 struct i2c_client *client = di->client;
207 struct i2c_msg msg[1];
208 unsigned char data[2];
209 int err;
210
211 if (!client->adapter)
212 return -ENODEV;
213
214 msg->addr = client->addr;
215 msg->flags = 0;
216 msg->len = 1;
217 msg->buf = data;
218
219 data[0] = reg;
220 err = i2c_transfer(client->adapter, msg, 1);
221
222 if (err >= 0) {
223 if (!b_single)
224 msg->len = 2;
225 else
226 msg->len = 1;
227
228 msg->flags = I2C_M_RD;
229 err = i2c_transfer(client->adapter, msg, 1);
230 if (err >= 0) {
231 if (!b_single)
97f70c23 232 *rt_value = get_unaligned_le16(data);
b996ad0e
RG
233 else
234 *rt_value = data[0];
235
236 return 0;
237 }
238 }
239 return err;
240}
241
242static int bq27200_battery_probe(struct i2c_client *client,
243 const struct i2c_device_id *id)
244{
245 char *name;
246 struct bq27x00_device_info *di;
247 struct bq27x00_access_methods *bus;
248 int num;
249 int retval = 0;
250
251 /* Get new ID for the new battery device */
252 retval = idr_pre_get(&battery_id, GFP_KERNEL);
253 if (retval == 0)
254 return -ENOMEM;
255 mutex_lock(&battery_mutex);
256 retval = idr_get_new(&battery_id, client, &num);
257 mutex_unlock(&battery_mutex);
258 if (retval < 0)
259 return retval;
260
261 name = kasprintf(GFP_KERNEL, "bq27200-%d", num);
262 if (!name) {
263 dev_err(&client->dev, "failed to allocate device name\n");
264 retval = -ENOMEM;
265 goto batt_failed_1;
266 }
267
268 di = kzalloc(sizeof(*di), GFP_KERNEL);
269 if (!di) {
270 dev_err(&client->dev, "failed to allocate device info data\n");
271 retval = -ENOMEM;
272 goto batt_failed_2;
273 }
274 di->id = num;
275
276 bus = kzalloc(sizeof(*bus), GFP_KERNEL);
277 if (!bus) {
278 dev_err(&client->dev, "failed to allocate access method "
279 "data\n");
280 retval = -ENOMEM;
281 goto batt_failed_3;
282 }
283
284 i2c_set_clientdata(client, di);
285 di->dev = &client->dev;
286 di->bat.name = name;
287 bus->read = &bq27200_read;
288 di->bus = bus;
289 di->client = client;
290
291 bq27x00_powersupply_init(di);
292
293 retval = power_supply_register(&client->dev, &di->bat);
294 if (retval) {
295 dev_err(&client->dev, "failed to register battery\n");
296 goto batt_failed_4;
297 }
298
299 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
300
301 return 0;
302
303batt_failed_4:
304 kfree(bus);
305batt_failed_3:
306 kfree(di);
307batt_failed_2:
308 kfree(name);
309batt_failed_1:
310 mutex_lock(&battery_mutex);
311 idr_remove(&battery_id, num);
312 mutex_unlock(&battery_mutex);
313
314 return retval;
315}
316
317static int bq27200_battery_remove(struct i2c_client *client)
318{
319 struct bq27x00_device_info *di = i2c_get_clientdata(client);
320
321 power_supply_unregister(&di->bat);
322
323 kfree(di->bat.name);
324
325 mutex_lock(&battery_mutex);
326 idr_remove(&battery_id, di->id);
327 mutex_unlock(&battery_mutex);
328
329 kfree(di);
330
331 return 0;
332}
333
334/*
335 * Module stuff
336 */
337
338static const struct i2c_device_id bq27200_id[] = {
339 { "bq27200", 0 },
340 {},
341};
342
343static struct i2c_driver bq27200_battery_driver = {
344 .driver = {
345 .name = "bq27200-battery",
346 },
347 .probe = bq27200_battery_probe,
348 .remove = bq27200_battery_remove,
349 .id_table = bq27200_id,
350};
351
352static int __init bq27x00_battery_init(void)
353{
354 int ret;
355
356 ret = i2c_add_driver(&bq27200_battery_driver);
357 if (ret)
358 printk(KERN_ERR "Unable to register BQ27200 driver\n");
359
360 return ret;
361}
362module_init(bq27x00_battery_init);
363
364static void __exit bq27x00_battery_exit(void)
365{
366 i2c_del_driver(&bq27200_battery_driver);
367}
368module_exit(bq27x00_battery_exit);
369
370MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
371MODULE_DESCRIPTION("BQ27x00 battery monitor driver");
372MODULE_LICENSE("GPL");