diff options
author | Xin Xie <xxie@nvidia.com> | 2012-06-12 18:23:31 -0700 |
---|---|---|
committer | Lokesh Pathak <lpathak@nvidia.com> | 2012-06-18 08:53:36 -0700 |
commit | e43dc6b9b19919885908c6f02b6cc5416da06456 (patch) | |
tree | 919f8a6f0183f785e6d821449bffa4aa61802a9d | |
parent | 97d9070b427f98596224fe876149027ed15e8eed (diff) |
usb: tegra: otg: fix unbalanced suspend/resume
Becasue of a previous workaround, suspend/resume pair is implemented as
suspend/complete pair in the driver's dev_pm_ops field.
If any driver suspend routine (which is called before otg suspend)
failed, then tegra_otg_resume() will be called even tegra_otg_suspend()
is not called. This will cause disable the OTG clock, and OTG will not
generate any more IRQ.
Ideal fix would be use suspend/resume pair to implement the dev_pm_ops,
but this might break previous workaround. This patch check suspend()
routine is called or not in the resume routine; even we use suspend/
resume pair in the future, it will not cause bad behaviour.
BUG 999759
Change-Id: I88f9c28bb76c5ff9e32917904017f291456cb933
Signed-off-by: Xin Xie <xxie@nvidia.com>
Reviewed-on: http://git-master/r/108444
(cherry picked from commit c751aeea65f126d8e2df7f8a9ba02a631f958dc1)
Reviewed-on: http://git-master/r/108945
Reviewed-by: Lokesh Pathak <lpathak@nvidia.com>
Tested-by: Lokesh Pathak <lpathak@nvidia.com>
-rw-r--r-- | drivers/usb/otg/tegra-otg.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/usb/otg/tegra-otg.c b/drivers/usb/otg/tegra-otg.c index 8442fcfc2796..081ad209e41c 100644 --- a/drivers/usb/otg/tegra-otg.c +++ b/drivers/usb/otg/tegra-otg.c @@ -67,6 +67,7 @@ struct tegra_otg_data { void *charger_cb_data; bool interrupt_mode; bool builtin_host; + bool suspended }; static struct tegra_otg_data *tegra_clone; @@ -419,6 +420,7 @@ static int tegra_otg_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tegra); tegra_clone = tegra; tegra->interrupt_mode = true; + tegra->suspended = false; tegra->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(tegra->clk)) { @@ -528,6 +530,8 @@ static int tegra_otg_suspend(struct device *dev) if (otg->state == OTG_STATE_B_PERIPHERAL) tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND); + tegra->suspended = true; + DBG("%s(%d) END\n", __func__, __LINE__); return 0; } @@ -541,6 +545,9 @@ static void tegra_otg_resume(struct device *dev) unsigned long flags; DBG("%s(%d) BEGIN\n", __func__, __LINE__); + if (!tegra->suspended) + return; + /* Clear pending interrupts */ clk_enable(tegra->clk); val = otg_readl(tegra, USB_PHY_WAKEUP); @@ -564,6 +571,9 @@ static void tegra_otg_resume(struct device *dev) irq_work(&tegra->work); enable_interrupt(tegra, true); + + tegra->suspended = false; + DBG("%s(%d) END\n", __func__, __LINE__); } |