From 51901f900320ae52fc59c9259cd051416cf6699c Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Thu, 19 Aug 2010 21:42:23 -0700 Subject: [PATCH] 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 --- drivers/usb/gadget/fsl_tegra_udc.c | 7 ++-- drivers/usb/gadget/fsl_udc_core.c | 58 +++++++++++++++++++----------- 2 files changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index 42f3effd3ba5..6091d1f7ea0c 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -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); } diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 00961da072fa..eb93c69951ba 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -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; -- 2.34.1