jz4740-battery: Protect against concurrent battery readings
[linux-2.6.git] / drivers / power / jz4740-battery.c
1 /*
2  * Battery measurement code for Ingenic JZ SOC.
3  *
4  * Copyright (C) 2009 Jiejing Zhang <kzjeef@gmail.com>
5  * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
6  *
7  * based on tosa_battery.c
8  *
9  * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
10 *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  */
16
17 #include <linux/interrupt.h>
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22
23 #include <linux/delay.h>
24 #include <linux/gpio.h>
25 #include <linux/mfd/core.h>
26 #include <linux/power_supply.h>
27
28 #include <linux/power/jz4740-battery.h>
29 #include <linux/jz4740-adc.h>
30
31 struct jz_battery {
32         struct jz_battery_platform_data *pdata;
33         struct platform_device *pdev;
34
35         struct resource *mem;
36         void __iomem *base;
37
38         int irq;
39         int charge_irq;
40
41         struct mfd_cell *cell;
42
43         int status;
44         long voltage;
45
46         struct completion read_completion;
47
48         struct power_supply battery;
49         struct delayed_work work;
50
51         struct mutex lock;
52 };
53
54 static inline struct jz_battery *psy_to_jz_battery(struct power_supply *psy)
55 {
56         return container_of(psy, struct jz_battery, battery);
57 }
58
59 static irqreturn_t jz_battery_irq_handler(int irq, void *devid)
60 {
61         struct jz_battery *battery = devid;
62
63         complete(&battery->read_completion);
64         return IRQ_HANDLED;
65 }
66
67 static long jz_battery_read_voltage(struct jz_battery *battery)
68 {
69         unsigned long t;
70         unsigned long val;
71         long voltage;
72
73         mutex_lock(&battery->lock);
74
75         INIT_COMPLETION(battery->read_completion);
76
77         enable_irq(battery->irq);
78         battery->cell->enable(battery->pdev);
79
80         t = wait_for_completion_interruptible_timeout(&battery->read_completion,
81                 HZ);
82
83         if (t > 0) {
84                 val = readw(battery->base) & 0xfff;
85
86                 if (battery->pdata->info.voltage_max_design <= 2500000)
87                         val = (val * 78125UL) >> 7UL;
88                 else
89                         val = ((val * 924375UL) >> 9UL) + 33000;
90                 voltage = (long)val;
91         } else {
92                 voltage = t ? t : -ETIMEDOUT;
93         }
94
95         battery->cell->disable(battery->pdev);
96         disable_irq(battery->irq);
97
98         mutex_unlock(&battery->lock);
99
100         return voltage;
101 }
102
103 static int jz_battery_get_capacity(struct power_supply *psy)
104 {
105         struct jz_battery *jz_battery = psy_to_jz_battery(psy);
106         struct power_supply_info *info = &jz_battery->pdata->info;
107         long voltage;
108         int ret;
109         int voltage_span;
110
111         voltage = jz_battery_read_voltage(jz_battery);
112
113         if (voltage < 0)
114                 return voltage;
115
116         voltage_span = info->voltage_max_design - info->voltage_min_design;
117         ret = ((voltage - info->voltage_min_design) * 100) / voltage_span;
118
119         if (ret > 100)
120                 ret = 100;
121         else if (ret < 0)
122                 ret = 0;
123
124         return ret;
125 }
126
127 static int jz_battery_get_property(struct power_supply *psy,
128         enum power_supply_property psp, union power_supply_propval *val)
129 {
130         struct jz_battery *jz_battery = psy_to_jz_battery(psy);
131         struct power_supply_info *info = &jz_battery->pdata->info;
132         long voltage;
133
134         switch (psp) {
135         case POWER_SUPPLY_PROP_STATUS:
136                 val->intval = jz_battery->status;
137                 break;
138         case POWER_SUPPLY_PROP_TECHNOLOGY:
139                 val->intval = jz_battery->pdata->info.technology;
140                 break;
141         case POWER_SUPPLY_PROP_HEALTH:
142                 voltage = jz_battery_read_voltage(jz_battery);
143                 if (voltage < info->voltage_min_design)
144                         val->intval = POWER_SUPPLY_HEALTH_DEAD;
145                 else
146                         val->intval = POWER_SUPPLY_HEALTH_GOOD;
147                 break;
148         case POWER_SUPPLY_PROP_CAPACITY:
149                 val->intval = jz_battery_get_capacity(psy);
150                 break;
151         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
152                 val->intval = jz_battery_read_voltage(jz_battery);
153                 if (val->intval < 0)
154                         return val->intval;
155                 break;
156         case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
157                 val->intval = info->voltage_max_design;
158                 break;
159         case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
160                 val->intval = info->voltage_min_design;
161                 break;
162         case POWER_SUPPLY_PROP_PRESENT:
163                 val->intval = 1;
164                 break;
165         default:
166                 return -EINVAL;
167         }
168         return 0;
169 }
170
171 static void jz_battery_external_power_changed(struct power_supply *psy)
172 {
173         struct jz_battery *jz_battery = psy_to_jz_battery(psy);
174
175         cancel_delayed_work(&jz_battery->work);
176         schedule_delayed_work(&jz_battery->work, 0);
177 }
178
179 static irqreturn_t jz_battery_charge_irq(int irq, void *data)
180 {
181         struct jz_battery *jz_battery = data;
182
183         cancel_delayed_work(&jz_battery->work);
184         schedule_delayed_work(&jz_battery->work, 0);
185
186         return IRQ_HANDLED;
187 }
188
189 static void jz_battery_update(struct jz_battery *jz_battery)
190 {
191         int status;
192         long voltage;
193         bool has_changed = false;
194         int is_charging;
195
196         if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
197                 is_charging = gpio_get_value(jz_battery->pdata->gpio_charge);
198                 is_charging ^= jz_battery->pdata->gpio_charge_active_low;
199                 if (is_charging)
200                         status = POWER_SUPPLY_STATUS_CHARGING;
201                 else
202                         status = POWER_SUPPLY_STATUS_NOT_CHARGING;
203
204                 if (status != jz_battery->status) {
205                         jz_battery->status = status;
206                         has_changed = true;
207                 }
208         }
209
210         voltage = jz_battery_read_voltage(jz_battery);
211         if (abs(voltage - jz_battery->voltage) < 50000) {
212                 jz_battery->voltage = voltage;
213                 has_changed = true;
214         }
215
216         if (has_changed)
217                 power_supply_changed(&jz_battery->battery);
218 }
219
220 static enum power_supply_property jz_battery_properties[] = {
221         POWER_SUPPLY_PROP_STATUS,
222         POWER_SUPPLY_PROP_TECHNOLOGY,
223         POWER_SUPPLY_PROP_HEALTH,
224         POWER_SUPPLY_PROP_CAPACITY,
225         POWER_SUPPLY_PROP_VOLTAGE_NOW,
226         POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
227         POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
228         POWER_SUPPLY_PROP_PRESENT,
229 };
230
231 static void jz_battery_work(struct work_struct *work)
232 {
233         /* Too small interval will increase system workload */
234         const int interval = HZ * 30;
235         struct jz_battery *jz_battery = container_of(work, struct jz_battery,
236                                             work.work);
237
238         jz_battery_update(jz_battery);
239         schedule_delayed_work(&jz_battery->work, interval);
240 }
241
242 static int __devinit jz_battery_probe(struct platform_device *pdev)
243 {
244         int ret = 0;
245         struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data;
246         struct jz_battery *jz_battery;
247         struct power_supply *battery;
248
249         jz_battery = kzalloc(sizeof(*jz_battery), GFP_KERNEL);
250         if (!jz_battery) {
251                 dev_err(&pdev->dev, "Failed to allocate driver structure\n");
252                 return -ENOMEM;
253         }
254
255         jz_battery->cell = pdev->dev.platform_data;
256
257         jz_battery->irq = platform_get_irq(pdev, 0);
258         if (jz_battery->irq < 0) {
259                 ret = jz_battery->irq;
260                 dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
261                 goto err_free;
262         }
263
264         jz_battery->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
265         if (!jz_battery->mem) {
266                 ret = -ENOENT;
267                 dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
268                 goto err_free;
269         }
270
271         jz_battery->mem = request_mem_region(jz_battery->mem->start,
272                                 resource_size(jz_battery->mem), pdev->name);
273         if (!jz_battery->mem) {
274                 ret = -EBUSY;
275                 dev_err(&pdev->dev, "Failed to request mmio memory region\n");
276                 goto err_free;
277         }
278
279         jz_battery->base = ioremap_nocache(jz_battery->mem->start,
280                                 resource_size(jz_battery->mem));
281         if (!jz_battery->base) {
282                 ret = -EBUSY;
283                 dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
284                 goto err_release_mem_region;
285         }
286
287         battery = &jz_battery->battery;
288         battery->name = pdata->info.name;
289         battery->type = POWER_SUPPLY_TYPE_BATTERY;
290         battery->properties     = jz_battery_properties;
291         battery->num_properties = ARRAY_SIZE(jz_battery_properties);
292         battery->get_property = jz_battery_get_property;
293         battery->external_power_changed = jz_battery_external_power_changed;
294         battery->use_for_apm = 1;
295
296         jz_battery->pdata = pdata;
297         jz_battery->pdev = pdev;
298
299         init_completion(&jz_battery->read_completion);
300         mutex_init(&jz_battery->lock);
301
302         INIT_DELAYED_WORK(&jz_battery->work, jz_battery_work);
303
304         ret = request_irq(jz_battery->irq, jz_battery_irq_handler, 0, pdev->name,
305                         jz_battery);
306         if (ret) {
307                 dev_err(&pdev->dev, "Failed to request irq %d\n", ret);
308                 goto err_iounmap;
309         }
310         disable_irq(jz_battery->irq);
311
312         if (gpio_is_valid(pdata->gpio_charge)) {
313                 ret = gpio_request(pdata->gpio_charge, dev_name(&pdev->dev));
314                 if (ret) {
315                         dev_err(&pdev->dev, "charger state gpio request failed.\n");
316                         goto err_free_irq;
317                 }
318                 ret = gpio_direction_input(pdata->gpio_charge);
319                 if (ret) {
320                         dev_err(&pdev->dev, "charger state gpio set direction failed.\n");
321                         goto err_free_gpio;
322                 }
323
324                 jz_battery->charge_irq = gpio_to_irq(pdata->gpio_charge);
325
326                 if (jz_battery->charge_irq >= 0) {
327                         ret = request_irq(jz_battery->charge_irq,
328                                     jz_battery_charge_irq,
329                                     IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
330                                     dev_name(&pdev->dev), jz_battery);
331                         if (ret) {
332                                 dev_err(&pdev->dev, "Failed to request charge irq: %d\n", ret);
333                                 goto err_free_gpio;
334                         }
335                 }
336         } else {
337                 jz_battery->charge_irq = -1;
338         }
339
340         if (jz_battery->pdata->info.voltage_max_design <= 2500000)
341                 jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB,
342                         JZ_ADC_CONFIG_BAT_MB);
343         else
344                 jz4740_adc_set_config(pdev->dev.parent, JZ_ADC_CONFIG_BAT_MB, 0);
345
346         ret = power_supply_register(&pdev->dev, &jz_battery->battery);
347         if (ret) {
348                 dev_err(&pdev->dev, "power supply battery register failed.\n");
349                 goto err_free_charge_irq;
350         }
351
352         platform_set_drvdata(pdev, jz_battery);
353         schedule_delayed_work(&jz_battery->work, 0);
354
355         return 0;
356
357 err_free_charge_irq:
358         if (jz_battery->charge_irq >= 0)
359                 free_irq(jz_battery->charge_irq, jz_battery);
360 err_free_gpio:
361         if (gpio_is_valid(pdata->gpio_charge))
362                 gpio_free(jz_battery->pdata->gpio_charge);
363 err_free_irq:
364         free_irq(jz_battery->irq, jz_battery);
365 err_iounmap:
366         platform_set_drvdata(pdev, NULL);
367         iounmap(jz_battery->base);
368 err_release_mem_region:
369         release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
370 err_free:
371         kfree(jz_battery);
372         return ret;
373 }
374
375 static int __devexit jz_battery_remove(struct platform_device *pdev)
376 {
377         struct jz_battery *jz_battery = platform_get_drvdata(pdev);
378
379         cancel_delayed_work_sync(&jz_battery->work);
380
381         if (gpio_is_valid(jz_battery->pdata->gpio_charge)) {
382                 if (jz_battery->charge_irq >= 0)
383                         free_irq(jz_battery->charge_irq, jz_battery);
384                 gpio_free(jz_battery->pdata->gpio_charge);
385         }
386
387         power_supply_unregister(&jz_battery->battery);
388
389         free_irq(jz_battery->irq, jz_battery);
390
391         iounmap(jz_battery->base);
392         release_mem_region(jz_battery->mem->start, resource_size(jz_battery->mem));
393         kfree(jz_battery);
394
395         return 0;
396 }
397
398 #ifdef CONFIG_PM
399 static int jz_battery_suspend(struct device *dev)
400 {
401         struct jz_battery *jz_battery = dev_get_drvdata(dev);
402
403         cancel_delayed_work_sync(&jz_battery->work);
404         jz_battery->status = POWER_SUPPLY_STATUS_UNKNOWN;
405
406         return 0;
407 }
408
409 static int jz_battery_resume(struct device *dev)
410 {
411         struct jz_battery *jz_battery = dev_get_drvdata(dev);
412
413         schedule_delayed_work(&jz_battery->work, 0);
414
415         return 0;
416 }
417
418 static const struct dev_pm_ops jz_battery_pm_ops = {
419         .suspend        = jz_battery_suspend,
420         .resume         = jz_battery_resume,
421 };
422
423 #define JZ_BATTERY_PM_OPS (&jz_battery_pm_ops)
424 #else
425 #define JZ_BATTERY_PM_OPS NULL
426 #endif
427
428 static struct platform_driver jz_battery_driver = {
429         .probe          = jz_battery_probe,
430         .remove         = __devexit_p(jz_battery_remove),
431         .driver = {
432                 .name = "jz4740-battery",
433                 .owner = THIS_MODULE,
434                 .pm = JZ_BATTERY_PM_OPS,
435         },
436 };
437
438 static int __init jz_battery_init(void)
439 {
440         return platform_driver_register(&jz_battery_driver);
441 }
442 module_init(jz_battery_init);
443
444 static void __exit jz_battery_exit(void)
445 {
446         platform_driver_unregister(&jz_battery_driver);
447 }
448 module_exit(jz_battery_exit);
449
450 MODULE_ALIAS("platform:jz4740-battery");
451 MODULE_LICENSE("GPL");
452 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
453 MODULE_DESCRIPTION("JZ4740 SoC battery driver");