usb_hcd_pci_pm_ops provides run-time functionality for the USB HCDs. It expects that driver's data is a struct usb_hcd. This does not work if we create the HCD device is a platform device and its parent is the PCI device. We create the pci_dev from device and usb_hcd from parent's driver data. This patch is preparation to let the xhci core work under a platform device. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/core/hcd-pci.c | 133 ++++++++++++++++++++++++++++++++++++++----- include/linux/usb/hcd.h | 1 + 2 files changed, 118 insertions(+), 16 deletions(-) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ce22f4a..01f8955 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/usb.h> #include <linux/usb/hcd.h> @@ -358,11 +359,8 @@ static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable) #endif /* CONFIG_PPC_PMAC */ -static int check_root_hub_suspended(struct device *dev) +static int _check_root_hub_suspended(struct device *dev, struct usb_hcd *hcd) { - struct pci_dev *pci_dev = to_pci_dev(dev); - struct usb_hcd *hcd = pci_get_drvdata(pci_dev); - if (HCD_RH_RUNNING(hcd)) { dev_warn(dev, "Root hub is not suspended\n"); return -EBUSY; @@ -377,10 +375,26 @@ static int check_root_hub_suspended(struct device *dev) return 0; } -static int suspend_common(struct device *dev, bool do_wakeup) +static int check_root_hub_suspended(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + return _check_root_hub_suspended(dev, hcd); +} + +static int check_plat_pci_root_hub_suspended(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _check_root_hub_suspended(dev, hcd); +} + + +static int _suspend_common(struct device *dev, bool do_wakeup, + struct usb_hcd *hcd) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); int retval; /* Root hub suspend should have stopped all downstream traffic, @@ -388,7 +402,7 @@ static int suspend_common(struct device *dev, bool do_wakeup) * and the stub usb_device (which we check here). But maybe it * didn't; writing sysfs power/state files ignores such rules... */ - retval = check_root_hub_suspended(dev); + retval = _check_root_hub_suspended(dev, hcd); if (retval) return retval; @@ -432,10 +446,9 @@ static int suspend_common(struct device *dev, bool do_wakeup) return retval; } -static int resume_common(struct device *dev, int event) +static int _resume_common(struct device *dev, int event, struct usb_hcd *hcd) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct usb_hcd *hcd = pci_get_drvdata(pci_dev); int retval; if (HCD_RH_RUNNING(hcd) || @@ -477,16 +490,25 @@ static int resume_common(struct device *dev, int event) static int hcd_pci_suspend(struct device *dev) { - return suspend_common(dev, device_may_wakeup(dev)); + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + return _suspend_common(dev, device_may_wakeup(dev), hcd); } -static int hcd_pci_suspend_noirq(struct device *dev) +static int hcd_plat_pci_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _suspend_common(dev, device_may_wakeup(dev), hcd); +} + +static int _hcd_pci_suspend_noirq(struct device *dev, struct usb_hcd *hcd) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct usb_hcd *hcd = pci_get_drvdata(pci_dev); int retval; - retval = check_root_hub_suspended(dev); + retval = _check_root_hub_suspended(dev, hcd); if (retval) return retval; @@ -519,6 +541,21 @@ static int hcd_pci_suspend_noirq(struct device *dev) return retval; } +static int hcd_pci_suspend_noirq(struct device *dev) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + return _hcd_pci_suspend_noirq(dev, hcd); +} + +static int hcd_plat_pci_suspend_noirq(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _hcd_pci_suspend_noirq(dev, hcd); +} + static int hcd_pci_resume_noirq(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -532,12 +569,32 @@ static int hcd_pci_resume_noirq(struct device *dev) static int hcd_pci_resume(struct device *dev) { - return resume_common(dev, PM_EVENT_RESUME); + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + return _resume_common(dev, PM_EVENT_RESUME, hcd); +} + +static int hcd_plat_pci_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _resume_common(dev, PM_EVENT_RESUME, hcd); } static int hcd_pci_restore(struct device *dev) { - return resume_common(dev, PM_EVENT_RESTORE); + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); + + return _resume_common(dev, PM_EVENT_RESTORE, hcd); +} + +static int hcd_plat_pci_restore(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _resume_common(dev, PM_EVENT_RESTORE, hcd); } #else @@ -548,35 +605,61 @@ static int hcd_pci_restore(struct device *dev) #define hcd_pci_resume NULL #define hcd_pci_restore NULL +#define hcd_plat_pci_suspend NULL +#define hcd_plat_pci_suspend_noirq NULL +#define hcd_plat_pci_resume_noirq NULL +#define hcd_plat_pci_resume NULL +#define hcd_plat_pci_restore NULL + #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_RUNTIME static int hcd_pci_runtime_suspend(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); int retval; - retval = suspend_common(dev, true); + retval = _suspend_common(dev, true, hcd); if (retval == 0) powermac_set_asic(to_pci_dev(dev), 0); dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval); return retval; } +static int hcd_plat_pci_runtime_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _suspend_common(dev, true, hcd); +} + static int hcd_pci_runtime_resume(struct device *dev) { + struct pci_dev *pci_dev = to_pci_dev(dev); + struct usb_hcd *hcd = pci_get_drvdata(pci_dev); int retval; powermac_set_asic(to_pci_dev(dev), 1); - retval = resume_common(dev, PM_EVENT_AUTO_RESUME); + retval = _resume_common(dev, PM_EVENT_AUTO_RESUME, hcd); dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval); return retval; } +static int hcd_plat_pci_runtime_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev->parent); + + return _resume_common(dev, PM_EVENT_AUTO_RESUME, hcd); +} + #else #define hcd_pci_runtime_suspend NULL #define hcd_pci_runtime_resume NULL +#define hcd_plat_pci_runtime_suspend NULL +#define hcd_plat_pci_runtime_resume NULL #endif /* CONFIG_PM_RUNTIME */ @@ -598,4 +681,22 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = { }; EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); +const struct dev_pm_ops usb_hcd_plat_pci_pm_ops = { + .suspend = hcd_plat_pci_suspend, + .suspend_noirq = hcd_plat_pci_suspend_noirq, + .resume_noirq = hcd_pci_resume_noirq, + .resume = hcd_plat_pci_resume, + .freeze = check_plat_pci_root_hub_suspended, + .freeze_noirq = check_plat_pci_root_hub_suspended, + .thaw_noirq = NULL, + .thaw = NULL, + .poweroff = hcd_plat_pci_suspend, + .poweroff_noirq = hcd_plat_pci_suspend_noirq, + .restore_noirq = hcd_pci_resume_noirq, + .restore = hcd_plat_pci_restore, + .runtime_suspend = hcd_plat_pci_runtime_suspend, + .runtime_resume = hcd_plat_pci_runtime_resume, +}; +EXPORT_SYMBOL_GPL(usb_hcd_plat_pci_pm_ops); + #endif /* CONFIG_PM */ diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 0097136..61181a4 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -396,6 +396,7 @@ extern void usb_hcd_pci_shutdown(struct pci_dev *dev); #ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops usb_hcd_pci_pm_ops; +extern const struct dev_pm_ops usb_hcd_plat_pci_pm_ops; #endif #endif /* CONFIG_PCI */ -- 1.7.4.4 -- 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