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