ba1bd1a545bea5fccb466f51880b11950aabc42b
[pandora-kernel.git] / drivers / power / ds2782_battery.c
1 /*
2  * I2C client/driver for the Maxim/Dallas DS2782 Stand-Alone Fuel Gauge IC
3  *
4  * Copyright (C) 2009 Bluewater Systems Ltd
5  *
6  * Author: Ryan Mallon <ryan@bluewatersys.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/errno.h>
18 #include <linux/swab.h>
19 #include <linux/i2c.h>
20 #include <linux/idr.h>
21 #include <linux/power_supply.h>
22 #include <linux/slab.h>
23
24 #define DS2782_REG_RARC         0x06    /* Remaining active relative capacity */
25
26 #define DS2782_REG_VOLT_MSB     0x0c
27 #define DS2782_REG_TEMP_MSB     0x0a
28 #define DS2782_REG_CURRENT_MSB  0x0e
29
30 /* EEPROM Block */
31 #define DS2782_REG_RSNSP        0x69    /* Sense resistor value */
32
33 /* Current unit measurement in uA for a 1 milli-ohm sense resistor */
34 #define DS2782_CURRENT_UNITS    1563
35
36 #define to_ds2782_info(x) container_of(x, struct ds2782_info, battery)
37
38 struct ds2782_info {
39         struct i2c_client       *client;
40         struct power_supply     battery;
41         int                     id;
42 };
43
44 static DEFINE_IDR(battery_id);
45 static DEFINE_MUTEX(battery_lock);
46
47 static inline int ds2782_read_reg(struct ds2782_info *info, int reg, u8 *val)
48 {
49         int ret;
50
51         ret = i2c_smbus_read_byte_data(info->client, reg);
52         if (ret < 0) {
53                 dev_err(&info->client->dev, "register read failed\n");
54                 return ret;
55         }
56
57         *val = ret;
58         return 0;
59 }
60
61 static inline int ds2782_read_reg16(struct ds2782_info *info, int reg_msb,
62                                     s16 *val)
63 {
64         int ret;
65
66         ret = swab16(i2c_smbus_read_word_data(info->client, reg_msb));
67         if (ret < 0) {
68                 dev_err(&info->client->dev, "register read failed\n");
69                 return ret;
70         }
71
72         *val = ret;
73         return 0;
74 }
75
76 static int ds2782_get_temp(struct ds2782_info *info, int *temp)
77 {
78         s16 raw;
79         int err;
80
81         /*
82          * Temperature is measured in units of 0.125 degrees celcius, the
83          * power_supply class measures temperature in tenths of degrees
84          * celsius. The temperature value is stored as a 10 bit number, plus
85          * sign in the upper bits of a 16 bit register.
86          */
87         err = ds2782_read_reg16(info, DS2782_REG_TEMP_MSB, &raw);
88         if (err)
89                 return err;
90         *temp = ((raw / 32) * 125) / 100;
91         return 0;
92 }
93
94 static int ds2782_get_current(struct ds2782_info *info, int *current_uA)
95 {
96         int sense_res;
97         int err;
98         u8 sense_res_raw;
99         s16 raw;
100
101         /*
102          * The units of measurement for current are dependent on the value of
103          * the sense resistor.
104          */
105         err = ds2782_read_reg(info, DS2782_REG_RSNSP, &sense_res_raw);
106         if (err)
107                 return err;
108         if (sense_res_raw == 0) {
109                 dev_err(&info->client->dev, "sense resistor value is 0\n");
110                 return -ENXIO;
111         }
112         sense_res = 1000 / sense_res_raw;
113
114         dev_dbg(&info->client->dev, "sense resistor = %d milli-ohms\n",
115                 sense_res);
116         err = ds2782_read_reg16(info, DS2782_REG_CURRENT_MSB, &raw);
117         if (err)
118                 return err;
119         *current_uA = raw * (DS2782_CURRENT_UNITS / sense_res);
120         return 0;
121 }
122
123 static int ds2782_get_voltage(struct ds2782_info *info, int *voltage_uA)
124 {
125         s16 raw;
126         int err;
127
128         /*
129          * Voltage is measured in units of 4.88mV. The voltage is stored as
130          * a 10-bit number plus sign, in the upper bits of a 16-bit register
131          */
132         err = ds2782_read_reg16(info, DS2782_REG_VOLT_MSB, &raw);
133         if (err)
134                 return err;
135         *voltage_uA = (raw / 32) * 4800;
136         return 0;
137 }
138
139 static int ds2782_get_capacity(struct ds2782_info *info, int *capacity)
140 {
141         int err;
142         u8 raw;
143
144         err = ds2782_read_reg(info, DS2782_REG_RARC, &raw);
145         if (err)
146                 return err;
147         *capacity = raw;
148         return raw;
149 }
150
151 static int ds2782_get_status(struct ds2782_info *info, int *status)
152 {
153         int err;
154         int current_uA;
155         int capacity;
156
157         err = ds2782_get_current(info, &current_uA);
158         if (err)
159                 return err;
160
161         err = ds2782_get_capacity(info, &capacity);
162         if (err)
163                 return err;
164
165         if (capacity == 100)
166                 *status = POWER_SUPPLY_STATUS_FULL;
167         else if (current_uA == 0)
168                 *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
169         else if (current_uA < 0)
170                 *status = POWER_SUPPLY_STATUS_DISCHARGING;
171         else
172                 *status = POWER_SUPPLY_STATUS_CHARGING;
173
174         return 0;
175 }
176
177 static int ds2782_battery_get_property(struct power_supply *psy,
178                                        enum power_supply_property prop,
179                                        union power_supply_propval *val)
180 {
181         struct ds2782_info *info = to_ds2782_info(psy);
182         int ret;
183
184         switch (prop) {
185         case POWER_SUPPLY_PROP_STATUS:
186                 ret = ds2782_get_status(info, &val->intval);
187                 break;
188
189         case POWER_SUPPLY_PROP_CAPACITY:
190                 ret = ds2782_get_capacity(info, &val->intval);
191                 break;
192
193         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
194                 ret = ds2782_get_voltage(info, &val->intval);
195                 break;
196
197         case POWER_SUPPLY_PROP_CURRENT_NOW:
198                 ret = ds2782_get_current(info, &val->intval);
199                 break;
200
201         case POWER_SUPPLY_PROP_TEMP:
202                 ret = ds2782_get_temp(info, &val->intval);
203                 break;
204
205         default:
206                 ret = -EINVAL;
207         }
208
209         return ret;
210 }
211
212 static enum power_supply_property ds2782_battery_props[] = {
213         POWER_SUPPLY_PROP_STATUS,
214         POWER_SUPPLY_PROP_CAPACITY,
215         POWER_SUPPLY_PROP_VOLTAGE_NOW,
216         POWER_SUPPLY_PROP_CURRENT_NOW,
217         POWER_SUPPLY_PROP_TEMP,
218 };
219
220 static void ds2782_power_supply_init(struct power_supply *battery)
221 {
222         battery->type                   = POWER_SUPPLY_TYPE_BATTERY;
223         battery->properties             = ds2782_battery_props;
224         battery->num_properties         = ARRAY_SIZE(ds2782_battery_props);
225         battery->get_property           = ds2782_battery_get_property;
226         battery->external_power_changed = NULL;
227 }
228
229 static int ds2782_battery_remove(struct i2c_client *client)
230 {
231         struct ds2782_info *info = i2c_get_clientdata(client);
232
233         power_supply_unregister(&info->battery);
234         kfree(info->battery.name);
235
236         mutex_lock(&battery_lock);
237         idr_remove(&battery_id, info->id);
238         mutex_unlock(&battery_lock);
239
240         kfree(info);
241         return 0;
242 }
243
244 static int ds2782_battery_probe(struct i2c_client *client,
245                                 const struct i2c_device_id *id)
246 {
247         struct ds2782_info *info;
248         int ret;
249         int num;
250
251         /* Get an ID for this battery */
252         ret = idr_pre_get(&battery_id, GFP_KERNEL);
253         if (ret == 0) {
254                 ret = -ENOMEM;
255                 goto fail_id;
256         }
257
258         mutex_lock(&battery_lock);
259         ret = idr_get_new(&battery_id, client, &num);
260         mutex_unlock(&battery_lock);
261         if (ret < 0)
262                 goto fail_id;
263
264         info = kzalloc(sizeof(*info), GFP_KERNEL);
265         if (!info) {
266                 ret = -ENOMEM;
267                 goto fail_info;
268         }
269
270         info->battery.name = kasprintf(GFP_KERNEL, "ds2782-%d", num);
271         if (!info->battery.name) {
272                 ret = -ENOMEM;
273                 goto fail_name;
274         }
275
276         i2c_set_clientdata(client, info);
277         info->client = client;
278         ds2782_power_supply_init(&info->battery);
279
280         ret = power_supply_register(&client->dev, &info->battery);
281         if (ret) {
282                 dev_err(&client->dev, "failed to register battery\n");
283                 goto fail_register;
284         }
285
286         return 0;
287
288 fail_register:
289         kfree(info->battery.name);
290 fail_name:
291         kfree(info);
292 fail_info:
293         mutex_lock(&battery_lock);
294         idr_remove(&battery_id, num);
295         mutex_unlock(&battery_lock);
296 fail_id:
297         return ret;
298 }
299
300 static const struct i2c_device_id ds2782_id[] = {
301         {"ds2782", 0},
302         {},
303 };
304
305 static struct i2c_driver ds2782_battery_driver = {
306         .driver         = {
307                 .name   = "ds2782-battery",
308         },
309         .probe          = ds2782_battery_probe,
310         .remove         = ds2782_battery_remove,
311         .id_table       = ds2782_id,
312 };
313
314 static int __init ds2782_init(void)
315 {
316         return i2c_add_driver(&ds2782_battery_driver);
317 }
318 module_init(ds2782_init);
319
320 static void __exit ds2782_exit(void)
321 {
322         i2c_del_driver(&ds2782_battery_driver);
323 }
324 module_exit(ds2782_exit);
325
326 MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
327 MODULE_DESCRIPTION("Maxim/Dallas DS2782 Stand-Alone Fuel Gauage IC driver");
328 MODULE_LICENSE("GPL");