diff mbox

[RFC] Power domains for platform bus type

Message ID 201101300107.19389.rjw@sisk.pl (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Rafael Wysocki Jan. 30, 2011, 12:07 a.m. UTC
None
diff mbox

Patch

Index: linux-2.6/include/linux/platform_device.h
===================================================================
--- linux-2.6.orig/include/linux/platform_device.h
+++ linux-2.6/include/linux/platform_device.h
@@ -14,6 +14,11 @@ 
 #include <linux/device.h>
 #include <linux/mod_devicetable.h>
 
+struct power_domain {
+	struct dev_pm_ops *pre_ops;
+	struct dev_pm_ops *post_ops;
+};
+
 struct platform_device {
 	const char	* name;
 	int		id;
@@ -22,6 +27,7 @@  struct platform_device {
 	struct resource	* resource;
 
 	const struct platform_device_id	*id_entry;
+	const struct power_domain *domain;
 
 	/* arch specific additions */
 	struct pdev_archdata	archdata;
Index: linux-2.6/drivers/base/platform.c
===================================================================
--- linux-2.6.orig/drivers/base/platform.c
+++ linux-2.6/drivers/base/platform.c
@@ -697,68 +697,98 @@  static void platform_pm_complete(struct
 int __weak platform_pm_suspend(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->suspend)
+		pd->pre_ops->suspend(dev);
 
-	if (drv->pm) {
-		if (drv->pm->suspend)
-			ret = drv->pm->suspend(dev);
-	} else {
-		ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->suspend)
+				ret = drv->pm->suspend(dev);
+		} else {
+			ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->suspend)
+		pd->post_ops->suspend(dev);
+
 	return ret;
 }
 
 int __weak platform_pm_suspend_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->suspend_noirq)
+		pd->pre_ops->suspend_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->suspend_noirq)
-			ret = drv->pm->suspend_noirq(dev);
+	if (drv && drv->pm && drv->pm->suspend_noirq) {
+		ret = drv->pm->suspend_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->suspend_noirq)
+		pd->post_ops->suspend_noirq(dev);
+
 	return ret;
 }
 
 int __weak platform_pm_resume(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->resume)
+		pd->pre_ops->resume(dev);
 
-	if (drv->pm) {
-		if (drv->pm->resume)
-			ret = drv->pm->resume(dev);
-	} else {
-		ret = platform_legacy_resume(dev);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->resume)
+				ret = drv->pm->resume(dev);
+		} else {
+			ret = platform_legacy_resume(dev);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->resume)
+		pd->post_ops->resume(dev);
+
 	return ret;
 }
 
 int __weak platform_pm_resume_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->resume_noirq)
+		pd->pre_ops->resume_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->resume_noirq)
-			ret = drv->pm->resume_noirq(dev);
+	if (drv && drv->pm && drv->pm->resume_noirq) {
+		ret = drv->pm->resume_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->resume_noirq)
+		pd->post_ops->resume_noirq(dev);
+
 	return ret;
 }
 
@@ -776,136 +806,196 @@  int __weak platform_pm_resume_noirq(stru
 static int platform_pm_freeze(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->freeze)
+		pd->pre_ops->freeze(dev);
 
-	if (drv->pm) {
-		if (drv->pm->freeze)
-			ret = drv->pm->freeze(dev);
-	} else {
-		ret = platform_legacy_suspend(dev, PMSG_FREEZE);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->freeze)
+				ret = drv->pm->freeze(dev);
+		} else {
+			ret = platform_legacy_suspend(dev, PMSG_FREEZE);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->freeze)
+		pd->post_ops->freeze(dev);
+
 	return ret;
 }
 
 static int platform_pm_freeze_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->freeze_noirq)
+		pd->pre_ops->freeze_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->freeze_noirq)
-			ret = drv->pm->freeze_noirq(dev);
+	if (drv && drv->pm && drv->pm->freeze_noirq) {
+		ret = drv->pm->freeze_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->freeze_noirq)
+		pd->post_ops->freeze_noirq(dev);
+
 	return ret;
 }
 
 static int platform_pm_thaw(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->thaw)
+		pd->pre_ops->thaw(dev);
 
-	if (drv->pm) {
-		if (drv->pm->thaw)
-			ret = drv->pm->thaw(dev);
-	} else {
-		ret = platform_legacy_resume(dev);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->thaw)
+				ret = drv->pm->thaw(dev);
+		} else {
+			ret = platform_legacy_resume(dev);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->thaw)
+		pd->post_ops->thaw(dev);
+
 	return ret;
 }
 
 static int platform_pm_thaw_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->thaw_noirq)
+		pd->pre_ops->thaw_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->thaw_noirq)
-			ret = drv->pm->thaw_noirq(dev);
+	if (drv && drv->pm && drv->pm->thaw_noirq) {
+		ret = drv->pm->thaw_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->thaw_noirq)
+		pd->post_ops->thaw_noirq(dev);
+
 	return ret;
 }
 
 static int platform_pm_poweroff(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->poweroff)
+		pd->pre_ops->poweroff(dev);
 
-	if (drv->pm) {
-		if (drv->pm->poweroff)
-			ret = drv->pm->poweroff(dev);
-	} else {
-		ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->poweroff)
+				ret = drv->pm->poweroff(dev);
+		} else {
+			ret = platform_legacy_suspend(dev, PMSG_HIBERNATE);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->poweroff)
+		pd->post_ops->poweroff(dev);
+
 	return ret;
 }
 
 static int platform_pm_poweroff_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->poweroff_noirq)
+		pd->pre_ops->poweroff_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->poweroff_noirq)
-			ret = drv->pm->poweroff_noirq(dev);
+	if (drv && drv->pm && drv->pm->poweroff_noirq) {
+		ret = drv->pm->poweroff_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->poweroff_noirq)
+		pd->post_ops->poweroff_noirq(dev);
+
 	return ret;
 }
 
 static int platform_pm_restore(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->restore)
+		pd->pre_ops->restore(dev);
 
-	if (drv->pm) {
-		if (drv->pm->restore)
-			ret = drv->pm->restore(dev);
-	} else {
-		ret = platform_legacy_resume(dev);
+	if (drv) {
+		if (drv->pm) {
+			if (drv->pm->restore)
+				ret = drv->pm->restore(dev);
+		} else {
+			ret = platform_legacy_resume(dev);
+		}
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->restore)
+		pd->post_ops->restore(dev);
+
 	return ret;
 }
 
 static int platform_pm_restore_noirq(struct device *dev)
 {
 	struct device_driver *drv = dev->driver;
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
 	int ret = 0;
 
-	if (!drv)
-		return 0;
+	if (pd && pd->pre_ops && pd->pre_ops->restore_noirq)
+		pd->pre_ops->restore_noirq(dev);
 
-	if (drv->pm) {
-		if (drv->pm->restore_noirq)
-			ret = drv->pm->restore_noirq(dev);
+	if (drv && drv->pm && drv->pm->restore_noirq) {
+		ret = drv->pm->restore_noirq(dev);
+		if (ret)
+			return ret;
 	}
 
+	if (pd && pd->post_ops && pd->post_ops->restore_noirq)
+		pd->post_ops->restore_noirq(dev);
+
 	return ret;
 }
 
@@ -926,12 +1016,40 @@  static int platform_pm_restore_noirq(str
 
 int __weak platform_pm_runtime_suspend(struct device *dev)
 {
-	return pm_generic_runtime_suspend(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
+	int ret;
+
+	if (pd && pd->pre_ops && pd->pre_ops->runtime_suspend)
+		pd->pre_ops->runtime_suspend(dev);
+
+	ret = pm_generic_runtime_suspend(dev);
+	if (ret)
+		return ret;
+
+	if (pd && pd->post_ops && pd->post_ops->runtime_suspend)
+		pd->post_ops->runtime_suspend(dev);
+
+	return 0;
 };
 
 int __weak platform_pm_runtime_resume(struct device *dev)
 {
-	return pm_generic_runtime_resume(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct power_domain *pd = pdev->domain;
+	int ret;
+
+	if (pd && pd->pre_ops && pd->pre_ops->runtime_resume)
+		pd->pre_ops->runtime_resume(dev);
+
+	ret = pm_generic_runtime_resume(dev);
+	if (ret)
+		return ret;
+
+	if (pd && pd->post_ops && pd->post_ops->runtime_resume)
+		pd->post_ops->runtime_resume(dev);
+
+	return 0;
 };
 
 int __weak platform_pm_runtime_idle(struct device *dev)