USB: EHCI: msm: Add support for power management

Enable runtime PM and mark no_callbacks flag.  OTG device, parent of
HCD takes care of putting hardware into low power mode.  Adjust port
power wakeup flags during system suspend and resume.

Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Pavankumar Kondeti 2010-12-07 17:53:57 +05:30 committed by Greg Kroah-Hartman
parent b0848aea10
commit 8bb6a164b9
2 changed files with 57 additions and 2 deletions

View file

@ -150,7 +150,7 @@ config USB_EHCI_MSM
Enables support for the USB Host controller present on the
Qualcomm chipsets. Root Hub has inbuilt TT.
This driver depends on OTG driver for PHY initialization,
clock management, powering up VBUS.
clock management, powering up VBUS, and power management.
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"

View file

@ -25,6 +25,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/pm_runtime.h>
#include <linux/usb/otg.h>
#include <linux/usb/msm_hsusb_hw.h>
@ -239,7 +240,8 @@ static int ehci_msm_probe(struct platform_device *pdev)
/*
* OTG driver takes care of PHY initialization, clock management,
* powering up VBUS and mapping of registers address space.
* powering up VBUS, mapping of registers address space and power
* management.
*/
otg = otg_get_transceiver();
if (!otg) {
@ -255,6 +257,13 @@ static int ehci_msm_probe(struct platform_device *pdev)
}
device_init_wakeup(&pdev->dev, 1);
/*
* OTG device parent of HCD takes care of putting
* hardware into low power mode.
*/
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
put_transceiver:
@ -272,6 +281,8 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
otg_set_host(otg, NULL);
otg_put_transceiver(otg);
@ -281,10 +292,54 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int ehci_msm_pm_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
bool wakeup = device_may_wakeup(dev);
dev_dbg(dev, "ehci-msm PM suspend\n");
/*
* EHCI helper function has also the same check before manipulating
* port wakeup flags. We do check here the same condition before
* calling the same helper function to avoid bringing hardware
* from Low power mode when there is no need for adjusting port
* wakeup flags.
*/
if (hcd->self.root_hub->do_remote_wakeup && !wakeup) {
pm_runtime_resume(dev);
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
wakeup);
}
return 0;
}
static int ehci_msm_pm_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
dev_dbg(dev, "ehci-msm PM resume\n");
ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
return 0;
}
#else
#define ehci_msm_pm_suspend NULL
#define ehci_msm_pm_resume NULL
#endif
static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
.suspend = ehci_msm_pm_suspend,
.resume = ehci_msm_pm_resume,
};
static struct platform_driver ehci_msm_driver = {
.probe = ehci_msm_probe,
.remove = __devexit_p(ehci_msm_remove),
.driver = {
.name = "msm_hsusb_host",
.pm = &ehci_msm_dev_pm_ops,
},
};