diff options
author | Venkat Moganty <vmoganty@nvidia.com> | 2011-07-21 22:32:54 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2011-08-10 12:29:03 -0700 |
commit | bb89f2bcf54d8037721a8df5e09a1ab55712de3f (patch) | |
tree | e00c8a2732c490368c5134dab8db1d9be3888003 | |
parent | 94f5c064dd99407a29804034e1abdae766a487e6 (diff) |
usb: otg: tegra: Fix kernel freeze during resume
Delaying the otg resume to occur after resuming all the devices.
This will make sure all the storage drivers are resumed before
un-register of the host controller driver.
Bug 843287
Reviewed-on: http://git-master/r/42412
(cherry picked from commit a60b2ef0800ba3bebcc6908d3c471d7b0e97423f)
Change-Id: If9a753e63262932833e14bdbf33ad70db72cc7f1
Reviewed-on: http://git-master/r/43438
Reviewed-by: David Schalig <dschalig@nvidia.com>
Reviewed-by: Jonathan Mayo <jmayo@nvidia.com>
Tested-by: David Schalig <dschalig@nvidia.com>
Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>
-rw-r--r-- | drivers/usb/gadget/fsl_udc_core.c | 62 | ||||
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 33 |
2 files changed, 52 insertions, 43 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 1dba4dfcacfd..ae02816b080d 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2890,43 +2890,45 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - if (udc_controller->transceiver) { + if (udc_controller->transceiver) { - if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) { - /* If ID status is low means host is connected, return */ - return 0; - } - /* check for VBUS */ - if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { - /* if there is no VBUS then power down the clocks and return */ - return 0; - } else { + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_ID_PIN_STATUS)) { + /* If ID status is low means host is connected, return */ + return 0; + } + /* check for VBUS */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) { + /* if there is no VBUS then power down the clocks and return */ + return 0; + } else { + if (udc_controller->transceiver->state == OTG_STATE_A_HOST) + return 0; + fsl_udc_clk_resume(true); + /* Detected VBUS set the transceiver state to device mode */ + udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL; + } + } else { + /* enable the clocks to the controller */ fsl_udc_clk_resume(true); - /* Detected VBUS set the transceiver state to device mode */ - udc_controller->transceiver->state = OTG_STATE_B_PERIPHERAL; - } - } else { - /* enable the clocks to the controller */ - fsl_udc_clk_resume(true); - } + } #if defined(CONFIG_ARCH_TEGRA) - fsl_udc_restart(udc_controller); + fsl_udc_restart(udc_controller); #else - /* Enable DR irq reg and set controller Run */ - if (udc_controller->stopped) { - dr_controller_setup(udc_controller); - dr_controller_run(udc_controller); - } - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; + /* Enable DR irq reg and set controller Run */ + if (udc_controller->stopped) { + dr_controller_setup(udc_controller); + dr_controller_run(udc_controller); + } + udc_controller->usb_state = USB_STATE_ATTACHED; + udc_controller->ep0_state = WAIT_FOR_SETUP; + udc_controller->ep0_dir = 0; #endif - /* Power down the phy if cable is not connected */ - if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) - fsl_udc_clk_suspend(false); + /* Power down the phy if cable is not connected */ + if (!(fsl_readl(&usb_sys_regs->vbus_wakeup) & USB_SYS_VBUS_STATUS)) + fsl_udc_clk_suspend(false); - return 0; + return 0; } /*------------------------------------------------------------------------- diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index ffcb4b3e46b4..9c894743d5d6 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -188,12 +188,13 @@ static irqreturn_t tegra_otg_irq(int irq, void *data) spin_lock_irqsave(&tegra->lock, flags); val = otg_readl(tegra, USB_PHY_WAKEUP); - otg_writel(tegra, val, USB_PHY_WAKEUP); - - if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) { - tegra->int_status = val; - tegra->detect_vbus = false; - schedule_work(&tegra->work); + if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) { + otg_writel(tegra, val, USB_PHY_WAKEUP); + if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) { + tegra->int_status = val; + tegra->detect_vbus = false; + schedule_work(&tegra->work); + } } spin_unlock_irqrestore(&tegra->lock, flags); @@ -377,8 +378,9 @@ static int __exit tegra_otg_remove(struct platform_device *pdev) } #ifdef CONFIG_PM -static int tegra_otg_suspend(struct platform_device *pdev, pm_message_t state) +static int tegra_otg_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); struct otg_transceiver *otg = &tegra_otg->otg; enum usb_otg_state from = otg->state; @@ -397,8 +399,9 @@ static int tegra_otg_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int tegra_otg_resume(struct platform_device * pdev) +static void tegra_otg_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); struct tegra_otg_data *tegra_otg = platform_get_drvdata(pdev); int val; unsigned long flags; @@ -427,20 +430,24 @@ static int tegra_otg_resume(struct platform_device * pdev) spin_unlock_irqrestore(&tegra_otg->lock, flags); } - return 0; + return; } + +static const struct dev_pm_ops tegra_otg_pm_ops = { + .complete = tegra_otg_resume, + .suspend = tegra_otg_suspend, +}; #endif static struct platform_driver tegra_otg_driver = { .driver = { .name = "tegra-otg", +#ifdef CONFIG_PM + .pm = &tegra_otg_pm_ops, +#endif }, .remove = __exit_p(tegra_otg_remove), .probe = tegra_otg_probe, -#ifdef CONFIG_PM - .suspend = tegra_otg_suspend, - .resume = tegra_otg_resume, -#endif }; static int __init tegra_otg_init(void) |