summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/fsl_udc_core.c
diff options
context:
space:
mode:
authorBenoit Goby <benoit@android.com>2011-04-08 20:50:59 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:37:08 -0800
commit559d4ba235a74ff6da1f9c02ee0149afc2fef298 (patch)
treee6c3c569a3c417e5361a85b56d59569adb42002a /drivers/usb/gadget/fsl_udc_core.c
parentcd8e270e0c1ac97fe7a612007d705e8cbec1bfca (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.c58
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;