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 timer_list charger_timer
;
37 static struct timer_list supply_timer
;
38 static struct timer_list polling_timer
;
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_timer_func(unsigned long unused
)
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 mod_timer(&supply_timer
,
169 jiffies
+ msecs_to_jiffies(pdata
->wait_for_charger
));
172 static void charger_timer_func(unsigned long unused
)
178 static irqreturn_t
power_changed_isr(int irq
, void *power_supply
)
180 if (power_supply
== &pda_psy_ac
)
181 ac_status
= PDA_PSY_TO_CHANGE
;
182 else if (power_supply
== &pda_psy_usb
)
183 usb_status
= PDA_PSY_TO_CHANGE
;
188 * Wait a bit before reading ac/usb line status and setting charger,
189 * because ac/usb status readings may lag from irq.
191 mod_timer(&charger_timer
,
192 jiffies
+ msecs_to_jiffies(pdata
->wait_for_status
));
197 static void polling_timer_func(unsigned long unused
)
201 dev_dbg(dev
, "polling...\n");
205 if (!ac_irq
&& new_ac_status
!= ac_status
) {
206 ac_status
= PDA_PSY_TO_CHANGE
;
210 if (!usb_irq
&& new_usb_status
!= usb_status
) {
211 usb_status
= PDA_PSY_TO_CHANGE
;
218 mod_timer(&polling_timer
,
219 jiffies
+ msecs_to_jiffies(pdata
->polling_interval
));
222 #ifdef CONFIG_USB_OTG_UTILS
223 static int otg_is_usb_online(void)
225 return (transceiver
->state
== OTG_STATE_B_PERIPHERAL
);
229 static int pda_power_probe(struct platform_device
*pdev
)
235 if (pdev
->id
!= -1) {
236 dev_err(dev
, "it's meaningless to register several "
237 "pda_powers; use id = -1\n");
242 pdata
= pdev
->dev
.platform_data
;
245 ret
= pdata
->init(dev
);
253 if (!pdata
->wait_for_status
)
254 pdata
->wait_for_status
= 500;
256 if (!pdata
->wait_for_charger
)
257 pdata
->wait_for_charger
= 500;
259 if (!pdata
->polling_interval
)
260 pdata
->polling_interval
= 2000;
262 if (!pdata
->ac_max_uA
)
263 pdata
->ac_max_uA
= 500000;
265 setup_timer(&charger_timer
, charger_timer_func
, 0);
266 setup_timer(&supply_timer
, supply_timer_func
, 0);
268 ac_irq
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "ac");
269 usb_irq
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
, "usb");
271 if (pdata
->supplied_to
) {
272 pda_psy_ac
.supplied_to
= pdata
->supplied_to
;
273 pda_psy_ac
.num_supplicants
= pdata
->num_supplicants
;
274 pda_psy_usb
.supplied_to
= pdata
->supplied_to
;
275 pda_psy_usb
.num_supplicants
= pdata
->num_supplicants
;
278 ac_draw
= regulator_get(dev
, "ac_draw");
279 if (IS_ERR(ac_draw
)) {
280 dev_dbg(dev
, "couldn't get ac_draw regulator\n");
282 ret
= PTR_ERR(ac_draw
);
285 if (pdata
->is_ac_online
) {
286 ret
= power_supply_register(&pdev
->dev
, &pda_psy_ac
);
288 dev_err(dev
, "failed to register %s power supply\n",
290 goto ac_supply_failed
;
294 ret
= request_irq(ac_irq
->start
, power_changed_isr
,
295 get_irq_flags(ac_irq
), ac_irq
->name
,
298 dev_err(dev
, "request ac irq failed\n");
306 #ifdef CONFIG_USB_OTG_UTILS
307 transceiver
= otg_get_transceiver();
308 if (transceiver
&& !pdata
->is_usb_online
) {
309 pdata
->is_usb_online
= otg_is_usb_online
;
313 if (pdata
->is_usb_online
) {
314 ret
= power_supply_register(&pdev
->dev
, &pda_psy_usb
);
316 dev_err(dev
, "failed to register %s power supply\n",
318 goto usb_supply_failed
;
322 ret
= request_irq(usb_irq
->start
, power_changed_isr
,
323 get_irq_flags(usb_irq
),
324 usb_irq
->name
, &pda_psy_usb
);
326 dev_err(dev
, "request usb irq failed\n");
335 dev_dbg(dev
, "will poll for status\n");
336 setup_timer(&polling_timer
, polling_timer_func
, 0);
337 mod_timer(&polling_timer
,
338 jiffies
+ msecs_to_jiffies(pdata
->polling_interval
));
341 if (ac_irq
|| usb_irq
)
342 device_init_wakeup(&pdev
->dev
, 1);
347 if (pdata
->is_usb_online
)
348 power_supply_unregister(&pda_psy_usb
);
350 if (pdata
->is_ac_online
&& ac_irq
)
351 free_irq(ac_irq
->start
, &pda_psy_ac
);
352 #ifdef CONFIG_USB_OTG_UTILS
354 otg_put_transceiver(transceiver
);
357 if (pdata
->is_ac_online
)
358 power_supply_unregister(&pda_psy_ac
);
361 regulator_put(ac_draw
);
371 static int pda_power_remove(struct platform_device
*pdev
)
373 if (pdata
->is_usb_online
&& usb_irq
)
374 free_irq(usb_irq
->start
, &pda_psy_usb
);
375 if (pdata
->is_ac_online
&& ac_irq
)
376 free_irq(ac_irq
->start
, &pda_psy_ac
);
379 del_timer_sync(&polling_timer
);
380 del_timer_sync(&charger_timer
);
381 del_timer_sync(&supply_timer
);
383 if (pdata
->is_usb_online
)
384 power_supply_unregister(&pda_psy_usb
);
385 if (pdata
->is_ac_online
)
386 power_supply_unregister(&pda_psy_ac
);
387 #ifdef CONFIG_USB_OTG_UTILS
389 otg_put_transceiver(transceiver
);
392 regulator_put(ac_draw
);
402 static int ac_wakeup_enabled
;
403 static int usb_wakeup_enabled
;
405 static int pda_power_suspend(struct platform_device
*pdev
, pm_message_t state
)
407 if (pdata
->suspend
) {
408 int ret
= pdata
->suspend(state
);
414 if (device_may_wakeup(&pdev
->dev
)) {
416 ac_wakeup_enabled
= !enable_irq_wake(ac_irq
->start
);
418 usb_wakeup_enabled
= !enable_irq_wake(usb_irq
->start
);
424 static int pda_power_resume(struct platform_device
*pdev
)
426 if (device_may_wakeup(&pdev
->dev
)) {
427 if (usb_irq
&& usb_wakeup_enabled
)
428 disable_irq_wake(usb_irq
->start
);
429 if (ac_irq
&& ac_wakeup_enabled
)
430 disable_irq_wake(ac_irq
->start
);
434 return pdata
->resume();
439 #define pda_power_suspend NULL
440 #define pda_power_resume NULL
441 #endif /* CONFIG_PM */
443 MODULE_ALIAS("platform:pda-power");
445 static struct platform_driver pda_power_pdrv
= {
449 .probe
= pda_power_probe
,
450 .remove
= pda_power_remove
,
451 .suspend
= pda_power_suspend
,
452 .resume
= pda_power_resume
,
455 static int __init
pda_power_init(void)
457 return platform_driver_register(&pda_power_pdrv
);
460 static void __exit
pda_power_exit(void)
462 platform_driver_unregister(&pda_power_pdrv
);
465 module_init(pda_power_init
);
466 module_exit(pda_power_exit
);
467 MODULE_LICENSE("GPL");
468 MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>");