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>
This commit is contained in:
Benoit Goby
2010-08-19 21:42:23 -07:00
committed by Colin Cross
parent 549d5a2073
commit 51901f9003
2 changed files with 41 additions and 24 deletions

View 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);
}

View 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;