mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-11 05:17:10 +09:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user