diff options
author | Li Jun <B47624@freescale.com> | 2014-04-25 13:56:20 +0800 |
---|---|---|
committer | Li Jun <B47624@freescale.com> | 2014-04-25 16:31:57 +0800 |
commit | b4f604b50bd59e3dd10fcce40523c0f26aaadf8b (patch) | |
tree | 88d58c1becf1ab57ae52f5346c23f7c58895dcfc | |
parent | c78c4d7c0c515e98fe81bf0f5e3a183cf52baeea (diff) |
ENGR00310498 usb: chipidea: otg: fix otg role switch from host to device failure
This patch fix the failure when OTG port switch from host to device mode
after removes ID cable with usb device(e.g usb hub) connected.
How to reproduce:
- Enable console wakeup:
echo enabled > /sys/class/tty/ttymxc0/power/wakeup
- Connect a usb hub with ID cable to OTG port.
- Suspend the system:
ehco mem > /sys/power/state
- Wakeup the system by console.
- Remove ID cable together with usb hub.
- OTG port cannot switch to device role.
Root cause:
In this case, ID change interrupt generates before port change interrupt,
so with irq disabled, ci_handle_id_switch() will find there is usb device
still connected and wait it to disconnect by sleep, but disconnect will not
happen since usb irq still disabled so port change irq has no chance to be
handled.
How this patch is fixing this issue:
This patch enables irq before sleep and disables irq after, thus port change
irq can be handled and usb device disconnection can timely happen, then
ci_handle_id_switch() can stop host and switch to device role correctly.
meanwhile change the delay time to 10~15 ms to avoid too frequent connection
check and irq enable/disable.
Signed-off-by: Li Jun <b47624@freescale.com>
-rw-r--r-- | drivers/usb/chipidea/otg.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index fb8a1fe6ead3..70ac5c4028af 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -100,8 +100,11 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) if ((ci->role == CI_ROLE_HOST) && ci->hcd) { roothub = ci->hcd->self.root_hub; for (i = 0; i < roothub->maxchild; ++i) { - while (usb_hub_find_child(roothub, (i + 1))) - usleep_range(500, 1000); + while (usb_hub_find_child(roothub, (i + 1))) { + enable_irq(ci->irq); + usleep_range(10000, 15000); + disable_irq_nosync(ci->irq); + } } } |