diff options
author | Benoit Goby <benoit@android.com> | 2011-04-08 20:50:59 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:37:08 -0800 |
commit | 559d4ba235a74ff6da1f9c02ee0149afc2fef298 (patch) | |
tree | e6c3c569a3c417e5361a85b56d59569adb42002a /drivers/usb/gadget/fsl_udc_core.c | |
parent | cd8e270e0c1ac97fe7a612007d705e8cbec1bfca (diff) |
usb: gadget: Reset the controller when cable is unplugged
Reset the controller when the cable is unplugged to leave it in the idle
state. The OTG driver will reconfigure it on vbus/id pin detection.
Change-Id: I87903ec86f3c35af64a141f27a34cc0720a61b08
Signed-off-by: Benoit Goby <benoit@android.com>
Diffstat (limited to 'drivers/usb/gadget/fsl_udc_core.c')
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 58 |
1 files changed, 37 insertions, 21 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 847ccccd068f..77b3cb7e6d9e 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -268,6 +268,33 @@ static void nuke(struct fsl_ep *ep, int status) Internal Hardware related function ------------------------------------------------------------------*/ +#define FSL_UDC_RESET_TIMEOUT 1000 +static int dr_controller_reset(struct fsl_udc *udc) +{ + unsigned int tmp; + unsigned long timeout; + + /* Stop and reset the usb controller */ + tmp = fsl_readl(&dr_regs->usbcmd); + tmp &= ~USB_CMD_RUN_STOP; + fsl_writel(tmp, &dr_regs->usbcmd); + + tmp = fsl_readl(&dr_regs->usbcmd); + tmp |= USB_CMD_CTRL_RESET; + fsl_writel(tmp, &dr_regs->usbcmd); + + /* Wait for reset to complete */ + timeout = jiffies + FSL_UDC_RESET_TIMEOUT; + while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { + if (time_after(jiffies, timeout)) { + ERR("udc reset timeout!\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + return 0; +} + static int dr_controller_setup(struct fsl_udc *udc) { unsigned int tmp, portctrl, ep_num; @@ -275,8 +302,10 @@ static int dr_controller_setup(struct fsl_udc *udc) #if !defined(CONFIG_ARCH_MXC) && !defined(CONFIG_ARCH_TEGRA) unsigned int ctrl; #endif +#ifdef CONFIG_ARCH_TEGRA unsigned long timeout; -#define FSL_UDC_RESET_TIMEOUT 1000 +#endif + int status; /* Config PHY interface */ portctrl = fsl_readl(&dr_regs->portsc1); @@ -299,24 +328,9 @@ static int dr_controller_setup(struct fsl_udc *udc) } fsl_writel(portctrl, &dr_regs->portsc1); - /* Stop and reset the usb controller */ - tmp = fsl_readl(&dr_regs->usbcmd); - tmp &= ~USB_CMD_RUN_STOP; - fsl_writel(tmp, &dr_regs->usbcmd); - - tmp = fsl_readl(&dr_regs->usbcmd); - tmp |= USB_CMD_CTRL_RESET; - fsl_writel(tmp, &dr_regs->usbcmd); - - /* Wait for reset to complete */ - timeout = jiffies + FSL_UDC_RESET_TIMEOUT; - while (fsl_readl(&dr_regs->usbcmd) & USB_CMD_CTRL_RESET) { - if (time_after(jiffies, timeout)) { - ERR("udc reset timeout!\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } + status = dr_controller_reset(udc); + if (status) + return status; /* Set the controller as device mode */ tmp = fsl_readl(&dr_regs->usbmode); @@ -2076,16 +2090,17 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) reset_queues(udc); /* stop the controller and turn off the clocks */ dr_controller_stop(udc); + dr_controller_reset(udc); fsl_udc_clk_suspend(); udc->vbus_active = 0; udc->usb_state = USB_STATE_DEFAULT; } else { spin_unlock_irqrestore(&udc->lock, flags); - return IRQ_HANDLED; + return IRQ_NONE; } } else { spin_unlock_irqrestore(&udc->lock, flags); - return IRQ_HANDLED; + return IRQ_NONE; } } #endif @@ -2885,6 +2900,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifdef CONFIG_USB_OTG_UTILS if (udc_controller->transceiver) { dr_controller_stop(udc_controller); + dr_controller_reset(udc_controller); fsl_udc_clk_suspend(); udc_controller->vbus_active = 0; udc_controller->usb_state = USB_STATE_DEFAULT; |