diff options
author | Hu hui <b29976@freescale.com> | 2010-10-22 09:41:32 +0800 |
---|---|---|
committer | Hu Hui <b29976@freescale.com> | 2010-10-22 10:04:27 +0800 |
commit | fbf5ecfc18d19e14b4ec54aa9862c3add4cf5b0a (patch) | |
tree | d6cb315bde97bcaa4864d5ed4a70458e9ce7aaeb | |
parent | a56663f8604a5f0a39c510b0d58e4fea4e129cf2 (diff) |
ENGR00132878 IMX USB:autosuspending caused device can not disconnect
if enable the auto suspend for the usb device attached to the usb otg
host port, after the usb device and it's roothub,hcd auto suspend,
disconnecting the usb device can not be realized by the roothub, because
the roothub is in the suspend state.
Signed-off-by: Hu Hui <b29976@freescale.com>
-rw-r--r-- | drivers/usb/host/ehci-arc.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-arc.c b/drivers/usb/host/ehci-arc.c index 3ee0dc4d1a31..14a8454b0a41 100644 --- a/drivers/usb/host/ehci-arc.c +++ b/drivers/usb/host/ehci-arc.c @@ -607,10 +607,33 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, } return 0; } + + if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { + fsl_usb_clk_gate(hcd->self.controller->platform_data, true); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + } /* only the otg host can go here */ /* wait for all usb device on the hcd dettached */ - while (roothub->children[0] != NULL) - msleep(1); + usb_lock_device(roothub); + if (roothub->children[0] != NULL) { + int old = hcd->self.is_b_host; + printk(KERN_DEBUG "will resume roothub and its children\n"); + hcd->self.is_b_host = 0; + /* resume the roothub, so that it can test the children is disconnected */ + if (roothub->state == USB_STATE_SUSPENDED) + usb_resume(&roothub->dev, PMSG_USER_SUSPEND); + /* we must do unlock here, the hubd thread will hold the same lock + * here release the lock, so that the hubd thread can process the usb + * disconnect event and set the children[0] be NULL, or there will be + * a deadlock */ + usb_unlock_device(roothub); + while (roothub->children[0] != NULL) + msleep(1); + usb_lock_device(roothub); + hcd->self.is_b_host = old; + } + usb_unlock_device(roothub); + if ((pdata->operating_mode != FSL_USB2_MPH_HOST) && (!(hcd->state & HC_STATE_SUSPENDED))) { printk(KERN_DEBUG "will suspend roothub and its children\n"); usb_lock_device(roothub); @@ -618,24 +641,8 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev, usb_unlock_device(roothub); } - if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { - fsl_usb_clk_gate(hcd->self.controller->platform_data, true); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - } - -#ifdef DEBUG - u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE); - mode &= USBMODE_CM_MASK; - tmp = ehci_readl(ehci, hcd->regs + 0x140); /* usbcmd */ - - printk(KERN_DEBUG "%s('%s'): suspend=%d already_suspended=%d " - "mode=%d usbcmd %08x\n", __func__, pdata->name, - pdata->suspended, pdata->already_suspended, mode, tmp); -#endif - pr_debug("%s: suspending...\n", __func__); - port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); /* save EHCI registers */ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); |