diff options
-rw-r--r-- | arch/arm/mach-omap2/clockdomain.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/powerdomain.c | 136 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/mach/powerdomain.h | 16 |
3 files changed, 156 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c index f867d8f1d0e9..b6ff5aa4726e 100644 --- a/arch/arm/mach-omap2/clockdomain.c +++ b/arch/arm/mach-omap2/clockdomain.c | |||
@@ -219,6 +219,8 @@ int clkdm_register(struct clockdomain *clkdm) | |||
219 | 219 | ||
220 | list_add(&clkdm->node, &clkdm_list); | 220 | list_add(&clkdm->node, &clkdm_list); |
221 | 221 | ||
222 | pwrdm_add_clkdm(pwrdm, clkdm); | ||
223 | |||
222 | pr_debug("clockdomain: registered %s\n", clkdm->name); | 224 | pr_debug("clockdomain: registered %s\n", clkdm->name); |
223 | ret = 0; | 225 | ret = 0; |
224 | 226 | ||
@@ -240,6 +242,8 @@ int clkdm_unregister(struct clockdomain *clkdm) | |||
240 | if (!clkdm) | 242 | if (!clkdm) |
241 | return -EINVAL; | 243 | return -EINVAL; |
242 | 244 | ||
245 | pwrdm_del_clkdm(clkdm->pwrdm, clkdm); | ||
246 | |||
243 | mutex_lock(&clkdm_mutex); | 247 | mutex_lock(&clkdm_mutex); |
244 | list_del(&clkdm->node); | 248 | list_del(&clkdm->node); |
245 | mutex_unlock(&clkdm_mutex); | 249 | mutex_unlock(&clkdm_mutex); |
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c index 1ec003832ef8..9a803492b28f 100644 --- a/arch/arm/mach-omap2/powerdomain.c +++ b/arch/arm/mach-omap2/powerdomain.c | |||
@@ -33,6 +33,7 @@ | |||
33 | 33 | ||
34 | #include <mach/cpu.h> | 34 | #include <mach/cpu.h> |
35 | #include <mach/powerdomain.h> | 35 | #include <mach/powerdomain.h> |
36 | #include <mach/clockdomain.h> | ||
36 | 37 | ||
37 | /* pwrdm_list contains all registered struct powerdomains */ | 38 | /* pwrdm_list contains all registered struct powerdomains */ |
38 | static LIST_HEAD(pwrdm_list); | 39 | static LIST_HEAD(pwrdm_list); |
@@ -237,6 +238,141 @@ int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)) | |||
237 | } | 238 | } |
238 | 239 | ||
239 | /** | 240 | /** |
241 | * pwrdm_add_clkdm - add a clockdomain to a powerdomain | ||
242 | * @pwrdm: struct powerdomain * to add the clockdomain to | ||
243 | * @clkdm: struct clockdomain * to associate with a powerdomain | ||
244 | * | ||
245 | * Associate the clockdomain 'clkdm' with a powerdomain 'pwrdm'. This | ||
246 | * enables the use of pwrdm_for_each_clkdm(). Returns -EINVAL if | ||
247 | * presented with invalid pointers; -ENOMEM if memory could not be allocated; | ||
248 | * or 0 upon success. | ||
249 | */ | ||
250 | int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) | ||
251 | { | ||
252 | unsigned long flags; | ||
253 | int i; | ||
254 | int ret = -EINVAL; | ||
255 | |||
256 | if (!pwrdm || !clkdm) | ||
257 | return -EINVAL; | ||
258 | |||
259 | pr_debug("powerdomain: associating clockdomain %s with powerdomain " | ||
260 | "%s\n", clkdm->name, pwrdm->name); | ||
261 | |||
262 | write_lock_irqsave(&pwrdm_rwlock, flags); | ||
263 | |||
264 | for (i = 0; i < PWRDM_MAX_CLKDMS; i++) { | ||
265 | if (!pwrdm->pwrdm_clkdms[i]) | ||
266 | break; | ||
267 | #ifdef DEBUG | ||
268 | if (pwrdm->pwrdm_clkdms[i] == clkdm) { | ||
269 | ret = -EINVAL; | ||
270 | goto pac_exit; | ||
271 | } | ||
272 | #endif | ||
273 | } | ||
274 | |||
275 | if (i == PWRDM_MAX_CLKDMS) { | ||
276 | pr_debug("powerdomain: increase PWRDM_MAX_CLKDMS for " | ||
277 | "pwrdm %s clkdm %s\n", pwrdm->name, clkdm->name); | ||
278 | WARN_ON(1); | ||
279 | ret = -ENOMEM; | ||
280 | goto pac_exit; | ||
281 | } | ||
282 | |||
283 | pwrdm->pwrdm_clkdms[i] = clkdm; | ||
284 | |||
285 | ret = 0; | ||
286 | |||
287 | pac_exit: | ||
288 | write_unlock_irqrestore(&pwrdm_rwlock, flags); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | /** | ||
294 | * pwrdm_del_clkdm - remove a clockdomain from a powerdomain | ||
295 | * @pwrdm: struct powerdomain * to add the clockdomain to | ||
296 | * @clkdm: struct clockdomain * to associate with a powerdomain | ||
297 | * | ||
298 | * Dissociate the clockdomain 'clkdm' from the powerdomain | ||
299 | * 'pwrdm'. Returns -EINVAL if presented with invalid pointers; | ||
300 | * -ENOENT if the clkdm was not associated with the powerdomain, or 0 | ||
301 | * upon success. | ||
302 | */ | ||
303 | int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm) | ||
304 | { | ||
305 | unsigned long flags; | ||
306 | int ret = -EINVAL; | ||
307 | int i; | ||
308 | |||
309 | if (!pwrdm || !clkdm) | ||
310 | return -EINVAL; | ||
311 | |||
312 | pr_debug("powerdomain: dissociating clockdomain %s from powerdomain " | ||
313 | "%s\n", clkdm->name, pwrdm->name); | ||
314 | |||
315 | write_lock_irqsave(&pwrdm_rwlock, flags); | ||
316 | |||
317 | for (i = 0; i < PWRDM_MAX_CLKDMS; i++) | ||
318 | if (pwrdm->pwrdm_clkdms[i] == clkdm) | ||
319 | break; | ||
320 | |||
321 | if (i == PWRDM_MAX_CLKDMS) { | ||
322 | pr_debug("powerdomain: clkdm %s not associated with pwrdm " | ||
323 | "%s ?!\n", clkdm->name, pwrdm->name); | ||
324 | ret = -ENOENT; | ||
325 | goto pdc_exit; | ||
326 | } | ||
327 | |||
328 | pwrdm->pwrdm_clkdms[i] = NULL; | ||
329 | |||
330 | ret = 0; | ||
331 | |||
332 | pdc_exit: | ||
333 | write_unlock_irqrestore(&pwrdm_rwlock, flags); | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * pwrdm_for_each_clkdm - call function on each clkdm in a pwrdm | ||
340 | * @pwrdm: struct powerdomain * to iterate over | ||
341 | * @fn: callback function * | ||
342 | * | ||
343 | * Call the supplied function for each clockdomain in the powerdomain | ||
344 | * 'pwrdm'. The callback function can return anything but 0 to bail | ||
345 | * out early from the iterator. The callback function is called with | ||
346 | * the pwrdm_rwlock held for reading, so no powerdomain structure | ||
347 | * manipulation functions should be called from the callback, although | ||
348 | * hardware powerdomain control functions are fine. Returns -EINVAL | ||
349 | * if presented with invalid pointers; or passes along the last return | ||
350 | * value of the callback function, which should be 0 for success or | ||
351 | * anything else to indicate failure. | ||
352 | */ | ||
353 | int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, | ||
354 | int (*fn)(struct powerdomain *pwrdm, | ||
355 | struct clockdomain *clkdm)) | ||
356 | { | ||
357 | unsigned long flags; | ||
358 | int ret = 0; | ||
359 | int i; | ||
360 | |||
361 | if (!fn) | ||
362 | return -EINVAL; | ||
363 | |||
364 | read_lock_irqsave(&pwrdm_rwlock, flags); | ||
365 | |||
366 | for (i = 0; i < PWRDM_MAX_CLKDMS && !ret; i++) | ||
367 | ret = (*fn)(pwrdm, pwrdm->pwrdm_clkdms[i]); | ||
368 | |||
369 | read_unlock_irqrestore(&pwrdm_rwlock, flags); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | |||
375 | /** | ||
240 | * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1 | 376 | * pwrdm_add_wkdep - add a wakeup dependency from pwrdm2 to pwrdm1 |
241 | * @pwrdm1: wake this struct powerdomain * up (dependent) | 377 | * @pwrdm1: wake this struct powerdomain * up (dependent) |
242 | * @pwrdm2: when this struct powerdomain * wakes up (source) | 378 | * @pwrdm2: when this struct powerdomain * wakes up (source) |
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h index c8f52c6f8b7e..5fa666fa9be8 100644 --- a/arch/arm/plat-omap/include/mach/powerdomain.h +++ b/arch/arm/plat-omap/include/mach/powerdomain.h | |||
@@ -44,9 +44,16 @@ | |||
44 | */ | 44 | */ |
45 | #define PWRDM_MAX_MEM_BANKS 4 | 45 | #define PWRDM_MAX_MEM_BANKS 4 |
46 | 46 | ||
47 | /* | ||
48 | * Maximum number of clockdomains that can be associated with a powerdomain. | ||
49 | * CORE powerdomain is probably the worst case. | ||
50 | */ | ||
51 | #define PWRDM_MAX_CLKDMS 3 | ||
52 | |||
47 | /* XXX A completely arbitrary number. What is reasonable here? */ | 53 | /* XXX A completely arbitrary number. What is reasonable here? */ |
48 | #define PWRDM_TRANSITION_BAILOUT 100000 | 54 | #define PWRDM_TRANSITION_BAILOUT 100000 |
49 | 55 | ||
56 | struct clockdomain; | ||
50 | struct powerdomain; | 57 | struct powerdomain; |
51 | 58 | ||
52 | /* Encodes dependencies between powerdomains - statically defined */ | 59 | /* Encodes dependencies between powerdomains - statically defined */ |
@@ -98,6 +105,9 @@ struct powerdomain { | |||
98 | /* Possible memory bank pwrstates when pwrdm is ON */ | 105 | /* Possible memory bank pwrstates when pwrdm is ON */ |
99 | const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS]; | 106 | const u8 pwrsts_mem_on[PWRDM_MAX_MEM_BANKS]; |
100 | 107 | ||
108 | /* Clockdomains in this powerdomain */ | ||
109 | struct clockdomain *pwrdm_clkdms[PWRDM_MAX_CLKDMS]; | ||
110 | |||
101 | struct list_head node; | 111 | struct list_head node; |
102 | 112 | ||
103 | }; | 113 | }; |
@@ -111,6 +121,12 @@ struct powerdomain *pwrdm_lookup(const char *name); | |||
111 | 121 | ||
112 | int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)); | 122 | int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)); |
113 | 123 | ||
124 | int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); | ||
125 | int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm); | ||
126 | int pwrdm_for_each_clkdm(struct powerdomain *pwrdm, | ||
127 | int (*fn)(struct powerdomain *pwrdm, | ||
128 | struct clockdomain *clkdm)); | ||
129 | |||
114 | int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); | 130 | int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); |
115 | int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); | 131 | int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); |
116 | int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); | 132 | int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); |