summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuresh Mangipudi <smangipudi@nvidia.com>2011-08-01 15:34:05 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:59 -0800
commit27f0f234d2416b52a5d1d5db40e6caa43c25bd90 (patch)
tree2130468c4fa619579a042aa453e0a2b72d1c9e7e
parent73b36a570d4b92c5214d2e30c0f19a928aa24723 (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 Reviewed-on: http://git-master/r/42412 (cherry picked from commit a60b2ef0800ba3bebcc6908d3c471d7b0e97423f) Original-Change-Id: I4912872e03fbd05ac6cd4a7b7a9c7401dc05e480 Reviewed-on: http://git-master/r/44314 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: Rd0abb04da12a158dad74bd6a2cfb8c734a91fab7
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c63
-rw-r--r--drivers/usb/otg/tegra-otg.c33
2 files changed, 53 insertions, 43 deletions
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 2a4e4c2436e6..44a253e99d3b 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -3139,42 +3139,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 (!(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) {
+
+ 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;
}
static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state)
diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c
index 3c1f1663d0ad..e24d5775fbc1 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;
@@ -394,8 +396,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();
@@ -410,20 +413,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)