[PATCH] of/platform: Implement support for dev_pm_ops
Grant Likely
grant.likely at secretlab.ca
Tue Oct 13 09:09:53 EST 2009
On Mon, Oct 12, 2009 at 8:50 AM, Anton Vorontsov
<avorontsov at ru.mvista.com> wrote:
> Linux power management subsystem supports vast amount of new PM
> callbacks that are crucial for proper suspend and hibernation support
> in drivers.
>
> This patch implements support for dev_pm_ops, preserving support
> for legacy callbacks.
>
> Signed-off-by: Anton Vorontsov <avorontsov at ru.mvista.com>
Hmmm... I'm not very familiar with the PM callbacks, but change
doesn't look right to me. In particular, a lot of these new hooks
don't do anything remotely of_platform bus specific. For example,
of_platform_pm_prepare() checks if there is drv, drv->pm, and
drv->pm->prepare. If all are true, then it calls drv->pm->prepare().
I see that the platform bus platform_pm_prepare() function is
absolutely identical. I haven't looked, but I wouldn't be surprised
if other busses do the same.
I think these simple pm ops should be made library functions that
platform, of_platform and other simple busses can just populate their
pm ops structure with.
g.
> ---
> drivers/of/platform.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++---
> 1 files changed, 290 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/of/platform.c b/drivers/of/platform.c
> index 298de0f..d58ade1 100644
> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c
> @@ -65,47 +65,322 @@ static int of_platform_device_remove(struct device *dev)
> return 0;
> }
>
> -static int of_platform_device_suspend(struct device *dev, pm_message_t state)
> +static void of_platform_device_shutdown(struct device *dev)
> {
> struct of_device *of_dev = to_of_device(dev);
> struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
> - int error = 0;
>
> - if (dev->driver && drv->suspend)
> - error = drv->suspend(of_dev, state);
> - return error;
> + if (dev->driver && drv->shutdown)
> + drv->shutdown(of_dev);
> }
>
> -static int of_platform_device_resume(struct device * dev)
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int of_platform_legacy_suspend(struct device *dev, pm_message_t mesg)
> {
> struct of_device *of_dev = to_of_device(dev);
> struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
> - int error = 0;
> + int ret = 0;
>
> - if (dev->driver && drv->resume)
> - error = drv->resume(of_dev);
> - return error;
> + if (dev->driver && drv->suspend)
> + ret = drv->suspend(of_dev, mesg);
> + return ret;
> }
>
> -static void of_platform_device_shutdown(struct device *dev)
> +static int of_platform_legacy_resume(struct device *dev)
> {
> struct of_device *of_dev = to_of_device(dev);
> struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
> + int ret = 0;
>
> - if (dev->driver && drv->shutdown)
> - drv->shutdown(of_dev);
> + if (dev->driver && drv->resume)
> + ret = drv->resume(of_dev);
> + return ret;
> +}
> +
> +static int of_platform_pm_prepare(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (drv && drv->pm && drv->pm->prepare)
> + ret = drv->pm->prepare(dev);
> +
> + return ret;
> +}
> +
> +static void of_platform_pm_complete(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> +
> + if (drv && drv->pm && drv->pm->complete)
> + drv->pm->complete(dev);
> +}
> +
> +#ifdef CONFIG_SUSPEND
> +
> +static int of_platform_pm_suspend(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->suspend)
> + ret = drv->pm->suspend(dev);
> + } else {
> + ret = of_platform_legacy_suspend(dev, PMSG_SUSPEND);
> + }
> +
> + return ret;
> }
>
> +static int of_platform_pm_suspend_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->suspend_noirq)
> + ret = drv->pm->suspend_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_resume(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->resume)
> + ret = drv->pm->resume(dev);
> + } else {
> + ret = of_platform_legacy_resume(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_resume_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->resume_noirq)
> + ret = drv->pm->resume_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +#else /* !CONFIG_SUSPEND */
> +
> +#define of_platform_pm_suspend NULL
> +#define of_platform_pm_resume NULL
> +#define of_platform_pm_suspend_noirq NULL
> +#define of_platform_pm_resume_noirq NULL
> +
> +#endif /* !CONFIG_SUSPEND */
> +
> +#ifdef CONFIG_HIBERNATION
> +
> +static int of_platform_pm_freeze(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->freeze)
> + ret = drv->pm->freeze(dev);
> + } else {
> + ret = of_platform_legacy_suspend(dev, PMSG_FREEZE);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_freeze_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->freeze_noirq)
> + ret = drv->pm->freeze_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_thaw(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->thaw)
> + ret = drv->pm->thaw(dev);
> + } else {
> + ret = of_platform_legacy_resume(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_thaw_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->thaw_noirq)
> + ret = drv->pm->thaw_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_poweroff(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->poweroff)
> + ret = drv->pm->poweroff(dev);
> + } else {
> + ret = of_platform_legacy_suspend(dev, PMSG_HIBERNATE);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_poweroff_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->poweroff_noirq)
> + ret = drv->pm->poweroff_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_restore(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->restore)
> + ret = drv->pm->restore(dev);
> + } else {
> + ret = of_platform_legacy_resume(dev);
> + }
> +
> + return ret;
> +}
> +
> +static int of_platform_pm_restore_noirq(struct device *dev)
> +{
> + struct device_driver *drv = dev->driver;
> + int ret = 0;
> +
> + if (!drv)
> + return 0;
> +
> + if (drv->pm) {
> + if (drv->pm->restore_noirq)
> + ret = drv->pm->restore_noirq(dev);
> + }
> +
> + return ret;
> +}
> +
> +#else /* !CONFIG_HIBERNATION */
> +
> +#define of_platform_pm_freeze NULL
> +#define of_platform_pm_thaw NULL
> +#define of_platform_pm_poweroff NULL
> +#define of_platform_pm_restore NULL
> +#define of_platform_pm_freeze_noirq NULL
> +#define of_platform_pm_thaw_noirq NULL
> +#define of_platform_pm_poweroff_noirq NULL
> +#define of_platform_pm_restore_noirq NULL
> +
> +#endif /* !CONFIG_HIBERNATION */
> +
> +static struct dev_pm_ops of_platform_dev_pm_ops = {
> + .prepare = of_platform_pm_prepare,
> + .complete = of_platform_pm_complete,
> + .suspend = of_platform_pm_suspend,
> + .resume = of_platform_pm_resume,
> + .freeze = of_platform_pm_freeze,
> + .thaw = of_platform_pm_thaw,
> + .poweroff = of_platform_pm_poweroff,
> + .restore = of_platform_pm_restore,
> + .suspend_noirq = of_platform_pm_suspend_noirq,
> + .resume_noirq = of_platform_pm_resume_noirq,
> + .freeze_noirq = of_platform_pm_freeze_noirq,
> + .thaw_noirq = of_platform_pm_thaw_noirq,
> + .poweroff_noirq = of_platform_pm_poweroff_noirq,
> + .restore_noirq = of_platform_pm_restore_noirq,
> +};
> +
> +#define OF_PLATFORM_PM_OPS_PTR (&of_platform_dev_pm_ops)
> +
> +#else /* !CONFIG_PM_SLEEP */
> +
> +#define OF_PLATFORM_PM_OPS_PTR NULL
> +
> +#endif /* !CONFIG_PM_SLEEP */
> +
> int of_bus_type_init(struct bus_type *bus, const char *name)
> {
> bus->name = name;
> bus->match = of_platform_bus_match;
> bus->probe = of_platform_device_probe;
> bus->remove = of_platform_device_remove;
> - bus->suspend = of_platform_device_suspend;
> - bus->resume = of_platform_device_resume;
> bus->shutdown = of_platform_device_shutdown;
> bus->dev_attrs = of_platform_device_attrs;
> + bus->pm = OF_PLATFORM_PM_OPS_PTR;
> return bus_register(bus);
> }
>
> --
> 1.6.3.3
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
More information about the Linuxppc-dev
mailing list