From: Andy Luo <[email protected]>

This patch enables runtime pm support for usb host driver

Signed-off-by: Andy Luo <[email protected]>
Signed-off-by: Hao Wu <[email protected]>
---
 drivers/usb/core/hcd-pci.c |  199 +++++++++++++++++++++++++++++++-------------
 1 files changed, 142 insertions(+), 57 deletions(-)

diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 1cf2d1e..b7860f4 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -250,6 +250,10 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct 
pci_device_id *id)
        if (retval != 0)
                goto err4;
        set_hs_companion(dev, hcd);
+
+       pm_runtime_set_active(&dev->dev);
+       pm_runtime_enable(&dev->dev);
+       pm_runtime_allow(&dev->dev);
        return retval;
 
  err4:
@@ -292,6 +296,18 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
        if (!hcd)
                return;
 
+       pm_runtime_forbid(&dev->dev);
+       pm_runtime_disable(&dev->dev);
+       pm_runtime_set_suspended(&dev->dev);
+
+       /* Fake an interrupt request in order to give the driver a chance
+        * to test whether the controller hardware has been removed (e.g.,
+        * cardbus physical eject).
+        */
+       local_irq_disable();
+       usb_hcd_irq(0, hcd);
+       local_irq_enable();
+
        usb_remove_hcd(hcd);
        if (hcd->driver->flags & HCD_MEMORY) {
                iounmap(hcd->regs);
@@ -317,12 +333,50 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
        if (!hcd)
                return;
 
-       if (hcd->driver->shutdown)
+       if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
+                       hcd->driver->shutdown)
                hcd->driver->shutdown(hcd);
 }
 EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM_OPS
+
+#ifdef CONFIG_PPC_PMAC
+static void hcd_pci_set_platform_config(struct pci_dev *pci_dev, int enable)
+{
+       /* Enanble or disable ASIC clocks for USB */
+       if (machine_is(powermac)) {
+               struct device_node      *of_node;
+
+               of_node = pci_device_to_OF_node(pci_dev);
+               if (of_node)
+                       pmac_call_feature(PMAC_FTR_USB_ENABLE,
+                                       of_node, 0, enable);
+       }
+}
+
+#elif defined(CONFIG_X86_MRST)
+static void hcd_pci_set_platform_config(struct pci_dev *pci_dev, int enable)
+{
+       /* Check if it is Intel Medfield platform */
+       if (pci_dev->vendor == PCI_VENDOR_ID_INTEL &&
+                               pci_dev->device == 0x0829) {
+               if (enable) {
+                       pci_restore_state(pci_dev);
+                       pci_set_power_state(pci_dev, PCI_D0);
+               } else {
+                       pci_save_state(pci_dev);
+                       pci_set_power_state(pci_dev, PCI_D3hot);
+               }
+       }
+}
+
+#else
+static inline void hcd_pci_set_platform_config(struct pci_dev *pci_dev,
+                                               int enable)
+{}
+
+#endif /* CONFIG_PPC_PMAC */
 
 static int check_root_hub_suspended(struct device *dev)
 {
@@ -337,7 +391,7 @@ static int check_root_hub_suspended(struct device *dev)
        return 0;
 }
 
-static int hcd_pci_suspend(struct device *dev)
+static int suspend_common(struct device *dev, bool do_wakeup)
 {
        struct pci_dev          *pci_dev = to_pci_dev(dev);
        struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
@@ -374,6 +428,48 @@ static int hcd_pci_suspend(struct device *dev)
        return retval;
 }
 
+static int resume_common(struct device *dev, int event)
+{
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
+       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
+       int                     retval;
+
+       if (hcd->state != HC_STATE_SUSPENDED) {
+               dev_dbg(dev, "can't resume, not suspended!\n");
+               return 0;
+       }
+
+       retval = pci_enable_device(pci_dev);
+       if (retval < 0) {
+               dev_err(dev, "can't re-enable after resume, %d!\n", retval);
+               return retval;
+       }
+
+       pci_set_master(pci_dev);
+
+       clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+       if (hcd->driver->pci_resume) {
+               if (event != PM_EVENT_AUTO_RESUME)
+                       wait_for_companions(pci_dev, hcd);
+
+               retval = hcd->driver->pci_resume(hcd,
+                               event == PM_EVENT_RESTORE);
+               if (retval) {
+                       dev_err(dev, "PCI post-resume error %d!\n", retval);
+                       usb_hc_died(hcd);
+               }
+       }
+       return retval;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int hcd_pci_suspend(struct device *dev)
+{
+       return suspend_common(dev, device_may_wakeup(dev));
+}
+
 static int hcd_pci_suspend_noirq(struct device *dev)
 {
        struct pci_dev          *pci_dev = to_pci_dev(dev);
@@ -408,16 +504,7 @@ static int hcd_pci_suspend_noirq(struct device *dev)
                return retval;
        }
 
-#ifdef CONFIG_PPC_PMAC
-       /* Disable ASIC clocks for USB */
-       if (machine_is(powermac)) {
-               struct device_node      *of_node;
-
-               of_node = pci_device_to_OF_node(pci_dev);
-               if (of_node)
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
-       }
-#endif
+       hcd_pci_set_platform_config(pci_dev, 0);
        return retval;
 }
 
@@ -425,69 +512,65 @@ static int hcd_pci_resume_noirq(struct device *dev)
 {
        struct pci_dev          *pci_dev = to_pci_dev(dev);
 
-#ifdef CONFIG_PPC_PMAC
-       /* Reenable ASIC clocks for USB */
-       if (machine_is(powermac)) {
-               struct device_node *of_node;
-
-               of_node = pci_device_to_OF_node(pci_dev);
-               if (of_node)
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE,
-                                               of_node, 0, 1);
-       }
-#endif
+       hcd_pci_set_platform_config(pci_dev, 1);
 
        /* Go back to D0 and disable remote wakeup */
        pci_back_from_sleep(pci_dev);
        return 0;
 }
 
-static int resume_common(struct device *dev, bool hibernated)
+static int hcd_pci_resume(struct device *dev)
 {
-       struct pci_dev          *pci_dev = to_pci_dev(dev);
-       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
-       int                     retval;
+       return resume_common(dev, PM_EVENT_RESUME);
+}
 
-       if (hcd->state != HC_STATE_SUSPENDED) {
-               dev_dbg(dev, "can't resume, not suspended!\n");
-               return 0;
-       }
+static int hcd_pci_restore(struct device *dev)
+{
+       return resume_common(dev, PM_EVENT_RESTORE);
+}
 
-       retval = pci_enable_device(pci_dev);
-       if (retval < 0) {
-               dev_err(dev, "can't re-enable after resume, %d!\n", retval);
-               return retval;
-       }
+#else
 
-       pci_set_master(pci_dev);
+#define hcd_pci_suspend                NULL
+#define hcd_pci_suspend_noirq  NULL
+#define hcd_pci_resume_noirq   NULL
+#define hcd_pci_resume         NULL
+#define hcd_pci_restore                NULL
 
-       clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+#endif /* CONFIG_PM_SLEEP */
 
-       if (hcd->driver->pci_resume) {
-               /* This call should be made only during system resume,
-                * not during runtime resume.
-                */
-               wait_for_companions(pci_dev, hcd);
+#ifdef CONFIG_PM_RUNTIME
 
-               retval = hcd->driver->pci_resume(hcd, hibernated);
-               if (retval) {
-                       dev_err(dev, "PCI post-resume error %d!\n", retval);
-                       usb_hc_died(hcd);
-               }
-       }
+static int hcd_pci_runtime_suspend(struct device *dev)
+{
+       int     retval;
+
+       device_set_wakeup_enable(dev, 1);
+       retval = suspend_common(dev, true);
+       if (retval == 0)
+               hcd_pci_set_platform_config(to_pci_dev(dev), 0);
+       dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
        return retval;
 }
 
-static int hcd_pci_resume(struct device *dev)
+static int hcd_pci_runtime_resume(struct device *dev)
 {
-       return resume_common(dev, false);
-}
+       int     retval;
 
-static int hcd_pci_restore(struct device *dev)
-{
-       return resume_common(dev, true);
+       device_set_wakeup_enable(dev, 0);
+       hcd_pci_set_platform_config(to_pci_dev(dev), 1);
+       retval = resume_common(dev, PM_EVENT_RESTORE);
+       dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
+       return retval;
 }
 
+#else
+
+#define hcd_pci_runtime_suspend        NULL
+#define hcd_pci_runtime_resume NULL
+
+#endif /* CONFIG_PM_RUNTIME */
+
 const struct dev_pm_ops usb_hcd_pci_pm_ops = {
        .suspend        = hcd_pci_suspend,
        .suspend_noirq  = hcd_pci_suspend_noirq,
@@ -501,7 +584,9 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
        .poweroff_noirq = hcd_pci_suspend_noirq,
        .restore_noirq  = hcd_pci_resume_noirq,
        .restore        = hcd_pci_restore,
+       .runtime_suspend = hcd_pci_runtime_suspend,
+       .runtime_resume = hcd_pci_runtime_resume,
 };
 EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
 
-#endif /* CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM_OPS */
-- 
1.6.0.6

Attachment: 0003-usb-core-add-runtime-pm-support-for-Intel-Medfield.patch
Description: 0003-usb-core-add-runtime-pm-support-for-Intel-Medfield.patch

_______________________________________________
MeeGo-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to