Skip to content

Commit

Permalink
PM / Runtime: Generic clock manipulation rountines for runtime PM (v6)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rafael J. Wysocki committed Apr 29, 2011
1 parent 1d2b71f commit 85eb8c8
Show file tree
Hide file tree
Showing 5 changed files with 486 additions and 131 deletions.
140 changes: 9 additions & 131 deletions arch/arm/mach-shmobile/pm_runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -94,87 +30,29 @@ static int default_platform_runtime_idle(struct device *dev)

static struct dev_power_domain default_power_domain = {
.ops = {
.runtime_suspend = default_platform_runtime_suspend,
.runtime_resume = default_platform_runtime_resume,
.runtime_suspend = pm_runtime_clk_suspend,
.runtime_resume = pm_runtime_clk_resume,
.runtime_idle = default_platform_runtime_idle,
USE_PLATFORM_PM_SLEEP_OPS
},
};

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);
#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain)

if (test_bit(BIT_ACTIVE, &prd->flags))
clk_put(prd->clk);
}
break;
}
#else

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;
}
#define DEFAULT_PWR_DOMAIN_PTR NULL

#endif /* CONFIG_PM_RUNTIME */

static struct notifier_block platform_bus_notifier = {
.notifier_call = platform_bus_notify
static struct pm_clk_notifier_block platform_bus_notifier = {
.pwr_domain = DEFAULT_PWR_DOMAIN_PTR,
.con_ids = { NULL, },
};

static int __init sh_pm_runtime_init(void)
{
bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
return 0;
}
core_initcall(sh_pm_runtime_init);
1 change: 1 addition & 0 deletions drivers/base/power/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
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
Loading

0 comments on commit 85eb8c8

Please sign in to comment.