• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6.36/arch/arm/mach-omap2/
1/*
2 * OMAP2/3/4 clockdomain framework functions
3 *
4 * Copyright (C) 2008-2010 Texas Instruments, Inc.
5 * Copyright (C) 2008-2010 Nokia Corporation
6 *
7 * Written by Paul Walmsley and Jouni H��gander
8 * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 */
14#undef DEBUG
15
16#include <linux/module.h>
17#include <linux/kernel.h>
18#include <linux/device.h>
19#include <linux/list.h>
20#include <linux/errno.h>
21#include <linux/delay.h>
22#include <linux/clk.h>
23#include <linux/limits.h>
24#include <linux/err.h>
25
26#include <linux/io.h>
27
28#include <linux/bitops.h>
29
30#include "prm.h"
31#include "prm-regbits-24xx.h"
32#include "cm.h"
33
34#include <plat/clock.h>
35#include <plat/powerdomain.h>
36#include <plat/clockdomain.h>
37#include <plat/prcm.h>
38
39/* clkdm_list contains all registered struct clockdomains */
40static LIST_HEAD(clkdm_list);
41
42/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
43static struct clkdm_autodep *autodeps;
44
45
46/* Private functions */
47
48static struct clockdomain *_clkdm_lookup(const char *name)
49{
50	struct clockdomain *clkdm, *temp_clkdm;
51
52	if (!name)
53		return NULL;
54
55	clkdm = NULL;
56
57	list_for_each_entry(temp_clkdm, &clkdm_list, node) {
58		if (!strcmp(name, temp_clkdm->name)) {
59			clkdm = temp_clkdm;
60			break;
61		}
62	}
63
64	return clkdm;
65}
66
67/**
68 * _clkdm_register - register a clockdomain
69 * @clkdm: struct clockdomain * to register
70 *
71 * Adds a clockdomain to the internal clockdomain list.
72 * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is
73 * already registered by the provided name, or 0 upon success.
74 */
75static int _clkdm_register(struct clockdomain *clkdm)
76{
77	struct powerdomain *pwrdm;
78
79	if (!clkdm || !clkdm->name)
80		return -EINVAL;
81
82	if (!omap_chip_is(clkdm->omap_chip))
83		return -EINVAL;
84
85	pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
86	if (!pwrdm) {
87		pr_err("clockdomain: %s: powerdomain %s does not exist\n",
88			clkdm->name, clkdm->pwrdm.name);
89		return -EINVAL;
90	}
91	clkdm->pwrdm.ptr = pwrdm;
92
93	/* Verify that the clockdomain is not already registered */
94	if (_clkdm_lookup(clkdm->name))
95		return -EEXIST;
96
97	list_add(&clkdm->node, &clkdm_list);
98
99	pwrdm_add_clkdm(pwrdm, clkdm);
100
101	pr_debug("clockdomain: registered %s\n", clkdm->name);
102
103	return 0;
104}
105
106/* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */
107static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
108					    struct clkdm_dep *deps)
109{
110	struct clkdm_dep *cd;
111
112	if (!clkdm || !deps || !omap_chip_is(clkdm->omap_chip))
113		return ERR_PTR(-EINVAL);
114
115	for (cd = deps; cd->clkdm_name; cd++) {
116		if (!omap_chip_is(cd->omap_chip))
117			continue;
118
119		if (!cd->clkdm && cd->clkdm_name)
120			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
121
122		if (cd->clkdm == clkdm)
123			break;
124	}
125
126	if (!cd->clkdm_name)
127		return ERR_PTR(-ENOENT);
128
129	return cd;
130}
131
132/*
133 * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
134 * @autodep: struct clkdm_autodep * to resolve
135 *
136 * Resolve autodep clockdomain names to clockdomain pointers via
137 * clkdm_lookup() and store the pointers in the autodep structure.  An
138 * "autodep" is a clockdomain sleep/wakeup dependency that is
139 * automatically added and removed whenever clocks in the associated
140 * clockdomain are enabled or disabled (respectively) when the
141 * clockdomain is in hardware-supervised mode.	Meant to be called
142 * once at clockdomain layer initialization, since these should remain
143 * fixed for a particular architecture.  No return value.
144 */
145static void _autodep_lookup(struct clkdm_autodep *autodep)
146{
147	struct clockdomain *clkdm;
148
149	if (!autodep)
150		return;
151
152	if (!omap_chip_is(autodep->omap_chip))
153		return;
154
155	clkdm = clkdm_lookup(autodep->clkdm.name);
156	if (!clkdm) {
157		pr_err("clockdomain: autodeps: clockdomain %s does not exist\n",
158			 autodep->clkdm.name);
159		clkdm = ERR_PTR(-ENOENT);
160	}
161	autodep->clkdm.ptr = clkdm;
162}
163
164/*
165 * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
166 * @clkdm: struct clockdomain *
167 *
168 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
169 * in hardware-supervised mode.  Meant to be called from clock framework
170 * when a clock inside clockdomain 'clkdm' is enabled.	No return value.
171 */
172static void _clkdm_add_autodeps(struct clockdomain *clkdm)
173{
174	struct clkdm_autodep *autodep;
175
176	if (!autodeps)
177		return;
178
179	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
180		if (IS_ERR(autodep->clkdm.ptr))
181			continue;
182
183		if (!omap_chip_is(autodep->omap_chip))
184			continue;
185
186		pr_debug("clockdomain: adding %s sleepdep/wkdep for "
187			 "clkdm %s\n", autodep->clkdm.ptr->name,
188			 clkdm->name);
189
190		clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
191		clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
192	}
193}
194
195/*
196 * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
197 * @clkdm: struct clockdomain *
198 *
199 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
200 * in hardware-supervised mode.  Meant to be called from clock framework
201 * when a clock inside clockdomain 'clkdm' is disabled.  No return value.
202 */
203static void _clkdm_del_autodeps(struct clockdomain *clkdm)
204{
205	struct clkdm_autodep *autodep;
206
207	if (!autodeps)
208		return;
209
210	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
211		if (IS_ERR(autodep->clkdm.ptr))
212			continue;
213
214		if (!omap_chip_is(autodep->omap_chip))
215			continue;
216
217		pr_debug("clockdomain: removing %s sleepdep/wkdep for "
218			 "clkdm %s\n", autodep->clkdm.ptr->name,
219			 clkdm->name);
220
221		clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
222		clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
223	}
224}
225
226/*
227 * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit
228 * @clkdm: struct clockdomain *
229 * @enable: int 0 to disable, 1 to enable
230 *
231 * Internal helper for actually switching the bit that controls hwsup
232 * idle transitions for clkdm.
233 */
234static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
235{
236	u32 bits, v;
237
238	if (cpu_is_omap24xx()) {
239		if (enable)
240			bits = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
241		else
242			bits = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
243	} else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
244		if (enable)
245			bits = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
246		else
247			bits = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
248	} else {
249		BUG();
250	}
251
252	bits = bits << __ffs(clkdm->clktrctrl_mask);
253
254	v = __raw_readl(clkdm->clkstctrl_reg);
255	v &= ~(clkdm->clktrctrl_mask);
256	v |= bits;
257	__raw_writel(v, clkdm->clkstctrl_reg);
258
259}
260
261/**
262 * _init_wkdep_usecount - initialize wkdep usecounts to match hardware
263 * @clkdm: clockdomain to initialize wkdep usecounts
264 *
265 * Initialize the wakeup dependency usecount variables for clockdomain @clkdm.
266 * If a wakeup dependency is present in the hardware, the usecount will be
267 * set to 1; otherwise, it will be set to 0.  Software should clear all
268 * software wakeup dependencies prior to calling this function if it wishes
269 * to ensure that all usecounts start at 0.  No return value.
270 */
271static void _init_wkdep_usecount(struct clockdomain *clkdm)
272{
273	u32 v;
274	struct clkdm_dep *cd;
275
276	if (!clkdm->wkdep_srcs)
277		return;
278
279	for (cd = clkdm->wkdep_srcs; cd->clkdm_name; cd++) {
280		if (!omap_chip_is(cd->omap_chip))
281			continue;
282
283		if (!cd->clkdm && cd->clkdm_name)
284			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
285
286		if (!cd->clkdm) {
287			WARN(!cd->clkdm, "clockdomain: %s: wkdep clkdm %s not "
288			     "found\n", clkdm->name, cd->clkdm_name);
289			continue;
290		}
291
292		v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
293					    PM_WKDEP,
294					    (1 << cd->clkdm->dep_bit));
295
296		if (v)
297			pr_debug("clockdomain: %s: wakeup dependency already "
298				 "set to wake up when %s wakes\n",
299				 clkdm->name, cd->clkdm->name);
300
301		atomic_set(&cd->wkdep_usecount, (v) ? 1 : 0);
302	}
303}
304
305/**
306 * _init_sleepdep_usecount - initialize sleepdep usecounts to match hardware
307 * @clkdm: clockdomain to initialize sleepdep usecounts
308 *
309 * Initialize the sleep dependency usecount variables for clockdomain @clkdm.
310 * If a sleep dependency is present in the hardware, the usecount will be
311 * set to 1; otherwise, it will be set to 0.  Software should clear all
312 * software sleep dependencies prior to calling this function if it wishes
313 * to ensure that all usecounts start at 0.  No return value.
314 */
315static void _init_sleepdep_usecount(struct clockdomain *clkdm)
316{
317	u32 v;
318	struct clkdm_dep *cd;
319
320	if (!cpu_is_omap34xx())
321		return;
322
323	if (!clkdm->sleepdep_srcs)
324		return;
325
326	for (cd = clkdm->sleepdep_srcs; cd->clkdm_name; cd++) {
327		if (!omap_chip_is(cd->omap_chip))
328			continue;
329
330		if (!cd->clkdm && cd->clkdm_name)
331			cd->clkdm = _clkdm_lookup(cd->clkdm_name);
332
333		if (!cd->clkdm) {
334			WARN(!cd->clkdm, "clockdomain: %s: sleepdep clkdm %s "
335			     "not found\n", clkdm->name, cd->clkdm_name);
336			continue;
337		}
338
339		v = prm_read_mod_bits_shift(clkdm->pwrdm.ptr->prcm_offs,
340					    OMAP3430_CM_SLEEPDEP,
341					    (1 << cd->clkdm->dep_bit));
342
343		if (v)
344			pr_debug("clockdomain: %s: sleep dependency already "
345				 "set to prevent from idling until %s "
346				 "idles\n", clkdm->name, cd->clkdm->name);
347
348		atomic_set(&cd->sleepdep_usecount, (v) ? 1 : 0);
349	}
350};
351
352/* Public functions */
353
354/**
355 * clkdm_init - set up the clockdomain layer
356 * @clkdms: optional pointer to an array of clockdomains to register
357 * @init_autodeps: optional pointer to an array of autodeps to register
358 *
359 * Set up internal state.  If a pointer to an array of clockdomains
360 * @clkdms was supplied, loop through the list of clockdomains,
361 * register all that are available on the current platform. Similarly,
362 * if a pointer to an array of clockdomain autodependencies
363 * @init_autodeps was provided, register those.  No return value.
364 */
365void clkdm_init(struct clockdomain **clkdms,
366		struct clkdm_autodep *init_autodeps)
367{
368	struct clockdomain **c = NULL;
369	struct clockdomain *clkdm;
370	struct clkdm_autodep *autodep = NULL;
371
372	if (clkdms)
373		for (c = clkdms; *c; c++)
374			_clkdm_register(*c);
375
376	autodeps = init_autodeps;
377	if (autodeps)
378		for (autodep = autodeps; autodep->clkdm.ptr; autodep++)
379			_autodep_lookup(autodep);
380
381	/*
382	 * Ensure that the *dep_usecount registers reflect the current
383	 * state of the PRCM.
384	 */
385	list_for_each_entry(clkdm, &clkdm_list, node) {
386		_init_wkdep_usecount(clkdm);
387		_init_sleepdep_usecount(clkdm);
388	}
389}
390
391/**
392 * clkdm_lookup - look up a clockdomain by name, return a pointer
393 * @name: name of clockdomain
394 *
395 * Find a registered clockdomain by its name @name.  Returns a pointer
396 * to the struct clockdomain if found, or NULL otherwise.
397 */
398struct clockdomain *clkdm_lookup(const char *name)
399{
400	struct clockdomain *clkdm, *temp_clkdm;
401
402	if (!name)
403		return NULL;
404
405	clkdm = NULL;
406
407	list_for_each_entry(temp_clkdm, &clkdm_list, node) {
408		if (!strcmp(name, temp_clkdm->name)) {
409			clkdm = temp_clkdm;
410			break;
411		}
412	}
413
414	return clkdm;
415}
416
417/**
418 * clkdm_for_each - call function on each registered clockdomain
419 * @fn: callback function *
420 *
421 * Call the supplied function @fn for each registered clockdomain.
422 * The callback function @fn can return anything but 0 to bail
423 * out early from the iterator.  The callback function is called with
424 * the clkdm_mutex held, so no clockdomain structure manipulation
425 * functions should be called from the callback, although hardware
426 * clockdomain control functions are fine.  Returns the last return
427 * value of the callback function, which should be 0 for success or
428 * anything else to indicate failure; or -EINVAL if the function pointer
429 * is null.
430 */
431int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
432			void *user)
433{
434	struct clockdomain *clkdm;
435	int ret = 0;
436
437	if (!fn)
438		return -EINVAL;
439
440	list_for_each_entry(clkdm, &clkdm_list, node) {
441		ret = (*fn)(clkdm, user);
442		if (ret)
443			break;
444	}
445
446	return ret;
447}
448
449
450/**
451 * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in
452 * @clkdm: struct clockdomain *
453 *
454 * Return a pointer to the struct powerdomain that the specified clockdomain
455 * @clkdm exists in, or returns NULL if @clkdm is NULL.
456 */
457struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
458{
459	if (!clkdm)
460		return NULL;
461
462	return clkdm->pwrdm.ptr;
463}
464
465
466/* Hardware clockdomain control */
467
468/**
469 * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1
470 * @clkdm1: wake this struct clockdomain * up (dependent)
471 * @clkdm2: when this struct clockdomain * wakes up (source)
472 *
473 * When the clockdomain represented by @clkdm2 wakes up, wake up
474 * @clkdm1. Implemented in hardware on the OMAP, this feature is
475 * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
476 * Returns -EINVAL if presented with invalid clockdomain pointers,
477 * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
478 * success.
479 */
480int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
481{
482	struct clkdm_dep *cd;
483
484	if (!clkdm1 || !clkdm2)
485		return -EINVAL;
486
487	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
488	if (IS_ERR(cd)) {
489		pr_debug("clockdomain: hardware cannot set/clear wake up of "
490			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
491		return PTR_ERR(cd);
492	}
493
494	if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
495		pr_debug("clockdomain: hardware will wake up %s when %s wakes "
496			 "up\n", clkdm1->name, clkdm2->name);
497
498		prm_set_mod_reg_bits((1 << clkdm2->dep_bit),
499				     clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
500	}
501
502	return 0;
503}
504
505/**
506 * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1
507 * @clkdm1: wake this struct clockdomain * up (dependent)
508 * @clkdm2: when this struct clockdomain * wakes up (source)
509 *
510 * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
511 * wakes up.  Returns -EINVAL if presented with invalid clockdomain
512 * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
513 * 0 upon success.
514 */
515int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
516{
517	struct clkdm_dep *cd;
518
519	if (!clkdm1 || !clkdm2)
520		return -EINVAL;
521
522	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
523	if (IS_ERR(cd)) {
524		pr_debug("clockdomain: hardware cannot set/clear wake up of "
525			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
526		return PTR_ERR(cd);
527	}
528
529	if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
530		pr_debug("clockdomain: hardware will no longer wake up %s "
531			 "after %s wakes up\n", clkdm1->name, clkdm2->name);
532
533		prm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
534				       clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP);
535	}
536
537	return 0;
538}
539
540/**
541 * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1
542 * @clkdm1: wake this struct clockdomain * up (dependent)
543 * @clkdm2: when this struct clockdomain * wakes up (source)
544 *
545 * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be
546 * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL
547 * if either clockdomain pointer is invalid; or -ENOENT if the hardware
548 * is incapable.
549 *
550 * REVISIT: Currently this function only represents software-controllable
551 * wakeup dependencies.  Wakeup dependencies fixed in hardware are not
552 * yet handled here.
553 */
554int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
555{
556	struct clkdm_dep *cd;
557
558	if (!clkdm1 || !clkdm2)
559		return -EINVAL;
560
561	cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
562	if (IS_ERR(cd)) {
563		pr_debug("clockdomain: hardware cannot set/clear wake up of "
564			 "%s when %s wakes up\n", clkdm1->name, clkdm2->name);
565		return PTR_ERR(cd);
566	}
567
568	return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs, PM_WKDEP,
569				       (1 << clkdm2->dep_bit));
570}
571
572/**
573 * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm
574 * @clkdm: struct clockdomain * to remove all wakeup dependencies from
575 *
576 * Remove all inter-clockdomain wakeup dependencies that could cause
577 * @clkdm to wake.  Intended to be used during boot to initialize the
578 * PRCM to a known state, after all clockdomains are put into swsup idle
579 * and woken up.  Returns -EINVAL if @clkdm pointer is invalid, or
580 * 0 upon success.
581 */
582int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
583{
584	struct clkdm_dep *cd;
585	u32 mask = 0;
586
587	if (!clkdm)
588		return -EINVAL;
589
590	for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
591		if (!omap_chip_is(cd->omap_chip))
592			continue;
593
594		/* PRM accesses are slow, so minimize them */
595		mask |= 1 << cd->clkdm->dep_bit;
596		atomic_set(&cd->wkdep_usecount, 0);
597	}
598
599	prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs, PM_WKDEP);
600
601	return 0;
602}
603
604/**
605 * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1
606 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
607 * @clkdm2: when this struct clockdomain * is active (source)
608 *
609 * Prevent @clkdm1 from automatically going inactive (and then to
610 * retention or off) if @clkdm2 is active.  Returns -EINVAL if
611 * presented with invalid clockdomain pointers or called on a machine
612 * that does not support software-configurable hardware sleep
613 * dependencies, -ENOENT if the specified dependency cannot be set in
614 * hardware, or 0 upon success.
615 */
616int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
617{
618	struct clkdm_dep *cd;
619
620	if (!cpu_is_omap34xx())
621		return -EINVAL;
622
623	if (!clkdm1 || !clkdm2)
624		return -EINVAL;
625
626	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
627	if (IS_ERR(cd)) {
628		pr_debug("clockdomain: hardware cannot set/clear sleep "
629			 "dependency affecting %s from %s\n", clkdm1->name,
630			 clkdm2->name);
631		return PTR_ERR(cd);
632	}
633
634	if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
635		pr_debug("clockdomain: will prevent %s from sleeping if %s "
636			 "is active\n", clkdm1->name, clkdm2->name);
637
638		cm_set_mod_reg_bits((1 << clkdm2->dep_bit),
639				    clkdm1->pwrdm.ptr->prcm_offs,
640				    OMAP3430_CM_SLEEPDEP);
641	}
642
643	return 0;
644}
645
646/**
647 * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1
648 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
649 * @clkdm2: when this struct clockdomain * is active (source)
650 *
651 * Allow @clkdm1 to automatically go inactive (and then to retention or
652 * off), independent of the activity state of @clkdm2.  Returns -EINVAL
653 * if presented with invalid clockdomain pointers or called on a machine
654 * that does not support software-configurable hardware sleep dependencies,
655 * -ENOENT if the specified dependency cannot be cleared in hardware, or
656 * 0 upon success.
657 */
658int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
659{
660	struct clkdm_dep *cd;
661
662	if (!cpu_is_omap34xx())
663		return -EINVAL;
664
665	if (!clkdm1 || !clkdm2)
666		return -EINVAL;
667
668	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
669	if (IS_ERR(cd)) {
670		pr_debug("clockdomain: hardware cannot set/clear sleep "
671			 "dependency affecting %s from %s\n", clkdm1->name,
672			 clkdm2->name);
673		return PTR_ERR(cd);
674	}
675
676	if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
677		pr_debug("clockdomain: will no longer prevent %s from "
678			 "sleeping if %s is active\n", clkdm1->name,
679			 clkdm2->name);
680
681		cm_clear_mod_reg_bits((1 << clkdm2->dep_bit),
682				      clkdm1->pwrdm.ptr->prcm_offs,
683				      OMAP3430_CM_SLEEPDEP);
684	}
685
686	return 0;
687}
688
689/**
690 * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1
691 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
692 * @clkdm2: when this struct clockdomain * is active (source)
693 *
694 * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will
695 * not be allowed to automatically go inactive if @clkdm2 is active;
696 * 0 if @clkdm1's automatic power state inactivity transition is independent
697 * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called
698 * on a machine that does not support software-configurable hardware sleep
699 * dependencies; or -ENOENT if the hardware is incapable.
700 *
701 * REVISIT: Currently this function only represents software-controllable
702 * sleep dependencies.	Sleep dependencies fixed in hardware are not
703 * yet handled here.
704 */
705int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
706{
707	struct clkdm_dep *cd;
708
709	if (!cpu_is_omap34xx())
710		return -EINVAL;
711
712	if (!clkdm1 || !clkdm2)
713		return -EINVAL;
714
715	cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
716	if (IS_ERR(cd)) {
717		pr_debug("clockdomain: hardware cannot set/clear sleep "
718			 "dependency affecting %s from %s\n", clkdm1->name,
719			 clkdm2->name);
720		return PTR_ERR(cd);
721	}
722
723	return prm_read_mod_bits_shift(clkdm1->pwrdm.ptr->prcm_offs,
724				       OMAP3430_CM_SLEEPDEP,
725				       (1 << clkdm2->dep_bit));
726}
727
728/**
729 * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm
730 * @clkdm: struct clockdomain * to remove all sleep dependencies from
731 *
732 * Remove all inter-clockdomain sleep dependencies that could prevent
733 * @clkdm from idling.  Intended to be used during boot to initialize the
734 * PRCM to a known state, after all clockdomains are put into swsup idle
735 * and woken up.  Returns -EINVAL if @clkdm pointer is invalid, or
736 * 0 upon success.
737 */
738int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
739{
740	struct clkdm_dep *cd;
741	u32 mask = 0;
742
743	if (!cpu_is_omap34xx())
744		return -EINVAL;
745
746	if (!clkdm)
747		return -EINVAL;
748
749	for (cd = clkdm->sleepdep_srcs; cd && cd->clkdm_name; cd++) {
750		if (!omap_chip_is(cd->omap_chip))
751			continue;
752
753		/* PRM accesses are slow, so minimize them */
754		mask |= 1 << cd->clkdm->dep_bit;
755		atomic_set(&cd->sleepdep_usecount, 0);
756	}
757
758	prm_clear_mod_reg_bits(mask, clkdm->pwrdm.ptr->prcm_offs,
759			       OMAP3430_CM_SLEEPDEP);
760
761	return 0;
762}
763
764/**
765 * omap2_clkdm_clktrctrl_read - read the clkdm's current state transition mode
766 * @clkdm: struct clkdm * of a clockdomain
767 *
768 * Return the clockdomain @clkdm current state transition mode from the
769 * corresponding domain CM_CLKSTCTRL register.	Returns -EINVAL if @clkdm
770 * is NULL or the current mode upon success.
771 */
772static int omap2_clkdm_clktrctrl_read(struct clockdomain *clkdm)
773{
774	u32 v;
775
776	if (!clkdm)
777		return -EINVAL;
778
779	v = __raw_readl(clkdm->clkstctrl_reg);
780	v &= clkdm->clktrctrl_mask;
781	v >>= __ffs(clkdm->clktrctrl_mask);
782
783	return v;
784}
785
786/**
787 * omap2_clkdm_sleep - force clockdomain sleep transition
788 * @clkdm: struct clockdomain *
789 *
790 * Instruct the CM to force a sleep transition on the specified
791 * clockdomain @clkdm.  Returns -EINVAL if @clkdm is NULL or if
792 * clockdomain does not support software-initiated sleep; 0 upon
793 * success.
794 */
795int omap2_clkdm_sleep(struct clockdomain *clkdm)
796{
797	if (!clkdm)
798		return -EINVAL;
799
800	if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
801		pr_debug("clockdomain: %s does not support forcing "
802			 "sleep via software\n", clkdm->name);
803		return -EINVAL;
804	}
805
806	pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
807
808	if (cpu_is_omap24xx()) {
809
810		cm_set_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
811			    clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
812
813	} else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
814
815		u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_SLEEP <<
816			 __ffs(clkdm->clktrctrl_mask));
817
818		u32 v = __raw_readl(clkdm->clkstctrl_reg);
819		v &= ~(clkdm->clktrctrl_mask);
820		v |= bits;
821		__raw_writel(v, clkdm->clkstctrl_reg);
822
823	} else {
824		BUG();
825	};
826
827	return 0;
828}
829
830/**
831 * omap2_clkdm_wakeup - force clockdomain wakeup transition
832 * @clkdm: struct clockdomain *
833 *
834 * Instruct the CM to force a wakeup transition on the specified
835 * clockdomain @clkdm.  Returns -EINVAL if @clkdm is NULL or if the
836 * clockdomain does not support software-controlled wakeup; 0 upon
837 * success.
838 */
839int omap2_clkdm_wakeup(struct clockdomain *clkdm)
840{
841	if (!clkdm)
842		return -EINVAL;
843
844	if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
845		pr_debug("clockdomain: %s does not support forcing "
846			 "wakeup via software\n", clkdm->name);
847		return -EINVAL;
848	}
849
850	pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
851
852	if (cpu_is_omap24xx()) {
853
854		cm_clear_mod_reg_bits(OMAP24XX_FORCESTATE_MASK,
855			      clkdm->pwrdm.ptr->prcm_offs, OMAP2_PM_PWSTCTRL);
856
857	} else if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
858
859		u32 bits = (OMAP34XX_CLKSTCTRL_FORCE_WAKEUP <<
860			 __ffs(clkdm->clktrctrl_mask));
861
862		u32 v = __raw_readl(clkdm->clkstctrl_reg);
863		v &= ~(clkdm->clktrctrl_mask);
864		v |= bits;
865		__raw_writel(v, clkdm->clkstctrl_reg);
866
867	} else {
868		BUG();
869	};
870
871	return 0;
872}
873
874/**
875 * omap2_clkdm_allow_idle - enable hwsup idle transitions for clkdm
876 * @clkdm: struct clockdomain *
877 *
878 * Allow the hardware to automatically switch the clockdomain @clkdm into
879 * active or idle states, as needed by downstream clocks.  If the
880 * clockdomain has any downstream clocks enabled in the clock
881 * framework, wkdep/sleepdep autodependencies are added; this is so
882 * device drivers can read and write to the device.  No return value.
883 */
884void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
885{
886	if (!clkdm)
887		return;
888
889	if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
890		pr_debug("clock: automatic idle transitions cannot be enabled "
891			 "on clockdomain %s\n", clkdm->name);
892		return;
893	}
894
895	pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
896		 clkdm->name);
897
898	if (cpu_is_omap44xx()) {
899		WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
900			  "support is not yet implemented\n");
901	} else {
902		if (atomic_read(&clkdm->usecount) > 0)
903			_clkdm_add_autodeps(clkdm);
904	}
905
906	_omap2_clkdm_set_hwsup(clkdm, 1);
907
908	pwrdm_clkdm_state_switch(clkdm);
909}
910
911/**
912 * omap2_clkdm_deny_idle - disable hwsup idle transitions for clkdm
913 * @clkdm: struct clockdomain *
914 *
915 * Prevent the hardware from automatically switching the clockdomain
916 * @clkdm into inactive or idle states.  If the clockdomain has
917 * downstream clocks enabled in the clock framework, wkdep/sleepdep
918 * autodependencies are removed.  No return value.
919 */
920void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
921{
922	if (!clkdm)
923		return;
924
925	if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
926		pr_debug("clockdomain: automatic idle transitions cannot be "
927			 "disabled on %s\n", clkdm->name);
928		return;
929	}
930
931	pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
932		 clkdm->name);
933
934	_omap2_clkdm_set_hwsup(clkdm, 0);
935
936	if (cpu_is_omap44xx()) {
937		WARN_ONCE(1, "clockdomain: OMAP4 wakeup/sleep dependency "
938			  "support is not yet implemented\n");
939	} else {
940		if (atomic_read(&clkdm->usecount) > 0)
941			_clkdm_del_autodeps(clkdm);
942	}
943}
944
945
946/* Clockdomain-to-clock framework interface code */
947
948/**
949 * omap2_clkdm_clk_enable - add an enabled downstream clock to this clkdm
950 * @clkdm: struct clockdomain *
951 * @clk: struct clk * of the enabled downstream clock
952 *
953 * Increment the usecount of the clockdomain @clkdm and ensure that it
954 * is awake before @clk is enabled.  Intended to be called by
955 * clk_enable() code.  If the clockdomain is in software-supervised
956 * idle mode, force the clockdomain to wake.  If the clockdomain is in
957 * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
958 * ensure that devices in the clockdomain can be read from/written to
959 * by on-chip processors.  Returns -EINVAL if passed null pointers;
960 * returns 0 upon success or if the clockdomain is in hwsup idle mode.
961 */
962int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
963{
964	int v;
965
966
967	if (!clkdm || !clk)
968		return -EINVAL;
969
970	if (atomic_inc_return(&clkdm->usecount) > 1)
971		return 0;
972
973	/* Clockdomain now has one enabled downstream clock */
974
975	pr_debug("clockdomain: clkdm %s: clk %s now enabled\n", clkdm->name,
976		 clk->name);
977
978	if (!clkdm->clkstctrl_reg)
979		return 0;
980
981	v = omap2_clkdm_clktrctrl_read(clkdm);
982
983	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
984	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
985		/* Disable HW transitions when we are changing deps */
986		_omap2_clkdm_set_hwsup(clkdm, 0);
987		_clkdm_add_autodeps(clkdm);
988		_omap2_clkdm_set_hwsup(clkdm, 1);
989	} else {
990		omap2_clkdm_wakeup(clkdm);
991	}
992
993	pwrdm_wait_transition(clkdm->pwrdm.ptr);
994	pwrdm_clkdm_state_switch(clkdm);
995
996	return 0;
997}
998
999/**
1000 * omap2_clkdm_clk_disable - remove an enabled downstream clock from this clkdm
1001 * @clkdm: struct clockdomain *
1002 * @clk: struct clk * of the disabled downstream clock
1003 *
1004 * Decrement the usecount of this clockdomain @clkdm when @clk is
1005 * disabled.  Intended to be called by clk_disable() code.  If the
1006 * clockdomain usecount goes to 0, put the clockdomain to sleep
1007 * (software-supervised mode) or remove the clkdm autodependencies
1008 * (hardware-supervised mode).  Returns -EINVAL if passed null
1009 * pointers; -ERANGE if the @clkdm usecount underflows and debugging
1010 * is enabled; or returns 0 upon success or if the clockdomain is in
1011 * hwsup idle mode.
1012 */
1013int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1014{
1015	int v;
1016
1017
1018	if (!clkdm || !clk)
1019		return -EINVAL;
1020
1021#ifdef DEBUG
1022	if (atomic_read(&clkdm->usecount) == 0) {
1023		WARN_ON(1); /* underflow */
1024		return -ERANGE;
1025	}
1026#endif
1027
1028	if (atomic_dec_return(&clkdm->usecount) > 0)
1029		return 0;
1030
1031	/* All downstream clocks of this clockdomain are now disabled */
1032
1033	pr_debug("clockdomain: clkdm %s: clk %s now disabled\n", clkdm->name,
1034		 clk->name);
1035
1036	if (!clkdm->clkstctrl_reg)
1037		return 0;
1038
1039	v = omap2_clkdm_clktrctrl_read(clkdm);
1040
1041	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
1042	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
1043		/* Disable HW transitions when we are changing deps */
1044		_omap2_clkdm_set_hwsup(clkdm, 0);
1045		_clkdm_del_autodeps(clkdm);
1046		_omap2_clkdm_set_hwsup(clkdm, 1);
1047	} else {
1048		omap2_clkdm_sleep(clkdm);
1049	}
1050
1051	pwrdm_clkdm_state_switch(clkdm);
1052
1053	return 0;
1054}
1055