aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/powerdomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/powerdomain.c')
-rw-r--r--arch/arm/mach-omap2/powerdomain.c136
1 files changed, 136 insertions, 0 deletions
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)