diff options
Diffstat (limited to 'drivers/power/pda_power.c')
-rw-r--r-- | drivers/power/pda_power.c | 89 |
1 files changed, 68 insertions, 21 deletions
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 69f8aa3a6a4..fd49689738a 100644 --- a/drivers/power/pda_power.c +++ b/drivers/power/pda_power.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/notifier.h> | ||
17 | #include <linux/power_supply.h> | 18 | #include <linux/power_supply.h> |
18 | #include <linux/pda_power.h> | 19 | #include <linux/pda_power.h> |
19 | #include <linux/regulator/consumer.h> | 20 | #include <linux/regulator/consumer.h> |
@@ -40,7 +41,9 @@ static int polling; | |||
40 | 41 | ||
41 | #ifdef CONFIG_USB_OTG_UTILS | 42 | #ifdef CONFIG_USB_OTG_UTILS |
42 | static struct otg_transceiver *transceiver; | 43 | static struct otg_transceiver *transceiver; |
44 | static struct notifier_block otg_nb; | ||
43 | #endif | 45 | #endif |
46 | |||
44 | static struct regulator *ac_draw; | 47 | static struct regulator *ac_draw; |
45 | 48 | ||
46 | enum { | 49 | enum { |
@@ -222,7 +225,42 @@ static void polling_timer_func(unsigned long unused) | |||
222 | #ifdef CONFIG_USB_OTG_UTILS | 225 | #ifdef CONFIG_USB_OTG_UTILS |
223 | static int otg_is_usb_online(void) | 226 | static int otg_is_usb_online(void) |
224 | { | 227 | { |
225 | return (transceiver->state == OTG_STATE_B_PERIPHERAL); | 228 | return (transceiver->last_event == USB_EVENT_VBUS || |
229 | transceiver->last_event == USB_EVENT_ENUMERATED); | ||
230 | } | ||
231 | |||
232 | static int otg_is_ac_online(void) | ||
233 | { | ||
234 | return (transceiver->last_event == USB_EVENT_CHARGER); | ||
235 | } | ||
236 | |||
237 | static int otg_handle_notification(struct notifier_block *nb, | ||
238 | unsigned long event, void *unused) | ||
239 | { | ||
240 | switch (event) { | ||
241 | case USB_EVENT_CHARGER: | ||
242 | ac_status = PDA_PSY_TO_CHANGE; | ||
243 | break; | ||
244 | case USB_EVENT_VBUS: | ||
245 | case USB_EVENT_ENUMERATED: | ||
246 | usb_status = PDA_PSY_TO_CHANGE; | ||
247 | break; | ||
248 | case USB_EVENT_NONE: | ||
249 | ac_status = PDA_PSY_TO_CHANGE; | ||
250 | usb_status = PDA_PSY_TO_CHANGE; | ||
251 | break; | ||
252 | default: | ||
253 | return NOTIFY_OK; | ||
254 | } | ||
255 | |||
256 | /* | ||
257 | * Wait a bit before reading ac/usb line status and setting charger, | ||
258 | * because ac/usb status readings may lag from irq. | ||
259 | */ | ||
260 | mod_timer(&charger_timer, | ||
261 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); | ||
262 | |||
263 | return NOTIFY_OK; | ||
226 | } | 264 | } |
227 | #endif | 265 | #endif |
228 | 266 | ||
@@ -282,6 +320,16 @@ static int pda_power_probe(struct platform_device *pdev) | |||
282 | ret = PTR_ERR(ac_draw); | 320 | ret = PTR_ERR(ac_draw); |
283 | } | 321 | } |
284 | 322 | ||
323 | #ifdef CONFIG_USB_OTG_UTILS | ||
324 | transceiver = otg_get_transceiver(); | ||
325 | if (transceiver && !pdata->is_usb_online) { | ||
326 | pdata->is_usb_online = otg_is_usb_online; | ||
327 | } | ||
328 | if (transceiver && !pdata->is_ac_online) { | ||
329 | pdata->is_ac_online = otg_is_ac_online; | ||
330 | } | ||
331 | #endif | ||
332 | |||
285 | if (pdata->is_ac_online) { | 333 | if (pdata->is_ac_online) { |
286 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); | 334 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); |
287 | if (ret) { | 335 | if (ret) { |
@@ -303,13 +351,6 @@ static int pda_power_probe(struct platform_device *pdev) | |||
303 | } | 351 | } |
304 | } | 352 | } |
305 | 353 | ||
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; | ||
310 | } | ||
311 | #endif | ||
312 | |||
313 | if (pdata->is_usb_online) { | 354 | if (pdata->is_usb_online) { |
314 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); | 355 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); |
315 | if (ret) { | 356 | if (ret) { |
@@ -331,6 +372,18 @@ static int pda_power_probe(struct platform_device *pdev) | |||
331 | } | 372 | } |
332 | } | 373 | } |
333 | 374 | ||
375 | #ifdef CONFIG_USB_OTG_UTILS | ||
376 | if (transceiver && pdata->use_otg_notifier) { | ||
377 | otg_nb.notifier_call = otg_handle_notification; | ||
378 | ret = otg_register_notifier(transceiver, &otg_nb); | ||
379 | if (ret) { | ||
380 | dev_err(dev, "failure to register otg notifier\n"); | ||
381 | goto otg_reg_notifier_failed; | ||
382 | } | ||
383 | polling = 0; | ||
384 | } | ||
385 | #endif | ||
386 | |||
334 | if (polling) { | 387 | if (polling) { |
335 | dev_dbg(dev, "will poll for status\n"); | 388 | dev_dbg(dev, "will poll for status\n"); |
336 | setup_timer(&polling_timer, polling_timer_func, 0); | 389 | setup_timer(&polling_timer, polling_timer_func, 0); |
@@ -343,6 +396,11 @@ static int pda_power_probe(struct platform_device *pdev) | |||
343 | 396 | ||
344 | return 0; | 397 | return 0; |
345 | 398 | ||
399 | #ifdef CONFIG_USB_OTG_UTILS | ||
400 | otg_reg_notifier_failed: | ||
401 | if (pdata->is_usb_online && usb_irq) | ||
402 | free_irq(usb_irq->start, &pda_psy_usb); | ||
403 | #endif | ||
346 | usb_irq_failed: | 404 | usb_irq_failed: |
347 | if (pdata->is_usb_online) | 405 | if (pdata->is_usb_online) |
348 | power_supply_unregister(&pda_psy_usb); | 406 | power_supply_unregister(&pda_psy_usb); |
@@ -440,8 +498,6 @@ static int pda_power_resume(struct platform_device *pdev) | |||
440 | #define pda_power_resume NULL | 498 | #define pda_power_resume NULL |
441 | #endif /* CONFIG_PM */ | 499 | #endif /* CONFIG_PM */ |
442 | 500 | ||
443 | MODULE_ALIAS("platform:pda-power"); | ||
444 | |||
445 | static struct platform_driver pda_power_pdrv = { | 501 | static struct platform_driver pda_power_pdrv = { |
446 | .driver = { | 502 | .driver = { |
447 | .name = "pda-power", | 503 | .name = "pda-power", |
@@ -452,17 +508,8 @@ static struct platform_driver pda_power_pdrv = { | |||
452 | .resume = pda_power_resume, | 508 | .resume = pda_power_resume, |
453 | }; | 509 | }; |
454 | 510 | ||
455 | static int __init pda_power_init(void) | 511 | module_platform_driver(pda_power_pdrv); |
456 | { | ||
457 | return platform_driver_register(&pda_power_pdrv); | ||
458 | } | ||
459 | 512 | ||
460 | static void __exit pda_power_exit(void) | ||
461 | { | ||
462 | platform_driver_unregister(&pda_power_pdrv); | ||
463 | } | ||
464 | |||
465 | module_init(pda_power_init); | ||
466 | module_exit(pda_power_exit); | ||
467 | MODULE_LICENSE("GPL"); | 513 | MODULE_LICENSE("GPL"); |
468 | MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); | 514 | MODULE_AUTHOR("Anton Vorontsov <cbou@mail.ru>"); |
515 | MODULE_ALIAS("platform:pda-power"); | ||