Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
[cris-mirror.git] / arch / arm / mach-shmobile / pm_runtime.c
blob94912d3944d3997d55bbb0b5d71d1be287c82ceb
1 /*
2 * arch/arm/mach-shmobile/pm_runtime.c
4 * Runtime PM support code for SuperH Mobile ARM
6 * Copyright (C) 2009-2010 Magnus Damm
8 * This file is subject to the terms and conditions of the GNU General Public
9 * License. See the file "COPYING" in the main directory of this archive
10 * for more details.
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/io.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
19 #include <linux/sh_clk.h>
20 #include <linux/bitmap.h>
22 #ifdef CONFIG_PM_RUNTIME
23 #define BIT_ONCE 0
24 #define BIT_ACTIVE 1
25 #define BIT_CLK_ENABLED 2
27 struct pm_runtime_data {
28 unsigned long flags;
29 struct clk *clk;
32 static void __devres_release(struct device *dev, void *res)
34 struct pm_runtime_data *prd = res;
36 dev_dbg(dev, "__devres_release()\n");
38 if (test_bit(BIT_CLK_ENABLED, &prd->flags))
39 clk_disable(prd->clk);
41 if (test_bit(BIT_ACTIVE, &prd->flags))
42 clk_put(prd->clk);
45 static struct pm_runtime_data *__to_prd(struct device *dev)
47 return devres_find(dev, __devres_release, NULL, NULL);
50 static void platform_pm_runtime_init(struct device *dev,
51 struct pm_runtime_data *prd)
53 if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
54 prd->clk = clk_get(dev, NULL);
55 if (!IS_ERR(prd->clk)) {
56 set_bit(BIT_ACTIVE, &prd->flags);
57 dev_info(dev, "clocks managed by runtime pm\n");
62 static void platform_pm_runtime_bug(struct device *dev,
63 struct pm_runtime_data *prd)
65 if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
66 dev_err(dev, "runtime pm suspend before resume\n");
69 int platform_pm_runtime_suspend(struct device *dev)
71 struct pm_runtime_data *prd = __to_prd(dev);
73 dev_dbg(dev, "platform_pm_runtime_suspend()\n");
75 platform_pm_runtime_bug(dev, prd);
77 if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
78 clk_disable(prd->clk);
79 clear_bit(BIT_CLK_ENABLED, &prd->flags);
82 return 0;
85 int platform_pm_runtime_resume(struct device *dev)
87 struct pm_runtime_data *prd = __to_prd(dev);
89 dev_dbg(dev, "platform_pm_runtime_resume()\n");
91 platform_pm_runtime_init(dev, prd);
93 if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
94 clk_enable(prd->clk);
95 set_bit(BIT_CLK_ENABLED, &prd->flags);
98 return 0;
101 int platform_pm_runtime_idle(struct device *dev)
103 /* suspend synchronously to disable clocks immediately */
104 return pm_runtime_suspend(dev);
107 static int platform_bus_notify(struct notifier_block *nb,
108 unsigned long action, void *data)
110 struct device *dev = data;
111 struct pm_runtime_data *prd;
113 dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
115 if (action == BUS_NOTIFY_BIND_DRIVER) {
116 prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL);
117 if (prd)
118 devres_add(dev, prd);
119 else
120 dev_err(dev, "unable to alloc memory for runtime pm\n");
123 return 0;
126 #else /* CONFIG_PM_RUNTIME */
128 static int platform_bus_notify(struct notifier_block *nb,
129 unsigned long action, void *data)
131 struct device *dev = data;
132 struct clk *clk;
134 dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
136 switch (action) {
137 case BUS_NOTIFY_BIND_DRIVER:
138 clk = clk_get(dev, NULL);
139 if (!IS_ERR(clk)) {
140 clk_enable(clk);
141 clk_put(clk);
142 dev_info(dev, "runtime pm disabled, clock forced on\n");
144 break;
145 case BUS_NOTIFY_UNBOUND_DRIVER:
146 clk = clk_get(dev, NULL);
147 if (!IS_ERR(clk)) {
148 clk_disable(clk);
149 clk_put(clk);
150 dev_info(dev, "runtime pm disabled, clock forced off\n");
152 break;
155 return 0;
158 #endif /* CONFIG_PM_RUNTIME */
160 static struct notifier_block platform_bus_notifier = {
161 .notifier_call = platform_bus_notify
164 static int __init sh_pm_runtime_init(void)
166 bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
167 return 0;
169 core_initcall(sh_pm_runtime_init);