===================================================================
@@ -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;
===================================================================
@@ -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)