diff options
author | Dima Zavin <dima@android.com> | 2011-07-10 19:01:15 -0400 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2011-08-19 13:03:22 -0400 |
commit | 9ad63986c606c60e2e916b1b96f22991f966d9cc (patch) | |
tree | 336bf435cea5ec4143134f98f0712d7a5bcc6b8c /drivers/power | |
parent | 0bea4b866448af09051e357b139f598aa70b8614 (diff) |
pda_power: Add support for using otg transceiver events
If the platform data sets the use_otg_notifier flag,
the driver will now register an otg notifier callback and listen
to transceiver events for AC/USB plug-in events instead. This would
normally be used by not specifying is_xx_online callbacks and
not specifying any irqs so the state machine is completely driven
from OTG xceiver events.
Signed-off-by: Dima Zavin <dima@android.com>
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
Diffstat (limited to 'drivers/power')
-rw-r--r-- | drivers/power/pda_power.c | 71 |
1 files changed, 59 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); |