usb: gadget: Reset the controller when cable is unplugged
authorBenoit Goby <benoit@android.com>
Fri, 20 Aug 2010 04:42:23 +0000 (21:42 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:27:46 +0000 (16:27 -0700)
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>
drivers/usb/gadget/fsl_tegra_udc.c
drivers/usb/gadget/fsl_udc_core.c

index 42f3effd3ba5588d8dc802fa852ea7254f335f27..6091d1f7ea0cea4a82a4c11bc9b24b2c8118d321 100644 (file)
@@ -51,14 +51,15 @@ int fsl_udc_clk_init(struct platform_device *pdev)
        if (instance == -1)
                instance = 0;
 
-       phy = tegra_usb_phy_open(instance, udc_base, pdata->phy_config);
+       phy = tegra_usb_phy_open(instance, udc_base, pdata->phy_config,
+                                               TEGRA_USB_PHY_MODE_DEVICE);
        if (IS_ERR(phy)) {
                dev_err(&pdev->dev, "Can't open phy\n");
                err = PTR_ERR(phy);
                goto err1;
        }
 
-       tegra_usb_phy_power_on(phy, TEGRA_USB_PHY_MODE_DEVICE);
+       tegra_usb_phy_power_on(phy);
 
        return 0;
 err1:
@@ -92,5 +93,5 @@ void fsl_udc_clk_suspend(void)
 void fsl_udc_clk_resume(void)
 {
        clk_enable(udc_clk);
-       tegra_usb_phy_power_on(phy, TEGRA_USB_PHY_MODE_DEVICE);
+       tegra_usb_phy_power_on(phy);
 }
index 00961da072facbd462d522a369bbc2cd372fd26c..eb93c69951badfcad3975ebac241dfe2a3b6eb7c 100644 (file)
@@ -183,14 +183,43 @@ 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;
 #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);
@@ -213,24 +242,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);
@@ -1805,16 +1819,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
@@ -2559,6 +2574,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
        udc_controller->transceiver = otg_get_transceiver();
        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;