summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jun <B47624@freescale.com>2014-04-25 13:56:20 +0800
committerLi Jun <B47624@freescale.com>2014-04-25 16:31:57 +0800
commitb4f604b50bd59e3dd10fcce40523c0f26aaadf8b (patch)
tree88d58c1becf1ab57ae52f5346c23f7c58895dcfc
parentc78c4d7c0c515e98fe81bf0f5e3a183cf52baeea (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.c7
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);
+ }
}
}