aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-04-29 18:25:44 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2011-04-29 18:25:44 -0400
commit85eb8c8d0b0900c073b0e6f89979ac9c439ade1a (patch)
treeff3486424b60bb8de28ef76655d65cd0c1180449 /arch
parent1d2b71f61b6a10216274e27b717becf9ae101fc7 (diff)
PM / Runtime: Generic clock manipulation rountines for runtime PM (v6)
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>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-shmobile/pm_runtime.c140
1 files changed, 9 insertions, 131 deletions
diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c
index 30bbe9a99ae1..2d1b67a59e4a 100644
--- a/arch/arm/mach-shmobile/pm_runtime.c
+++ b/arch/arm/mach-shmobile/pm_runtime.c
@@ -21,70 +21,6 @@
21#include <linux/slab.h> 21#include <linux/slab.h>
22 22
23#ifdef CONFIG_PM_RUNTIME 23#ifdef CONFIG_PM_RUNTIME
24#define BIT_ONCE 0
25#define BIT_ACTIVE 1
26#define BIT_CLK_ENABLED 2
27
28struct pm_runtime_data {
29 unsigned long flags;
30 struct clk *clk;
31};
32
33static struct pm_runtime_data *__to_prd(struct device *dev)
34{
35 return dev ? dev->power.subsys_data : NULL;
36}
37
38static void platform_pm_runtime_init(struct device *dev,
39 struct pm_runtime_data *prd)
40{
41 if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
42 prd->clk = clk_get(dev, NULL);
43 if (!IS_ERR(prd->clk)) {
44 set_bit(BIT_ACTIVE, &prd->flags);
45 dev_info(dev, "clocks managed by runtime pm\n");
46 }
47 }
48}
49
50static void platform_pm_runtime_bug(struct device *dev,
51 struct pm_runtime_data *prd)
52{
53 if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
54 dev_err(dev, "runtime pm suspend before resume\n");
55}
56
57static int default_platform_runtime_suspend(struct device *dev)
58{
59 struct pm_runtime_data *prd = __to_prd(dev);
60
61 dev_dbg(dev, "%s()\n", __func__);
62
63 platform_pm_runtime_bug(dev, prd);
64
65 if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
66 clk_disable(prd->clk);
67 clear_bit(BIT_CLK_ENABLED, &prd->flags);
68 }
69
70 return 0;
71}
72
73static int default_platform_runtime_resume(struct device *dev)
74{
75 struct pm_runtime_data *prd = __to_prd(dev);
76
77 dev_dbg(dev, "%s()\n", __func__);
78
79 platform_pm_runtime_init(dev, prd);
80
81 if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
82 clk_enable(prd->clk);
83 set_bit(BIT_CLK_ENABLED, &prd->flags);
84 }
85
86 return 0;
87}
88 24
89static int default_platform_runtime_idle(struct device *dev) 25static int default_platform_runtime_idle(struct device *dev)
90{ 26{
@@ -94,87 +30,29 @@ static int default_platform_runtime_idle(struct device *dev)
94 30
95static struct dev_power_domain default_power_domain = { 31static struct dev_power_domain default_power_domain = {
96 .ops = { 32 .ops = {
97 .runtime_suspend = default_platform_runtime_suspend, 33 .runtime_suspend = pm_runtime_clk_suspend,
98 .runtime_resume = default_platform_runtime_resume, 34 .runtime_resume = pm_runtime_clk_resume,
99 .runtime_idle = default_platform_runtime_idle, 35 .runtime_idle = default_platform_runtime_idle,
100 USE_PLATFORM_PM_SLEEP_OPS 36 USE_PLATFORM_PM_SLEEP_OPS
101 }, 37 },
102}; 38};
103 39
104static int platform_bus_notify(struct notifier_block *nb, 40#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain)
105 unsigned long action, void *data)
106{
107 struct device *dev = data;
108 struct pm_runtime_data *prd;
109
110 dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
111
112 switch (action) {
113 case BUS_NOTIFY_BIND_DRIVER:
114 prd = kzalloc(sizeof(*prd), GFP_KERNEL);
115 if (prd) {
116 dev->power.subsys_data = prd;
117 dev->pwr_domain = &default_power_domain;
118 } else {
119 dev_err(dev, "unable to alloc memory for runtime pm\n");
120 }
121 break;
122 case BUS_NOTIFY_UNBOUND_DRIVER:
123 prd = __to_prd(dev);
124 if (prd) {
125 if (test_bit(BIT_CLK_ENABLED, &prd->flags))
126 clk_disable(prd->clk);
127 41
128 if (test_bit(BIT_ACTIVE, &prd->flags)) 42#else
129 clk_put(prd->clk);
130 }
131 break;
132 }
133 43
134 return 0; 44#define DEFAULT_PWR_DOMAIN_PTR NULL
135}
136
137#else /* CONFIG_PM_RUNTIME */
138
139static int platform_bus_notify(struct notifier_block *nb,
140 unsigned long action, void *data)
141{
142 struct device *dev = data;
143 struct clk *clk;
144
145 dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
146
147 switch (action) {
148 case BUS_NOTIFY_BIND_DRIVER:
149 clk = clk_get(dev, NULL);
150 if (!IS_ERR(clk)) {
151 clk_enable(clk);
152 clk_put(clk);
153 dev_info(dev, "runtime pm disabled, clock forced on\n");
154 }
155 break;
156 case BUS_NOTIFY_UNBOUND_DRIVER:
157 clk = clk_get(dev, NULL);
158 if (!IS_ERR(clk)) {
159 clk_disable(clk);
160 clk_put(clk);
161 dev_info(dev, "runtime pm disabled, clock forced off\n");
162 }
163 break;
164 }
165
166 return 0;
167}
168 45
169#endif /* CONFIG_PM_RUNTIME */ 46#endif /* CONFIG_PM_RUNTIME */
170 47
171static struct notifier_block platform_bus_notifier = { 48static struct pm_clk_notifier_block platform_bus_notifier = {
172 .notifier_call = platform_bus_notify 49 .pwr_domain = DEFAULT_PWR_DOMAIN_PTR,
50 .con_ids = { NULL, },
173}; 51};
174 52
175static int __init sh_pm_runtime_init(void) 53static int __init sh_pm_runtime_init(void)
176{ 54{
177 bus_register_notifier(&platform_bus_type, &platform_bus_notifier); 55 pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
178 return 0; 56 return 0;
179} 57}
180core_initcall(sh_pm_runtime_init); 58core_initcall(sh_pm_runtime_init);