aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-omap2/clockdomain.c4
-rw-r--r--arch/arm/mach-omap2/powerdomain.c136
-rw-r--r--arch/arm/plat-omap/include/mach/powerdomain.h16
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 */
38static LIST_HEAD(pwrdm_list); 39static 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 */
250int 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
287pac_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 */
303int 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
332pdc_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 */
353int 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
56struct clockdomain;
50struct powerdomain; 57struct 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
112int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm)); 122int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm));
113 123
124int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
125int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
126int pwrdm_for_each_clkdm(struct powerdomain *pwrdm,
127 int (*fn)(struct powerdomain *pwrdm,
128 struct clockdomain *clkdm));
129
114int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); 130int pwrdm_add_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
115int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); 131int pwrdm_del_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);
116int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2); 132int pwrdm_read_wkdep(struct powerdomain *pwrdm1, struct powerdomain *pwrdm2);