diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2011-04-29 18:25:44 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2011-04-29 18:25:44 -0400 |
commit | 85eb8c8d0b0900c073b0e6f89979ac9c439ade1a (patch) | |
tree | ff3486424b60bb8de28ef76655d65cd0c1180449 /arch/arm/mach-shmobile/pm_runtime.c | |
parent | 1d2b71f61b6a10216274e27b717becf9ae101fc7 (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/arm/mach-shmobile/pm_runtime.c')
-rw-r--r-- | arch/arm/mach-shmobile/pm_runtime.c | 140 |
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 | |||
28 | struct pm_runtime_data { | ||
29 | unsigned long flags; | ||
30 | struct clk *clk; | ||
31 | }; | ||
32 | |||
33 | static struct pm_runtime_data *__to_prd(struct device *dev) | ||
34 | { | ||
35 | return dev ? dev->power.subsys_data : NULL; | ||
36 | } | ||
37 | |||
38 | static 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 | |||
50 | static 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 | |||
57 | static 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 | |||
73 | static 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 | ||
89 | static int default_platform_runtime_idle(struct device *dev) | 25 | static 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 | ||
95 | static struct dev_power_domain default_power_domain = { | 31 | static 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 | ||
104 | static 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 | |||
139 | static 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 | ||
171 | static struct notifier_block platform_bus_notifier = { | 48 | static 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 | ||
175 | static int __init sh_pm_runtime_init(void) | 53 | static 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 | } |
180 | core_initcall(sh_pm_runtime_init); | 58 | core_initcall(sh_pm_runtime_init); |