[linux-pm] [PATCHv2] amba: support pm ops

Rafael J. Wysocki rjw at sisk.pl
Mon Feb 21 15:26:10 EST 2011


On Monday, February 21, 2011, Rabin Vincent wrote:
> Support pm_ops in the AMBA bus, required to allow drivers to use runtime pm.
> The implementation of AMBA bus pm ops is based on the platform bus
> implementation.
> 
> Signed-off-by: Rabin Vincent <rabin.vincent at stericsson.com>

Acked-by: Rafael J. Wysocki <rjw at sisk.pl>

(although I'd probably avoid creating an empty struct dev_pm_ops object
if both CONFIG_HIBERNATION and CONFIG_SUSPEND are unset).

> ---
> v2: Base the implementation on the platform bus instead of the generic ops,
>     implementation all the functions platform does and with the same behaviour.
>     Also continue to support the legacy operations so that this patch doesn't
>     need to modify all the drivers and thus becomes easier to merge.
> 
>  drivers/amba/bus.c       |  329 ++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/amba/bus.h |    2 +
>  2 files changed, 308 insertions(+), 23 deletions(-)
> 
> diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
> index ca96b0a..7bc7762 100644
> --- a/drivers/amba/bus.c
> +++ b/drivers/amba/bus.c
> @@ -13,12 +13,12 @@
>  #include <linux/string.h>
>  #include <linux/slab.h>
>  #include <linux/io.h>
> +#include <linux/pm.h>
>  #include <linux/amba/bus.h>
>  
>  #include <asm/irq.h>
>  #include <asm/sizes.h>
>  
> -#define to_amba_device(d)	container_of(d, struct amba_device, dev)
>  #define to_amba_driver(d)	container_of(d, struct amba_driver, drv)
>  
>  static struct amba_id *
> @@ -57,26 +57,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
>  #define amba_uevent NULL
>  #endif
>  
> -static int amba_suspend(struct device *dev, pm_message_t state)
> -{
> -	struct amba_driver *drv = to_amba_driver(dev->driver);
> -	int ret = 0;
> -
> -	if (dev->driver && drv->suspend)
> -		ret = drv->suspend(to_amba_device(dev), state);
> -	return ret;
> -}
> -
> -static int amba_resume(struct device *dev)
> -{
> -	struct amba_driver *drv = to_amba_driver(dev->driver);
> -	int ret = 0;
> -
> -	if (dev->driver && drv->resume)
> -		ret = drv->resume(to_amba_device(dev));
> -	return ret;
> -}
> -
>  #define amba_attr_func(name,fmt,arg...)					\
>  static ssize_t name##_show(struct device *_dev,				\
>  			   struct device_attribute *attr, char *buf)	\
> @@ -102,6 +82,310 @@ static struct device_attribute amba_dev_attrs[] = {
>  	__ATTR_NULL,
>  };
>  
> +#ifdef CONFIG_PM_SLEEP
> +
> +static int amba_legacy_suspend(struct device *dev, pm_message_t mesg)
> +{
> +	struct amba_driver *adrv = to_amba_driver(dev->driver);
> +	struct amba_device *adev = to_amba_device(dev);
> +	int ret = 0;
> +
> +	if (dev->driver && adrv->suspend)
> +		ret = adrv->suspend(adev, mesg);
> +
> +	return ret;
> +}
> +
> +static int amba_legacy_resume(struct device *dev)
> +{
> +	struct amba_driver *adrv = to_amba_driver(dev->driver);
> +	struct amba_device *adev = to_amba_device(dev);
> +	int ret = 0;
> +
> +	if (dev->driver && adrv->resume)
> +		ret = adrv->resume(adev);
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_pm_complete(struct device *dev)
> +{
> +	struct device_driver *drv = dev->driver;
> +
> +	if (drv && drv->pm && drv->pm->complete)
> +		drv->pm->complete(dev);
> +}
> +
> +#else /* !CONFIG_PM_SLEEP */
> +
> +#define amba_pm_prepare		NULL
> +#define amba_pm_complete		NULL
> +
> +#endif /* !CONFIG_PM_SLEEP */
> +
> +#ifdef CONFIG_SUSPEND
> +
> +static int amba_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 = amba_legacy_suspend(dev, PMSG_SUSPEND);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_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 = amba_legacy_resume(dev);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_pm_suspend		NULL
> +#define amba_pm_resume		NULL
> +#define amba_pm_suspend_noirq	NULL
> +#define amba_pm_resume_noirq	NULL
> +
> +#endif /* !CONFIG_SUSPEND */
> +
> +#ifdef CONFIG_HIBERNATION
> +
> +static int amba_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 = amba_legacy_suspend(dev, PMSG_FREEZE);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_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 = amba_legacy_resume(dev);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_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 = amba_legacy_suspend(dev, PMSG_HIBERNATE);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_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 = amba_legacy_resume(dev);
> +	}
> +
> +	return ret;
> +}
> +
> +static int amba_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 amba_pm_freeze		NULL
> +#define amba_pm_thaw		NULL
> +#define amba_pm_poweroff		NULL
> +#define amba_pm_restore		NULL
> +#define amba_pm_freeze_noirq	NULL
> +#define amba_pm_thaw_noirq		NULL
> +#define amba_pm_poweroff_noirq	NULL
> +#define amba_pm_restore_noirq	NULL
> +
> +#endif /* !CONFIG_HIBERNATION */
> +
> +static const struct dev_pm_ops amba_pm = {
> +	.prepare	= amba_pm_prepare,
> +	.complete	= amba_pm_complete,
> +	.suspend	= amba_pm_suspend,
> +	.resume		= amba_pm_resume,
> +	.freeze		= amba_pm_freeze,
> +	.thaw		= amba_pm_thaw,
> +	.poweroff	= amba_pm_poweroff,
> +	.restore	= amba_pm_restore,
> +	.suspend_noirq	= amba_pm_suspend_noirq,
> +	.resume_noirq	= amba_pm_resume_noirq,
> +	.freeze_noirq	= amba_pm_freeze_noirq,
> +	.thaw_noirq	= amba_pm_thaw_noirq,
> +	.poweroff_noirq	= amba_pm_poweroff_noirq,
> +	.restore_noirq	= amba_pm_restore_noirq,
> +	SET_RUNTIME_PM_OPS(
> +		pm_generic_runtime_suspend,
> +		pm_generic_runtime_resume,
> +		pm_generic_runtime_idle
> +	)
> +};
> +
>  /*
>   * Primecells are part of the Advanced Microcontroller Bus Architecture,
>   * so we call the bus "amba".
> @@ -111,8 +395,7 @@ struct bus_type amba_bustype = {
>  	.dev_attrs	= amba_dev_attrs,
>  	.match		= amba_match,
>  	.uevent		= amba_uevent,
> -	.suspend	= amba_suspend,
> -	.resume		= amba_resume,
> +	.pm		= &amba_pm,
>  };
>  
>  static int __init amba_init(void)
> diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
> index a0ccf28..1849975 100644
> --- a/include/linux/amba/bus.h
> +++ b/include/linux/amba/bus.h
> @@ -58,6 +58,8 @@ enum amba_vendor {
>  
>  extern struct bus_type amba_bustype;
>  
> +#define to_amba_device(d)	container_of(d, struct amba_device, dev)
> +
>  #define amba_get_drvdata(d)	dev_get_drvdata(&d->dev)
>  #define amba_set_drvdata(d,p)	dev_set_drvdata(&d->dev, p)
>  
> 




More information about the linux-arm-kernel mailing list