Host device is made a child of OTG device. Implement nop functions for runtime PM callbacks and enable runtime PM. OTG device is notfied about Host device suspend and 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@xxxxxxxxxxxxxx> --- drivers/usb/host/Kconfig | 4 +- drivers/usb/host/ehci-msm.c | 81 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index c816475..de67da1 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -142,8 +142,8 @@ 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 and memory mapping of - register address space. + clock management, powering up VBUS, memory mapping of + register address space and power management. config USB_EHCI_HCD_PPC_OF bool "EHCI support for PPC USB controller on OF platform bus" diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 7a2172a..9e46102 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -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> @@ -232,7 +233,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) { @@ -257,7 +259,11 @@ static int ehci_msm_probe(struct platform_device *pdev) } device_init_wakeup(&pdev->dev, 1); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + return 0; + put_module: module_put(otg->dev->driver->owner); put_transceiver: @@ -275,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); @@ -285,10 +293,81 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_RUNTIME +static int ehci_msm_runtime_idle(struct device *dev) +{ + dev_dbg(dev, "ehci-msm runtime idle\n"); + return 0; +} + +static int ehci_msm_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "ehci-msm runtime suspend\n"); + return 0; +} + +static int ehci_msm_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "ehci-msm runtime resume\n"); + return 0; +} +#else +#define ehci_msm_runtime_idle NULL +#define ehci_msm_runtime_suspend NULL +#define ehci_msm_runtime_resume NULL +#endif + +#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 = { + .runtime_suspend = ehci_msm_runtime_suspend, + .runtime_resume = ehci_msm_runtime_resume, + .runtime_idle = ehci_msm_runtime_idle, + .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, }, }; -- 1.7.1 -- Sent by a consultant of the Qualcomm Innovation Center, Inc. The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum. -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html