From: "Rafael J. Wysocki" <rjw@sisk.pl>
To: Linux PM mailing list <linux-pm@lists.linux-foundation.org>
Cc: linux-sh@vger.kernel.org, Greg KH <gregkh@suse.de>,
LKML <linux-kernel@vger.kernel.org>,
Grant Likely <grant.likely@secretlab.ca>
Subject: [PATCH 7/9] PM / Runtime: Add generic clock manipulation rountines for runtime PM
Date: Sun, 17 Apr 2011 01:42:10 +0200 [thread overview]
Message-ID: <201104170142.10723.rjw@sisk.pl> (raw)
In-Reply-To: <201104170135.19388.rjw@sisk.pl>
From: Rafael J. Wysocki <rjw@sisk.pl>
Many different platforms and subsystems may want to disable device
clocks during suspend and enable them during resume which is going to
be done in a very similar way in all those cases. For this reason,
provide generic routines for the manipulation of device clocks during
suspend and resume.
Convert the ARM shmobile platform to using the new routines.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
arch/arm/mach-shmobile/pm_runtime.c | 139 +--------------------------
drivers/base/power/Makefile | 1
drivers/base/power/clock_ops.c | 179 ++++++++++++++++++++++++++++++++++++
include/linux/pm_runtime.h | 27 +++++
kernel/power/Kconfig | 4
5 files changed, 216 insertions(+), 134 deletions(-)
Index: linux-2.6/drivers/base/power/clock_ops.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/base/power/clock_ops.c
@@ -0,0 +1,179 @@
+/*
+ * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
+ *
+ * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Jinzai Solution Inc.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#ifdef CONFIG_PM_RUNTIME
+
+struct pm_runtime_data {
+ struct clk *clk;
+ unsigned int clock_active:1;
+ unsigned int clock_enabled:1;
+};
+
+static struct pm_runtime_data *__to_prd(struct device *dev)
+{
+ return dev ? dev->power.subsys_data : NULL;
+}
+
+int pm_runtime_clock_add(struct device *dev)
+{
+ struct pm_runtime_data *prd;
+
+ prd = kzalloc(sizeof(*prd), GFP_KERNEL);
+ if (!prd) {
+ dev_err(dev, "unable to allocate memory for runtime PM\n");
+ return -ENOMEM;
+ }
+
+ dev->power.subsys_data = prd;
+ return 0;
+}
+
+void pm_runtime_clock_remove(struct device *dev)
+{
+ struct pm_runtime_data *prd = __to_prd(dev);
+
+ if (!prd)
+ return;
+
+ if (prd->clk) {
+ if (prd->clock_enabled)
+ clk_disable(prd->clk);
+
+ if (prd->clock_active)
+ clk_put(prd->clk);
+ }
+
+ kfree(prd);
+}
+
+static void pm_runtime_clock_init(struct device *dev,
+ struct pm_runtime_data *prd)
+{
+ prd->clk = clk_get(dev, NULL);
+ if (!IS_ERR(prd->clk)) {
+ prd->clock_active = true;
+ dev_info(dev, "clock managed by runtime PM\n");
+ }
+}
+
+int pm_runtime_clock_suspend(struct device *dev)
+{
+ struct pm_runtime_data *prd = __to_prd(dev);
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ if (prd) {
+ if (!prd->clk) {
+ dev_err(dev, "clock is not ready for runtime PM\n");
+ pm_runtime_clock_init(dev, prd);
+ }
+
+ if (prd->clock_active) {
+ clk_disable(prd->clk);
+ prd->clock_enabled = false;
+ }
+ }
+
+ return 0;
+}
+
+int pm_runtime_clock_resume(struct device *dev)
+{
+ struct pm_runtime_data *prd = __to_prd(dev);
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ if (prd) {
+ if (!prd->clk)
+ pm_runtime_clock_init(dev, prd);
+
+ if (prd->clock_active) {
+ clk_enable(prd->clk);
+ prd->clock_enabled = true;
+ }
+ }
+
+ return 0;
+}
+
+static int pm_runtime_clock_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct pm_domain_notifier_block *pdnb;
+ struct device *dev = data;
+
+ dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+ pdnb = container_of(nb, struct pm_domain_notifier_block, nb);
+
+ switch (action) {
+ case BUS_NOTIFY_BIND_DRIVER:
+ dev->pwr_domain = pdnb->pwr_domain;
+ pm_runtime_clock_add(dev);
+ break;
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ dev->pwr_domain = NULL;
+ pm_runtime_clock_remove(dev);
+ break;
+ }
+
+ return 0;
+}
+
+#else /* !CONFIG_PM_RUNTIME */
+
+static int pm_runtime_clock_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct clk *clk;
+
+ dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+ switch (action) {
+ case BUS_NOTIFY_BIND_DRIVER:
+ clk = clk_get(dev, NULL);
+ if (!IS_ERR(clk)) {
+ clk_enable(clk);
+ clk_put(clk);
+ dev_info(dev, "runtime PM disabled, clock forced on\n");
+ }
+ break;
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ clk = clk_get(dev, NULL);
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ clk_put(clk);
+ dev_info(dev, "runtime PM disabled, clock forced off\n");
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+void pm_runtim_clock_add_notifier(struct bus_type *bus,
+ struct pm_domain_notifier_block *pdnb)
+{
+ if (!bus || !pdnb)
+ return;
+
+ pdnb->nb.notifier_call = pm_runtime_clock_notify;
+ bus_register_notifier(bus, &pdnb->nb);
+}
Index: linux-2.6/kernel/power/Kconfig
===================================================================
--- linux-2.6.orig/kernel/power/Kconfig
+++ linux-2.6/kernel/power/Kconfig
@@ -229,3 +229,7 @@ config PM_OPP
representing individual voltage domains and provides SOC
implementations a ready to use framework to manage OPPs.
For more information, read <file:Documentation/power/opp.txt>
+
+config PM_RUNTIME_CLK
+ def_bool y
+ depends on PM_RUNTIME && HAVE_CLK
Index: linux-2.6/drivers/base/power/Makefile
===================================================================
--- linux-2.6.orig/drivers/base/power/Makefile
+++ linux-2.6/drivers/base/power/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
+obj-$(CONFIG_HAVE_CLK) += clock_ops.o
ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG
Index: linux-2.6/include/linux/pm_runtime.h
===================================================================
--- linux-2.6.orig/include/linux/pm_runtime.h
+++ linux-2.6/include/linux/pm_runtime.h
@@ -245,4 +245,31 @@ static inline void pm_runtime_dont_use_a
__pm_runtime_use_autosuspend(dev, false);
}
+struct pm_domain_notifier_block {
+ struct notifier_block nb;
+ struct dev_power_domain *pwr_domain;
+};
+
+#ifdef CONFIG_PM_RUNTIME_CLK
+extern int pm_runtime_clock_add(struct device *dev);
+extern void pm_runtime_clock_remove(struct device *dev);
+extern int pm_runtime_clock_suspend(struct device *dev);
+extern int pm_runtime_clock_resume(struct device *dev);
+#else
+static inline pm_runtime_clock_add(struct device *dev) { return -EINVAL; }
+static inline pm_runtime_clock_remove(struct device *dev) {}
+#define pm_runtime_clock_suspend NULL
+#define pm_runtime_clock_resume NULL
+#endif
+
+#ifdef CONFIG_HAVE_CLK
+extern void pm_runtim_clock_add_notifier(struct bus_type *bus,
+ struct pm_domain_notifier_block *pdnb);
+#else
+static inline void pm_runtim_clock_add_notifier(struct bus_type *bus,
+ struct pm_domain_notifier_block *pdnb);
+{
+}
+#endif
+
#endif
Index: linux-2.6/arch/arm/mach-shmobile/pm_runtime.c
===================================================================
--- linux-2.6.orig/arch/arm/mach-shmobile/pm_runtime.c
+++ linux-2.6/arch/arm/mach-shmobile/pm_runtime.c
@@ -21,70 +21,6 @@
#include <linux/slab.h>
#ifdef CONFIG_PM_RUNTIME
-#define BIT_ONCE 0
-#define BIT_ACTIVE 1
-#define BIT_CLK_ENABLED 2
-
-struct pm_runtime_data {
- unsigned long flags;
- struct clk *clk;
-};
-
-static struct pm_runtime_data *__to_prd(struct device *dev)
-{
- return dev ? dev->power.subsys_data : NULL;
-}
-
-static void platform_pm_runtime_init(struct device *dev,
- struct pm_runtime_data *prd)
-{
- if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
- prd->clk = clk_get(dev, NULL);
- if (!IS_ERR(prd->clk)) {
- set_bit(BIT_ACTIVE, &prd->flags);
- dev_info(dev, "clocks managed by runtime pm\n");
- }
- }
-}
-
-static void platform_pm_runtime_bug(struct device *dev,
- struct pm_runtime_data *prd)
-{
- if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
- dev_err(dev, "runtime pm suspend before resume\n");
-}
-
-static int default_platform_runtime_suspend(struct device *dev)
-{
- struct pm_runtime_data *prd = __to_prd(dev);
-
- dev_dbg(dev, "%s()\n", __func__);
-
- platform_pm_runtime_bug(dev, prd);
-
- if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
- clk_disable(prd->clk);
- clear_bit(BIT_CLK_ENABLED, &prd->flags);
- }
-
- return 0;
-}
-
-static int default_platform_runtime_resume(struct device *dev)
-{
- struct pm_runtime_data *prd = __to_prd(dev);
-
- dev_dbg(dev, "%s()\n", __func__);
-
- platform_pm_runtime_init(dev, prd);
-
- if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
- clk_enable(prd->clk);
- set_bit(BIT_CLK_ENABLED, &prd->flags);
- }
-
- return 0;
-}
static int default_platform_runtime_idle(struct device *dev)
{
@@ -95,86 +31,21 @@ static int default_platform_runtime_idle
static struct dev_power_domain default_power_domain = {
.ops = {
USE_PLATFORM_PM_SLEEP_OPS,
- .runtime_suspend = default_platform_runtime_suspend,
- .runtime_resume = default_platform_runtime_resume,
+ .runtime_suspend = pm_runtime_clock_suspend,
+ .runtime_resume = pm_runtime_clock_resume,
.runtime_idle = default_platform_runtime_idle,
},
};
-static int platform_bus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct pm_runtime_data *prd;
-
- dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
-
- switch (action) {
- case BUS_NOTIFY_BIND_DRIVER:
- prd = kzalloc(sizeof(*prd), GFP_KERNEL);
- if (prd) {
- dev->power.subsys_data = prd;
- dev->pwr_domain = &default_power_domain;
- } else {
- dev_err(dev, "unable to alloc memory for runtime pm\n");
- }
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- prd = __to_prd(dev);
- if (prd) {
- if (test_bit(BIT_CLK_ENABLED, &prd->flags))
- clk_disable(prd->clk);
-
- if (test_bit(BIT_ACTIVE, &prd->flags))
- clk_put(prd->clk);
- }
- break;
- }
-
- return 0;
-}
-
-#else /* CONFIG_PM_RUNTIME */
-
-static int platform_bus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct clk *clk;
-
- dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
-
- switch (action) {
- case BUS_NOTIFY_BIND_DRIVER:
- clk = clk_get(dev, NULL);
- if (!IS_ERR(clk)) {
- clk_enable(clk);
- clk_put(clk);
- dev_info(dev, "runtime pm disabled, clock forced on\n");
- }
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- clk = clk_get(dev, NULL);
- if (!IS_ERR(clk)) {
- clk_disable(clk);
- clk_put(clk);
- dev_info(dev, "runtime pm disabled, clock forced off\n");
- }
- break;
- }
-
- return 0;
-}
-
#endif /* CONFIG_PM_RUNTIME */
-static struct notifier_block platform_bus_notifier = {
- .notifier_call = platform_bus_notify
+static struct pm_domain_notifier_block platform_bus_notifier = {
+ .pwr_domain = &default_power_domain,
};
static int __init sh_pm_runtime_init(void)
{
- bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
+ pm_runtim_clock_add_notifier(&platform_bus_type, &platform_bus_notifier);
return 0;
}
core_initcall(sh_pm_runtime_init);
next prev parent reply other threads:[~2011-04-16 23:42 UTC|newest]
Thread overview: 59+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <201104130205.26988.rjw@sisk.pl>
2011-04-13 14:17 ` [RFC][PATCH] PM: Make power domain callbacks take precedence over subsystem ones Alan Stern
[not found] ` <Pine.LNX.4.44L0.1104130954270.2005-100000@iolanthe.rowland.org>
2011-04-13 16:15 ` Grant Likely
[not found] ` <BANLkTiknpAkUQMaq3WZSTHy2cs-vXkv08Q@mail.gmail.com>
2011-04-14 23:12 ` Rafael J. Wysocki
[not found] ` <201104150112.24722.rjw@sisk.pl>
2011-04-15 14:38 ` Grant Likely
2011-04-15 14:39 ` Alan Stern
2011-04-14 18:20 ` Magnus Damm
[not found] ` <BANLkTimQ6kX41-53Dw2RqEVyYzbT2qbz9Q@mail.gmail.com>
2011-04-14 22:45 ` Rafael J. Wysocki
2011-04-14 23:16 ` [RFC][PATCH 0/2] Remove __weak definitions of platform PM callbacks Rafael J. Wysocki
[not found] ` <201104150116.01634.rjw@sisk.pl>
2011-04-14 23:18 ` [RFC][PATCH 1/2] shmobile: Use power domains for platform runtime PM Rafael J. Wysocki
2011-04-14 23:19 ` [RFC][PATCH 2/2] PM / Platform: Use generic runtime PM callbacks directly Rafael J. Wysocki
2011-04-16 17:17 ` [RFC][PATCH] PM: Make power domain callbacks take precedence over subsystem ones Kevin Hilman
2011-04-16 23:35 ` [PATCH 0/9] PM: Rework shmobile and OMAP runtime PM using power domains Rafael J. Wysocki
[not found] ` <201104170135.19388.rjw@sisk.pl>
2011-04-16 23:36 ` [PATCH 1/9] PM: Make power domain callbacks take precedence over subsystem ones Rafael J. Wysocki
2011-04-16 23:37 ` [PATCH 2/9] PM: Export platform bus type's default PM callbacks Rafael J. Wysocki
2011-04-16 23:38 ` [PATCH 3/9] shmobile: Use power domains for platform runtime PM Rafael J. Wysocki
2011-04-16 23:38 ` [PATCH 4/9] PM / Platform: Use generic runtime PM callbacks directly Rafael J. Wysocki
2011-04-16 23:39 ` [PATCH 5/9] OMAP2+ / PM: Move runtime PM implementation to use power domains Rafael J. Wysocki
2011-04-16 23:40 ` [PATCH 6/9] PM / Runtime: Add subsystem data field to struct dev_pm_info Rafael J. Wysocki
2011-04-16 23:42 ` Rafael J. Wysocki [this message]
2011-04-18 19:59 ` [Update][PATCH 7/9] PM / Runtime: Add generic clock manipulation rountines for runtime PM Rafael J. Wysocki
[not found] ` <201104182159.54316.rjw@sisk.pl>
2011-04-19 10:18 ` Magnus Damm
[not found] ` <BANLkTimZpXAH7uGTDmYJSJJWgX=H5md0JQ@mail.gmail.com>
2011-04-19 21:42 ` Rafael J. Wysocki
[not found] ` <201104182157.28373.rjw@sisk.pl>
[not found] ` <201104192342.26670.rjw@sisk.pl>
2011-04-19 21:59 ` Paul Mundt
[not found] ` <20110419215944.GA10031@linux-sh.org>
2011-04-19 22:10 ` Rafael J. Wysocki
[not found] ` <201104200010.50656.rjw@sisk.pl>
2011-04-19 22:20 ` Paul Mundt
2011-04-19 22:50 ` Rafael J. Wysocki
2011-04-19 10:58 ` [PATCH " Mark Brown
[not found] ` <20110419105836.GG9462@sirena.org.uk>
2011-04-19 21:35 ` Rafael J. Wysocki
[not found] ` <201104192335.34560.rjw@sisk.pl>
2011-04-20 11:57 ` Mark Brown
2011-04-16 23:43 ` [PATCH 8/9] OMAP1 / PM: Use generic clock manipulation routines " Rafael J. Wysocki
2011-04-16 23:44 ` [PATCH 9/9] PM: Revert "driver core: platform_bus: allow runtime override of dev_pm_ops" Rafael J. Wysocki
[not found] ` <201104170143.28980.rjw@sisk.pl>
2011-04-18 8:18 ` [PATCH 8/9] OMAP1 / PM: Use generic clock manipulation routines for runtime PM Paul Mundt
[not found] ` <20110418081809.GA32457@linux-sh.org>
2011-04-18 19:57 ` Rafael J. Wysocki
2011-04-24 21:30 ` [PATCH 0/9] PM: Rework shmobile and OMAP runtime PM using power domains (v2) Rafael J. Wysocki
[not found] ` <201104242330.13607.rjw@sisk.pl>
2011-04-24 21:36 ` [PATCH 1/9] PM: Make power domain callbacks take precedence over subsystem ones Rafael J. Wysocki
2011-04-24 21:37 ` [PATCH 2/9] PM: Export platform bus type's default PM callbacks Rafael J. Wysocki
2011-04-24 21:38 ` [PATCH 3/9] shmobile: Use power domains for platform runtime PM Rafael J. Wysocki
2011-04-24 21:39 ` [PATCH 4/9] PM / Platform: Use generic runtime PM callbacks directly Rafael J. Wysocki
2011-04-24 21:41 ` [PATCH 5/9] OMAP2+ / PM: move runtime PM implementation to use device power domains Rafael J. Wysocki
2011-04-24 21:42 ` [PATCH 6/9] PM / Runtime: Add subsystem data field to struct dev_pm_info Rafael J. Wysocki
2011-04-24 21:42 ` [PATCH 7/9] PM / Runtime: Generic clock manipulation rountines for runtime PM (v2) Rafael J. Wysocki
2011-04-24 21:43 ` [PATCH 8/9] OMAP1 / PM: Use generic clock manipulation routines for runtime PM Rafael J. Wysocki
2011-04-24 21:44 ` [PATCH 9/9] PM: Revert "driver core: platform_bus: allow runtime override of dev_pm_ops" Rafael J. Wysocki
2011-04-24 23:36 ` [PATCH 0/9] PM: Rework shmobile and OMAP runtime PM using power domains (v2) Greg KH
[not found] ` <201104242342.58326.rjw@sisk.pl>
2011-04-27 21:48 ` [Update][PATCH 7/9] PM / Runtime: Generic clock manipulation rountines for runtime PM (v3) Rafael J. Wysocki
[not found] ` <201104272348.24084.rjw@sisk.pl>
2011-04-27 23:04 ` Colin Cross
[not found] ` <BANLkTimHkKq9+0z-4CZs=34GNO6Ab0wZPQ@mail.gmail.com>
2011-04-28 0:58 ` Rafael J. Wysocki
[not found] ` <201104280258.34694.rjw@sisk.pl>
2011-04-28 1:06 ` Rafael J. Wysocki
[not found] ` <201104280306.13262.rjw@sisk.pl>
2011-04-28 1:33 ` Rafael J. Wysocki
[not found] ` <201104280333.13730.rjw@sisk.pl>
2011-04-28 19:36 ` [Update x2][PATCH 7/9] PM / Runtime: Generic clock manipulation rountines for runtime PM (v5) Rafael J. Wysocki
[not found] ` <201104282136.26163.rjw@sisk.pl>
2011-04-29 19:35 ` Stephen Boyd
[not found] ` <4DBB12EF.9030000@codeaurora.org>
2011-04-29 20:29 ` Rafael J. Wysocki
[not found] ` <201104292229.56518.rjw@sisk.pl>
2011-04-29 22:04 ` [Update x3][PATCH 7/9] PM / Runtime: Generic clock manipulation rountines for runtime PM (v6) Rafael J. Wysocki
[not found] ` <201104300004.02601.rjw@sisk.pl>
2011-05-03 17:00 ` Stephen Boyd
[not found] ` <4DC034CA.6000505@codeaurora.org>
2011-05-03 17:38 ` Rafael J. Wysocki
2011-04-29 20:50 ` [Update][PATCH 7/9] PM / Runtime: Generic clock manipulation rountines for runtime PM (v3) Grant Likely
[not found] ` <20110429205039.GB7497@ponder.secretlab.ca>
2011-04-29 21:07 ` Rafael J. Wysocki
[not found] ` <201104242343.41456.rjw@sisk.pl>
2011-05-16 10:16 ` [PATCH 8/9] OMAP1 / PM: Use generic clock manipulation routines for runtime PM Kevin Hilman
[not found] ` <87mxindk7m.fsf@ti.com>
2011-05-16 18:26 ` Rafael J. Wysocki
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=201104170142.10723.rjw@sisk.pl \
--to=rjw@sisk.pl \
--cc=grant.likely@secretlab.ca \
--cc=gregkh@suse.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@lists.linux-foundation.org \
--cc=linux-sh@vger.kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox