diff options
Diffstat (limited to 'arch/arm/mach-omap2/powerdomain.c')
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 110 |
1 files changed, 85 insertions, 25 deletions
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index ef71fdd40fc4..5164d587ef52 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * OMAP powerdomain control | 2 | * OMAP powerdomain control |
3 | * | 3 | * |
4 | * Copyright (C) 2007-2008 Texas Instruments, Inc. | 4 | * Copyright (C) 2007-2008, 2011 Texas Instruments, Inc. |
5 | * Copyright (C) 2007-2011 Nokia Corporation | 5 | * Copyright (C) 2007-2011 Nokia Corporation |
6 | * | 6 | * |
7 | * Written by Paul Walmsley | 7 | * Written by Paul Walmsley |
@@ -77,13 +77,11 @@ static struct powerdomain *_pwrdm_lookup(const char *name) | |||
77 | static int _pwrdm_register(struct powerdomain *pwrdm) | 77 | static int _pwrdm_register(struct powerdomain *pwrdm) |
78 | { | 78 | { |
79 | int i; | 79 | int i; |
80 | struct voltagedomain *voltdm; | ||
80 | 81 | ||
81 | if (!pwrdm || !pwrdm->name) | 82 | if (!pwrdm || !pwrdm->name) |
82 | return -EINVAL; | 83 | return -EINVAL; |
83 | 84 | ||
84 | if (!omap_chip_is(pwrdm->omap_chip)) | ||
85 | return -EINVAL; | ||
86 | |||
87 | if (cpu_is_omap44xx() && | 85 | if (cpu_is_omap44xx() && |
88 | pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) { | 86 | pwrdm->prcm_partition == OMAP4430_INVALID_PRCM_PARTITION) { |
89 | pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n", | 87 | pr_err("powerdomain: %s: missing OMAP4 PRCM partition ID\n", |
@@ -94,6 +92,16 @@ static int _pwrdm_register(struct powerdomain *pwrdm) | |||
94 | if (_pwrdm_lookup(pwrdm->name)) | 92 | if (_pwrdm_lookup(pwrdm->name)) |
95 | return -EEXIST; | 93 | return -EEXIST; |
96 | 94 | ||
95 | voltdm = voltdm_lookup(pwrdm->voltdm.name); | ||
96 | if (!voltdm) { | ||
97 | pr_err("powerdomain: %s: voltagedomain %s does not exist\n", | ||
98 | pwrdm->name, pwrdm->voltdm.name); | ||
99 | return -EINVAL; | ||
100 | } | ||
101 | pwrdm->voltdm.ptr = voltdm; | ||
102 | INIT_LIST_HEAD(&pwrdm->voltdm_node); | ||
103 | voltdm_add_pwrdm(voltdm, pwrdm); | ||
104 | |||
97 | list_add(&pwrdm->node, &pwrdm_list); | 105 | list_add(&pwrdm->node, &pwrdm_list); |
98 | 106 | ||
99 | /* Initialize the powerdomain's state counter */ | 107 | /* Initialize the powerdomain's state counter */ |
@@ -194,36 +202,76 @@ static int _pwrdm_post_transition_cb(struct powerdomain *pwrdm, void *unused) | |||
194 | /* Public functions */ | 202 | /* Public functions */ |
195 | 203 | ||
196 | /** | 204 | /** |
197 | * pwrdm_init - set up the powerdomain layer | 205 | * pwrdm_register_platform_funcs - register powerdomain implementation fns |
198 | * @pwrdms: array of struct powerdomain pointers to register | 206 | * @po: func pointers for arch specific implementations |
199 | * @custom_funcs: func pointers for arch specific implementations | ||
200 | * | 207 | * |
201 | * Loop through the array of powerdomains @pwrdms, registering all | 208 | * Register the list of function pointers used to implement the |
202 | * that are available on the current CPU. Also, program all | 209 | * powerdomain functions on different OMAP SoCs. Should be called |
203 | * powerdomain target state as ON; this is to prevent domains from | 210 | * before any other pwrdm_register*() function. Returns -EINVAL if |
204 | * hitting low power states (if bootloader has target states set to | 211 | * @po is null, -EEXIST if platform functions have already been |
205 | * something other than ON) and potentially even losing context while | 212 | * registered, or 0 upon success. |
206 | * PM is not fully initialized. The PM late init code can then program | ||
207 | * the desired target state for all the power domains. No return | ||
208 | * value. | ||
209 | */ | 213 | */ |
210 | void pwrdm_init(struct powerdomain **pwrdms, struct pwrdm_ops *custom_funcs) | 214 | int pwrdm_register_platform_funcs(struct pwrdm_ops *po) |
215 | { | ||
216 | if (!po) | ||
217 | return -EINVAL; | ||
218 | |||
219 | if (arch_pwrdm) | ||
220 | return -EEXIST; | ||
221 | |||
222 | arch_pwrdm = po; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * pwrdm_register_pwrdms - register SoC powerdomains | ||
229 | * @ps: pointer to an array of struct powerdomain to register | ||
230 | * | ||
231 | * Register the powerdomains available on a particular OMAP SoC. Must | ||
232 | * be called after pwrdm_register_platform_funcs(). May be called | ||
233 | * multiple times. Returns -EACCES if called before | ||
234 | * pwrdm_register_platform_funcs(); -EINVAL if the argument @ps is | ||
235 | * null; or 0 upon success. | ||
236 | */ | ||
237 | int pwrdm_register_pwrdms(struct powerdomain **ps) | ||
211 | { | 238 | { |
212 | struct powerdomain **p = NULL; | 239 | struct powerdomain **p = NULL; |
213 | struct powerdomain *temp_p; | ||
214 | 240 | ||
215 | if (!custom_funcs) | 241 | if (!arch_pwrdm) |
216 | WARN(1, "powerdomain: No custom pwrdm functions registered\n"); | 242 | return -EEXIST; |
217 | else | ||
218 | arch_pwrdm = custom_funcs; | ||
219 | 243 | ||
220 | if (pwrdms) { | 244 | if (!ps) |
221 | for (p = pwrdms; *p; p++) | 245 | return -EINVAL; |
222 | _pwrdm_register(*p); | 246 | |
223 | } | 247 | for (p = ps; *p; p++) |
248 | _pwrdm_register(*p); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * pwrdm_complete_init - set up the powerdomain layer | ||
255 | * | ||
256 | * Do whatever is necessary to initialize registered powerdomains and | ||
257 | * powerdomain code. Currently, this programs the next power state | ||
258 | * for each powerdomain to ON. This prevents powerdomains from | ||
259 | * unexpectedly losing context or entering high wakeup latency modes | ||
260 | * with non-power-management-enabled kernels. Must be called after | ||
261 | * pwrdm_register_pwrdms(). Returns -EACCES if called before | ||
262 | * pwrdm_register_pwrdms(), or 0 upon success. | ||
263 | */ | ||
264 | int pwrdm_complete_init(void) | ||
265 | { | ||
266 | struct powerdomain *temp_p; | ||
267 | |||
268 | if (list_empty(&pwrdm_list)) | ||
269 | return -EACCES; | ||
224 | 270 | ||
225 | list_for_each_entry(temp_p, &pwrdm_list, node) | 271 | list_for_each_entry(temp_p, &pwrdm_list, node) |
226 | pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON); | 272 | pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON); |
273 | |||
274 | return 0; | ||
227 | } | 275 | } |
228 | 276 | ||
229 | /** | 277 | /** |
@@ -390,6 +438,18 @@ int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, | |||
390 | } | 438 | } |
391 | 439 | ||
392 | /** | 440 | /** |
441 | * pwrdm_get_voltdm - return a ptr to the voltdm that this pwrdm resides in | ||
442 | * @pwrdm: struct powerdomain * | ||
443 | * | ||
444 | * Return a pointer to the struct voltageomain that the specified powerdomain | ||
445 | * @pwrdm exists in. | ||
446 | */ | ||
447 | struct voltagedomain *pwrdm_get_voltdm(struct powerdomain *pwrdm) | ||
448 | { | ||
449 | return pwrdm->voltdm.ptr; | ||
450 | } | ||
451 | |||
452 | /** | ||
393 | * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain | 453 | * pwrdm_get_mem_bank_count - get number of memory banks in this powerdomain |
394 | * @pwrdm: struct powerdomain * | 454 | * @pwrdm: struct powerdomain * |
395 | * | 455 | * |