diff options
-rw-r--r-- | drivers/power/pda_power.c | 71 | ||||
-rw-r--r-- | include/linux/pda_power.h | 2 |
2 files changed, 61 insertions, 12 deletions
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c index 69f8aa3a6a4b..81b720107c3a 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> |
@@ -38,9 +39,8 @@ static struct timer_list supply_timer; | |||
38 | static struct timer_list polling_timer; | 39 | static struct timer_list polling_timer; |
39 | static int polling; | 40 | static int polling; |
40 | 41 | ||
41 | #ifdef CONFIG_USB_OTG_UTILS | ||
42 | static struct otg_transceiver *transceiver; | 42 | static struct otg_transceiver *transceiver; |
43 | #endif | 43 | static struct notifier_block otg_nb; |
44 | static struct regulator *ac_draw; | 44 | static struct regulator *ac_draw; |
45 | 45 | ||
46 | enum { | 46 | enum { |
@@ -222,7 +222,42 @@ static void polling_timer_func(unsigned long unused) | |||
222 | #ifdef CONFIG_USB_OTG_UTILS | 222 | #ifdef CONFIG_USB_OTG_UTILS |
223 | static int otg_is_usb_online(void) | 223 | static int otg_is_usb_online(void) |
224 | { | 224 | { |
225 | return (transceiver->state == OTG_STATE_B_PERIPHERAL); | 225 | return (transceiver->last_event == USB_EVENT_VBUS || |
226 | transceiver->last_event == USB_EVENT_ENUMERATED); | ||
227 | } | ||
228 | |||
229 | static int otg_is_ac_online(void) | ||
230 | { | ||
231 | return (transceiver->last_event == USB_EVENT_CHARGER); | ||
232 | } | ||
233 | |||
234 | static int otg_handle_notification(struct notifier_block *nb, | ||
235 | unsigned long event, void *unused) | ||
236 | { | ||
237 | switch (event) { | ||
238 | case USB_EVENT_CHARGER: | ||
239 | ac_status = PDA_PSY_TO_CHANGE; | ||
240 | break; | ||
241 | case USB_EVENT_VBUS: | ||
242 | case USB_EVENT_ENUMERATED: | ||
243 | usb_status = PDA_PSY_TO_CHANGE; | ||
244 | break; | ||
245 | case USB_EVENT_NONE: | ||
246 | ac_status = PDA_PSY_TO_CHANGE; | ||
247 | usb_status = PDA_PSY_TO_CHANGE; | ||
248 | break; | ||
249 | default: | ||
250 | return NOTIFY_OK; | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | * Wait a bit before reading ac/usb line status and setting charger, | ||
255 | * because ac/usb status readings may lag from irq. | ||
256 | */ | ||
257 | mod_timer(&charger_timer, | ||
258 | jiffies + msecs_to_jiffies(pdata->wait_for_status)); | ||
259 | |||
260 | return NOTIFY_OK; | ||
226 | } | 261 | } |
227 | #endif | 262 | #endif |
228 | 263 | ||
@@ -282,6 +317,14 @@ static int pda_power_probe(struct platform_device *pdev) | |||
282 | ret = PTR_ERR(ac_draw); | 317 | ret = PTR_ERR(ac_draw); |
283 | } | 318 | } |
284 | 319 | ||
320 | transceiver = otg_get_transceiver(); | ||
321 | if (transceiver && !pdata->is_usb_online) { | ||
322 | pdata->is_usb_online = otg_is_usb_online; | ||
323 | } | ||
324 | if (transceiver && !pdata->is_ac_online) { | ||
325 | pdata->is_ac_online = otg_is_ac_online; | ||
326 | } | ||
327 | |||
285 | if (pdata->is_ac_online) { | 328 | if (pdata->is_ac_online) { |
286 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); | 329 | ret = power_supply_register(&pdev->dev, &pda_psy_ac); |
287 | if (ret) { | 330 | if (ret) { |
@@ -303,13 +346,6 @@ static int pda_power_probe(struct platform_device *pdev) | |||
303 | } | 346 | } |
304 | } | 347 | } |
305 | 348 | ||
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) { | 349 | if (pdata->is_usb_online) { |
314 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); | 350 | ret = power_supply_register(&pdev->dev, &pda_psy_usb); |
315 | if (ret) { | 351 | if (ret) { |
@@ -331,6 +367,16 @@ static int pda_power_probe(struct platform_device *pdev) | |||
331 | } | 367 | } |
332 | } | 368 | } |
333 | 369 | ||
370 | if (transceiver && pdata->use_otg_notifier) { | ||
371 | otg_nb.notifier_call = otg_handle_notification; | ||
372 | ret = otg_register_notifier(transceiver, &otg_nb); | ||
373 | if (ret) { | ||
374 | dev_err(dev, "failure to register otg notifier\n"); | ||
375 | goto otg_reg_notifier_failed; | ||
376 | } | ||
377 | polling = 0; | ||
378 | } | ||
379 | |||
334 | if (polling) { | 380 | if (polling) { |
335 | dev_dbg(dev, "will poll for status\n"); | 381 | dev_dbg(dev, "will poll for status\n"); |
336 | setup_timer(&polling_timer, polling_timer_func, 0); | 382 | setup_timer(&polling_timer, polling_timer_func, 0); |
@@ -343,16 +389,17 @@ static int pda_power_probe(struct platform_device *pdev) | |||
343 | 389 | ||
344 | return 0; | 390 | return 0; |
345 | 391 | ||
392 | otg_reg_notifier_failed: | ||
393 | if (pdata->is_usb_online && usb_irq) | ||
394 | free_irq(usb_irq->start, &pda_psy_usb); | ||
346 | usb_irq_failed: | 395 | usb_irq_failed: |
347 | if (pdata->is_usb_online) | 396 | if (pdata->is_usb_online) |
348 | power_supply_unregister(&pda_psy_usb); | 397 | power_supply_unregister(&pda_psy_usb); |
349 | usb_supply_failed: | 398 | usb_supply_failed: |
350 | if (pdata->is_ac_online && ac_irq) | 399 | if (pdata->is_ac_online && ac_irq) |
351 | free_irq(ac_irq->start, &pda_psy_ac); | 400 | free_irq(ac_irq->start, &pda_psy_ac); |
352 | #ifdef CONFIG_USB_OTG_UTILS | ||
353 | if (transceiver) | 401 | if (transceiver) |
354 | otg_put_transceiver(transceiver); | 402 | otg_put_transceiver(transceiver); |
355 | #endif | ||
356 | ac_irq_failed: | 403 | ac_irq_failed: |
357 | if (pdata->is_ac_online) | 404 | if (pdata->is_ac_online) |
358 | power_supply_unregister(&pda_psy_ac); | 405 | power_supply_unregister(&pda_psy_ac); |
diff --git a/include/linux/pda_power.h b/include/linux/pda_power.h index c9e4d814ff77..2bb62bf296ac 100644 --- a/include/linux/pda_power.h +++ b/include/linux/pda_power.h | |||
@@ -35,6 +35,8 @@ struct pda_power_pdata { | |||
35 | unsigned int polling_interval; /* msecs, default is 2000 */ | 35 | unsigned int polling_interval; /* msecs, default is 2000 */ |
36 | 36 | ||
37 | unsigned long ac_max_uA; /* current to draw when on AC */ | 37 | unsigned long ac_max_uA; /* current to draw when on AC */ |
38 | |||
39 | bool use_otg_notifier; | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | #endif /* __PDA_POWER_H__ */ | 42 | #endif /* __PDA_POWER_H__ */ |