[PATCH 3/4] USB: EHCI: msm: Add support for power management

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux