2 * Common power driver for PDAs and phones with one or two external
3 * power supplies (AC/USB) connected to main and backup batteries,
4 * and optional builtin charger.
6 * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
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.
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/err.h>
16 #include <linux/interrupt.h>
17 #include <linux/power_supply.h>
18 #include <linux/pda_power.h>
19 #include <linux/regulator/consumer.h>
20 #include <linux/timer.h>
21 #include <linux/jiffies.h>
22 #include <linux/usb/otg.h>
24 static inline unsigned int get_irq_flags(struct resource *res)
26 unsigned int flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED;
28 flags |= res->flags & IRQF_TRIGGER_MASK;
33 static struct device *dev;
34 static struct pda_power_pdata *pdata;
35 static struct resource *ac_irq, *usb_irq;
36 static struct delayed_work charger_work;
37 static struct delayed_work polling_work;
38 static struct delayed_work supply_work;
41 #ifdef CONFIG_USB_OTG_UTILS
42 static struct otg_transceiver *transceiver;
44 static struct regulator *ac_draw;
51 static int new_ac_status = -1;
52 static int new_usb_status = -1;
53 static int ac_status = -1;
54 static int usb_status = -1;
56 static int pda_power_get_property(struct power_supply *psy,
57 enum power_supply_property psp,
58 union power_supply_propval *val)
61 case POWER_SUPPLY_PROP_ONLINE:
62 if (psy->type == POWER_SUPPLY_TYPE_MAINS)
63 val->intval = pdata->is_ac_online ?
64 pdata->is_ac_online() : 0;
66 val->intval = pdata->is_usb_online ?
67 pdata->is_usb_online() : 0;
75 static enum power_supply_property pda_power_props[] = {
76 POWER_SUPPLY_PROP_ONLINE,
79 static char *pda_power_supplied_to[] = {
84 static struct power_supply pda_psy_ac = {
86 .type = POWER_SUPPLY_TYPE_MAINS,
87 .supplied_to = pda_power_supplied_to,
88 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
89 .properties = pda_power_props,
90 .num_properties = ARRAY_SIZE(pda_power_props),
91 .get_property = pda_power_get_property,
94 static struct power_supply pda_psy_usb = {
96 .type = POWER_SUPPLY_TYPE_USB,
97 .supplied_to = pda_power_supplied_to,
98 .num_supplicants = ARRAY_SIZE(pda_power_supplied_to),
99 .properties = pda_power_props,
100 .num_properties = ARRAY_SIZE(pda_power_props),
101 .get_property = pda_power_get_property,
104 static void update_status(void)
106 if (pdata->is_ac_online)
107 new_ac_status = !!pdata->is_ac_online();
109 if (pdata->is_usb_online)
110 new_usb_status = !!pdata->is_usb_online();
113 static void update_charger(void)
115 static int regulator_enabled;
116 int max_uA = pdata->ac_max_uA;
118 if (pdata->set_charge) {
119 if (new_ac_status > 0) {
120 dev_dbg(dev, "charger on (AC)\n");
121 pdata->set_charge(PDA_POWER_CHARGE_AC);
122 } else if (new_usb_status > 0) {
123 dev_dbg(dev, "charger on (USB)\n");
124 pdata->set_charge(PDA_POWER_CHARGE_USB);
126 dev_dbg(dev, "charger off\n");
127 pdata->set_charge(0);
129 } else if (ac_draw) {
130 if (new_ac_status > 0) {
131 regulator_set_current_limit(ac_draw, max_uA, max_uA);
132 if (!regulator_enabled) {
133 dev_dbg(dev, "charger on (AC)\n");
134 regulator_enable(ac_draw);
135 regulator_enabled = 1;
138 if (regulator_enabled) {
139 dev_dbg(dev, "charger off\n");
140 regulator_disable(ac_draw);
141 regulator_enabled = 0;
147 static void supply_work_func(struct work_struct *work)
149 if (ac_status == PDA_PSY_TO_CHANGE) {
150 ac_status = new_ac_status;
151 power_supply_changed(&pda_psy_ac);
154 if (usb_status == PDA_PSY_TO_CHANGE) {
155 usb_status = new_usb_status;
156 power_supply_changed(&pda_psy_usb);
160 static void psy_changed(void)
165 * Okay, charger set. Now wait a bit before notifying supplicants,
166 * charge power should stabilize.
168 cancel_delayed_work(&supply_work);
169 schedule_delayed_work(&supply_work,
170 msecs_to_jiffies(pdata->wait_for_charger));
173 static void charger_work_func(struct work_struct *work)
179 static irqreturn_t power_changed_isr(int irq, void *power_supply)
181 if (power_supply == &pda_psy_ac)
182 ac_status = PDA_PSY_TO_CHANGE;
183 else if (power_supply == &pda_psy_usb)
184 usb_status = PDA_PSY_TO_CHANGE;
189 * Wait a bit before reading ac/usb line status and setting charger,
190 * because ac/usb status readings may lag from irq.
192 cancel_delayed_work(&charger_work);
193 schedule_delayed_work(&charger_work,
194 msecs_to_jiffies(pdata->wait_for_status));
199 static void polling_work_func(struct work_struct *work)
203 dev_dbg(dev, "polling...\n");
207 if (!ac_irq && new_ac_status != ac_status) {
208 ac_status = PDA_PSY_TO_CHANGE;
212 if (!usb_irq && new_usb_status != usb_status) {
213 usb_status = PDA_PSY_TO_CHANGE;
220 cancel_delayed_work(&polling_work);
221 schedule_delayed_work(&polling_work,
222 msecs_to_jiffies(pdata->polling_interval));
225 #ifdef CONFIG_USB_OTG_UTILS
226 static int otg_is_usb_online(void)
228 return (transceiver->state == OTG_STATE_B_PERIPHERAL);
232 static int pda_power_probe(struct platform_device *pdev)
238 if (pdev->id != -1) {
239 dev_err(dev, "it's meaningless to register several "
240 "pda_powers; use id = -1\n");
245 pdata = pdev->dev.platform_data;
248 ret = pdata->init(dev);
256 if (!pdata->wait_for_status)
257 pdata->wait_for_status = 500;
259 if (!pdata->wait_for_charger)
260 pdata->wait_for_charger = 500;
262 if (!pdata->polling_interval)
263 pdata->polling_interval = 2000;
265 if (!pdata->ac_max_uA)
266 pdata->ac_max_uA = 500000;
268 INIT_DELAYED_WORK(&charger_work, charger_work_func);
269 INIT_DELAYED_WORK(&supply_work, supply_work_func);
271 ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac");
272 usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb");
274 if (pdata->supplied_to) {
275 pda_psy_ac.supplied_to = pdata->supplied_to;
276 pda_psy_ac.num_supplicants = pdata->num_supplicants;
277 pda_psy_usb.supplied_to = pdata->supplied_to;
278 pda_psy_usb.num_supplicants = pdata->num_supplicants;
281 ac_draw = regulator_get(dev, "ac_draw");
282 if (IS_ERR(ac_draw)) {
283 dev_dbg(dev, "couldn't get ac_draw regulator\n");
285 ret = PTR_ERR(ac_draw);
288 if (pdata->is_ac_online) {
289 ret = power_supply_register(&pdev->dev, &pda_psy_ac);
291 dev_err(dev, "failed to register %s power supply\n",
293 goto ac_supply_failed;
297 ret = request_irq(ac_irq->start, power_changed_isr,
298 get_irq_flags(ac_irq), ac_irq->name,
301 dev_err(dev, "request ac irq failed\n");
309 #ifdef CONFIG_USB_OTG_UTILS
310 transceiver = otg_get_transceiver();
311 if (transceiver && !pdata->is_usb_online) {
312 pdata->is_usb_online = otg_is_usb_online;
316 if (pdata->is_usb_online) {
317 ret = power_supply_register(&pdev->dev, &pda_psy_usb);
319 dev_err(dev, "failed to register %s power supply\n",
321 goto usb_supply_failed;
325 ret = request_irq(usb_irq->start, power_changed_isr,
326 get_irq_flags(usb_irq),
327 usb_irq->name, &pda_psy_usb);
329 dev_err(dev, "request usb irq failed\n");
338 dev_dbg(dev, "will poll for status\n");
339 INIT_DELAYED_WORK(&polling_work, polling_work_func);
340 cancel_delayed_work(&polling_work);
341 schedule_delayed_work(&polling_work,
342 msecs_to_jiffies(pdata->polling_interval));
345 if (ac_irq || usb_irq)
346 device_init_wakeup(&pdev->dev, 1);
351 if (pdata->is_usb_online)
352 power_supply_unregister(&pda_psy_usb);
354 if (pdata->is_ac_online && ac_irq)
355 free_irq(ac_irq->start, &pda_psy_ac);
356 #ifdef CONFIG_USB_OTG_UTILS
358 otg_put_transceiver(transceiver);
361 if (pdata->is_ac_online)
362 power_supply_unregister(&pda_psy_ac);
365 regulator_put(ac_draw);
375 static int pda_power_remove(struct platform_device *pdev)
377 if (pdata->is_usb_online && usb_irq)
378 free_irq(usb_irq->start, &pda_psy_usb);
379 if (pdata->is_ac_online && ac_irq)
380 free_irq(ac_irq->start, &pda_psy_ac);
383 cancel_delayed_work_sync(&polling_work);
384 cancel_delayed_work_sync(&charger_work);
385 cancel_delayed_work_sync(&supply_work);
387 if (pdata->is_usb_online)
388 power_supply_unregister(&pda_psy_usb);
389 if (pdata->is_ac_online)
390 power_supply_unregister(&pda_psy_ac);
391 #ifdef CONFIG_USB_OTG_UTILS
393 otg_put_transceiver(transceiver);
396 regulator_put(ac_draw);
406 static int ac_wakeup_enabled;
407 static int usb_wakeup_enabled;
409 static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
411 if (pdata->suspend) {
412 int ret = pdata->suspend(state);
418 if (device_may_wakeup(&pdev->dev)) {
420 ac_wakeup_enabled = !enable_irq_wake(ac_irq->start);
422 usb_wakeup_enabled = !enable_irq_wake(usb_irq->start);
428 static int pda_power_resume(struct platform_device *pdev)
430 if (device_may_wakeup(&pdev->dev)) {
431 if (usb_irq && usb_wakeup_enabled)
432 disable_irq_wake(usb_irq->start);
433 if (ac_irq && ac_wakeup_enabled)
434 disable_irq_wake(ac_irq->start);
438 return pdata->resume();
443 #define pda_power_suspend NULL
444 #define pda_power_resume NULL
445 #endif /* CONFIG_PM */
447 MODULE_ALIAS("platform:pda-power");
449 static struct platform_driver pda_power_pdrv = {
453 .probe = pda_power_probe,
454 .remove = pda_power_remove,
455 .suspend = pda_power_suspend,
456 .resume = pda_power_resume,
459 static int __init pda_power_init(void)
461 return platform_driver_register(&pda_power_pdrv);
464 static void __exit pda_power_exit(void)
466 platform_driver_unregister(&pda_power_pdrv);
469 module_init(pda_power_init);
470 module_exit(pda_power_exit);
471 MODULE_LICENSE("GPL");
472 MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");