summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVenkat Moganty <vmoganty@nvidia.com>2011-07-21 22:32:54 +0530
committerNiket Sirsi <nsirsi@nvidia.com>2011-07-25 16:04:15 -0700
commita60b2ef0800ba3bebcc6908d3c471d7b0e97423f (patch)
treea07c178a56585b2b2c5d5512be2f66289c25acbe
parentb3b7824a869f8db2cef777b25f44d702832ea522 (diff)
usb: otg: tegra: Fix for 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 Change-Id: I38c801d61e0bc903c0cb074d84d753b947f7b7f5 Reviewed-on: http://git-master/r/42412 Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com> Tested-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c62
-rw-r--r--drivers/usb/otg/tegra-otg.c33
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 82118cd1cbf7..cb5b731ec558 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -2862,43 +2862,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 28e8bd0c2063..f372c021ef46 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);
@@ -374,8 +375,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;
@@ -391,8 +393,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);
tegra_otg_enable_clk();
@@ -407,20 +410,24 @@ static int tegra_otg_resume(struct platform_device * pdev)
writel(tegra_otg->intr_reg_data, (tegra_otg->regs + USB_PHY_WAKEUP));
clk_disable(tegra_otg->clk);
- 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)