Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba74ec7f authored by Rabin Vincent's avatar Rabin Vincent Committed by Russell King
Browse files

ARM: 6758/1: amba: support pm ops



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.

Acked-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarRabin Vincent <rabin.vincent@stericsson.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 2d00880f
Loading
Loading
Loading
Loading
+317 −23
Original line number Original line Diff line number Diff line
@@ -13,12 +13,13 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/amba/bus.h>
#include <linux/amba/bus.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/sizes.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)
#define to_amba_driver(d)	container_of(d, struct amba_driver, drv)


static const struct amba_id *
static const struct amba_id *
@@ -57,26 +58,6 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
#define amba_uevent NULL
#define amba_uevent NULL
#endif
#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...)					\
#define amba_attr_func(name,fmt,arg...)					\
static ssize_t name##_show(struct device *_dev,				\
static ssize_t name##_show(struct device *_dev,				\
			   struct device_attribute *attr, char *buf)	\
			   struct device_attribute *attr, char *buf)	\
@@ -102,6 +83,320 @@ static struct device_attribute amba_dev_attrs[] = {
	__ATTR_NULL,
	__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 */

#ifdef CONFIG_PM

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
	)
};

#define AMBA_PM (&amba_pm)

#else /* !CONFIG_PM */

#define AMBA_PM	NULL

#endif /* !CONFIG_PM */

/*
/*
 * Primecells are part of the Advanced Microcontroller Bus Architecture,
 * Primecells are part of the Advanced Microcontroller Bus Architecture,
 * so we call the bus "amba".
 * so we call the bus "amba".
@@ -111,8 +406,7 @@ struct bus_type amba_bustype = {
	.dev_attrs	= amba_dev_attrs,
	.dev_attrs	= amba_dev_attrs,
	.match		= amba_match,
	.match		= amba_match,
	.uevent		= amba_uevent,
	.uevent		= amba_uevent,
	.suspend	= amba_suspend,
	.pm		= AMBA_PM,
	.resume		= amba_resume,
};
};


static int __init amba_init(void)
static int __init amba_init(void)
+2 −0
Original line number Original line Diff line number Diff line
@@ -58,6 +58,8 @@ enum amba_vendor {


extern struct bus_type amba_bustype;
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_get_drvdata(d)	dev_get_drvdata(&d->dev)
#define amba_set_drvdata(d,p)	dev_set_drvdata(&d->dev, p)
#define amba_set_drvdata(d,p)	dev_set_drvdata(&d->dev, p)