[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