All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anton Vorontsov <avorontsov@ru.mvista.com>
To: Grant Likely <grant.likely@secretlab.ca>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: linuxppc-dev@ozlabs.org, linux-pm@lists.linux-foundation.org,
	David Miller <davem@davemloft.net>
Subject: [PATCH] of/platform: Implement support for dev_pm_ops
Date: Mon, 12 Oct 2009 19:50:41 +0400	[thread overview]
Message-ID: <20091012155041.GA1071@oksana.dev.rtsoft.ru> (raw)

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@ru.mvista.com>
---
 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

             reply	other threads:[~2009-10-12 15:50 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-12 15:50 Anton Vorontsov [this message]
2009-10-12 22:09 ` [PATCH] of/platform: Implement support for dev_pm_ops Grant Likely
2009-10-12 22:09 ` Grant Likely
2009-10-12 22:44   ` Anton Vorontsov
2009-10-14  4:55     ` Benjamin Herrenschmidt
2009-10-14  4:55     ` Benjamin Herrenschmidt
2009-10-12 22:44   ` Anton Vorontsov
  -- strict thread matches above, loose matches on Subject: below --
2009-10-12 15:50 Anton Vorontsov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091012155041.GA1071@oksana.dev.rtsoft.ru \
    --to=avorontsov@ru.mvista.com \
    --cc=benh@kernel.crashing.org \
    --cc=davem@davemloft.net \
    --cc=grant.likely@secretlab.ca \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=linuxppc-dev@ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.