aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clockdomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c569
1 files changed, 378 insertions, 191 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 7faf82d4e85c..2da3b5ec010c 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm)
92 92
93 pwrdm_add_clkdm(pwrdm, clkdm); 93 pwrdm_add_clkdm(pwrdm, clkdm);
94 94
95 spin_lock_init(&clkdm->lock);
96
97 pr_debug("clockdomain: registered %s\n", clkdm->name); 95 pr_debug("clockdomain: registered %s\n", clkdm->name);
98 96
99 return 0; 97 return 0;
@@ -122,7 +120,7 @@ static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
122 return cd; 120 return cd;
123} 121}
124 122
125/* 123/**
126 * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store 124 * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
127 * @autodep: struct clkdm_autodep * to resolve 125 * @autodep: struct clkdm_autodep * to resolve
128 * 126 *
@@ -154,88 +152,206 @@ static void _autodep_lookup(struct clkdm_autodep *autodep)
154 autodep->clkdm.ptr = clkdm; 152 autodep->clkdm.ptr = clkdm;
155} 153}
156 154
157/* 155/**
158 * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable 156 * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms
159 * @clkdm: struct clockdomain * 157 * @clkdm: clockdomain that we are resolving dependencies for
158 * @clkdm_deps: ptr to array of struct clkdm_deps to resolve
160 * 159 *
161 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 160 * Iterates through @clkdm_deps, looking up the struct clockdomain named by
162 * in hardware-supervised mode. Meant to be called from clock framework 161 * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep.
163 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 162 * No return value.
163 */
164static void _resolve_clkdm_deps(struct clockdomain *clkdm,
165 struct clkdm_dep *clkdm_deps)
166{
167 struct clkdm_dep *cd;
168
169 for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
170 if (cd->clkdm)
171 continue;
172 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
173
174 WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
175 clkdm->name, cd->clkdm_name);
176 }
177}
178
179/**
180 * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless)
181 * @clkdm1: wake this struct clockdomain * up (dependent)
182 * @clkdm2: when this struct clockdomain * wakes up (source)
164 * 183 *
165 * XXX autodeps are deprecated and should be removed at the earliest 184 * When the clockdomain represented by @clkdm2 wakes up, wake up
166 * opportunity 185 * @clkdm1. Implemented in hardware on the OMAP, this feature is
186 * designed to reduce wakeup latency of the dependent clockdomain @clkdm1.
187 * Returns -EINVAL if presented with invalid clockdomain pointers,
188 * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon
189 * success.
167 */ 190 */
168void _clkdm_add_autodeps(struct clockdomain *clkdm) 191static int _clkdm_add_wkdep(struct clockdomain *clkdm1,
192 struct clockdomain *clkdm2)
169{ 193{
170 struct clkdm_autodep *autodep; 194 struct clkdm_dep *cd;
195 int ret = 0;
171 196
172 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) 197 if (!clkdm1 || !clkdm2)
173 return; 198 return -EINVAL;
174 199
175 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 200 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
176 if (IS_ERR(autodep->clkdm.ptr)) 201 if (IS_ERR(cd))
177 continue; 202 ret = PTR_ERR(cd);
178 203
179 pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", 204 if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
180 clkdm->name, autodep->clkdm.ptr->name); 205 ret = -EINVAL;
206
207 if (ret) {
208 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
209 clkdm1->name, clkdm2->name);
210 return ret;
211 }
212
213 cd->wkdep_usecount++;
214 if (cd->wkdep_usecount == 1) {
215 pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
216 clkdm1->name, clkdm2->name);
181 217
182 clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); 218 ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
183 clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
184 } 219 }
220
221 return ret;
185} 222}
186 223
187/* 224/**
188 * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm 225 * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless)
189 * @clkdm: struct clockdomain * 226 * @clkdm1: wake this struct clockdomain * up (dependent)
227 * @clkdm2: when this struct clockdomain * wakes up (source)
190 * 228 *
191 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 229 * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2
192 * in hardware-supervised mode. Meant to be called from clock framework 230 * wakes up. Returns -EINVAL if presented with invalid clockdomain
193 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 231 * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or
232 * 0 upon success.
233 */
234static int _clkdm_del_wkdep(struct clockdomain *clkdm1,
235 struct clockdomain *clkdm2)
236{
237 struct clkdm_dep *cd;
238 int ret = 0;
239
240 if (!clkdm1 || !clkdm2)
241 return -EINVAL;
242
243 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
244 if (IS_ERR(cd))
245 ret = PTR_ERR(cd);
246
247 if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
248 ret = -EINVAL;
249
250 if (ret) {
251 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
252 clkdm1->name, clkdm2->name);
253 return ret;
254 }
255
256 cd->wkdep_usecount--;
257 if (cd->wkdep_usecount == 0) {
258 pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
259 clkdm1->name, clkdm2->name);
260
261 ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
262 }
263
264 return ret;
265}
266
267/**
268 * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless)
269 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
270 * @clkdm2: when this struct clockdomain * is active (source)
194 * 271 *
195 * XXX autodeps are deprecated and should be removed at the earliest 272 * Prevent @clkdm1 from automatically going inactive (and then to
196 * opportunity 273 * retention or off) if @clkdm2 is active. Returns -EINVAL if
274 * presented with invalid clockdomain pointers or called on a machine
275 * that does not support software-configurable hardware sleep
276 * dependencies, -ENOENT if the specified dependency cannot be set in
277 * hardware, or 0 upon success.
197 */ 278 */
198void _clkdm_del_autodeps(struct clockdomain *clkdm) 279static int _clkdm_add_sleepdep(struct clockdomain *clkdm1,
280 struct clockdomain *clkdm2)
199{ 281{
200 struct clkdm_autodep *autodep; 282 struct clkdm_dep *cd;
283 int ret = 0;
201 284
202 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) 285 if (!clkdm1 || !clkdm2)
203 return; 286 return -EINVAL;
204 287
205 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 288 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
206 if (IS_ERR(autodep->clkdm.ptr)) 289 if (IS_ERR(cd))
207 continue; 290 ret = PTR_ERR(cd);
208 291
209 pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", 292 if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
210 clkdm->name, autodep->clkdm.ptr->name); 293 ret = -EINVAL;
211 294
212 clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); 295 if (ret) {
213 clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); 296 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
297 clkdm1->name, clkdm2->name);
298 return ret;
299 }
300
301 cd->sleepdep_usecount++;
302 if (cd->sleepdep_usecount == 1) {
303 pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
304 clkdm1->name, clkdm2->name);
305
306 ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
214 } 307 }
308
309 return ret;
215} 310}
216 311
217/** 312/**
218 * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms 313 * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless)
219 * @clkdm: clockdomain that we are resolving dependencies for 314 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent)
220 * @clkdm_deps: ptr to array of struct clkdm_deps to resolve 315 * @clkdm2: when this struct clockdomain * is active (source)
221 * 316 *
222 * Iterates through @clkdm_deps, looking up the struct clockdomain named by 317 * Allow @clkdm1 to automatically go inactive (and then to retention or
223 * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. 318 * off), independent of the activity state of @clkdm2. Returns -EINVAL
224 * No return value. 319 * if presented with invalid clockdomain pointers or called on a machine
320 * that does not support software-configurable hardware sleep dependencies,
321 * -ENOENT if the specified dependency cannot be cleared in hardware, or
322 * 0 upon success.
225 */ 323 */
226static void _resolve_clkdm_deps(struct clockdomain *clkdm, 324static int _clkdm_del_sleepdep(struct clockdomain *clkdm1,
227 struct clkdm_dep *clkdm_deps) 325 struct clockdomain *clkdm2)
228{ 326{
229 struct clkdm_dep *cd; 327 struct clkdm_dep *cd;
328 int ret = 0;
230 329
231 for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { 330 if (!clkdm1 || !clkdm2)
232 if (cd->clkdm) 331 return -EINVAL;
233 continue;
234 cd->clkdm = _clkdm_lookup(cd->clkdm_name);
235 332
236 WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", 333 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
237 clkdm->name, cd->clkdm_name); 334 if (IS_ERR(cd))
335 ret = PTR_ERR(cd);
336
337 if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
338 ret = -EINVAL;
339
340 if (ret) {
341 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
342 clkdm1->name, clkdm2->name);
343 return ret;
238 } 344 }
345
346 cd->sleepdep_usecount--;
347 if (cd->sleepdep_usecount == 0) {
348 pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
349 clkdm1->name, clkdm2->name);
350
351 ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
352 }
353
354 return ret;
239} 355}
240 356
241/* Public functions */ 357/* Public functions */
@@ -456,30 +572,18 @@ struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm)
456int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 572int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
457{ 573{
458 struct clkdm_dep *cd; 574 struct clkdm_dep *cd;
459 int ret = 0; 575 int ret;
460 576
461 if (!clkdm1 || !clkdm2) 577 if (!clkdm1 || !clkdm2)
462 return -EINVAL; 578 return -EINVAL;
463 579
464 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 580 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
465 if (IS_ERR(cd)) 581 if (IS_ERR(cd))
466 ret = PTR_ERR(cd); 582 return PTR_ERR(cd);
467 583
468 if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) 584 pwrdm_lock(cd->clkdm->pwrdm.ptr);
469 ret = -EINVAL; 585 ret = _clkdm_add_wkdep(clkdm1, clkdm2);
470 586 pwrdm_unlock(cd->clkdm->pwrdm.ptr);
471 if (ret) {
472 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
473 clkdm1->name, clkdm2->name);
474 return ret;
475 }
476
477 if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
478 pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
479 clkdm1->name, clkdm2->name);
480
481 ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
482 }
483 587
484 return ret; 588 return ret;
485} 589}
@@ -497,30 +601,18 @@ int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
497int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 601int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
498{ 602{
499 struct clkdm_dep *cd; 603 struct clkdm_dep *cd;
500 int ret = 0; 604 int ret;
501 605
502 if (!clkdm1 || !clkdm2) 606 if (!clkdm1 || !clkdm2)
503 return -EINVAL; 607 return -EINVAL;
504 608
505 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 609 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
506 if (IS_ERR(cd)) 610 if (IS_ERR(cd))
507 ret = PTR_ERR(cd); 611 return PTR_ERR(cd);
508 612
509 if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) 613 pwrdm_lock(cd->clkdm->pwrdm.ptr);
510 ret = -EINVAL; 614 ret = _clkdm_del_wkdep(clkdm1, clkdm2);
511 615 pwrdm_unlock(cd->clkdm->pwrdm.ptr);
512 if (ret) {
513 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
514 clkdm1->name, clkdm2->name);
515 return ret;
516 }
517
518 if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
519 pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
520 clkdm1->name, clkdm2->name);
521
522 ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
523 }
524 616
525 return ret; 617 return ret;
526} 618}
@@ -560,7 +652,7 @@ int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
560 return ret; 652 return ret;
561 } 653 }
562 654
563 /* XXX It's faster to return the atomic wkdep_usecount */ 655 /* XXX It's faster to return the wkdep_usecount */
564 return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); 656 return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
565} 657}
566 658
@@ -600,30 +692,18 @@ int clkdm_clear_all_wkdeps(struct clockdomain *clkdm)
600int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 692int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
601{ 693{
602 struct clkdm_dep *cd; 694 struct clkdm_dep *cd;
603 int ret = 0; 695 int ret;
604 696
605 if (!clkdm1 || !clkdm2) 697 if (!clkdm1 || !clkdm2)
606 return -EINVAL; 698 return -EINVAL;
607 699
608 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 700 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
609 if (IS_ERR(cd)) 701 if (IS_ERR(cd))
610 ret = PTR_ERR(cd); 702 return PTR_ERR(cd);
611 703
612 if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) 704 pwrdm_lock(cd->clkdm->pwrdm.ptr);
613 ret = -EINVAL; 705 ret = _clkdm_add_sleepdep(clkdm1, clkdm2);
614 706 pwrdm_unlock(cd->clkdm->pwrdm.ptr);
615 if (ret) {
616 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
617 clkdm1->name, clkdm2->name);
618 return ret;
619 }
620
621 if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
622 pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
623 clkdm1->name, clkdm2->name);
624
625 ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
626 }
627 707
628 return ret; 708 return ret;
629} 709}
@@ -643,30 +723,18 @@ int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
643int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 723int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
644{ 724{
645 struct clkdm_dep *cd; 725 struct clkdm_dep *cd;
646 int ret = 0; 726 int ret;
647 727
648 if (!clkdm1 || !clkdm2) 728 if (!clkdm1 || !clkdm2)
649 return -EINVAL; 729 return -EINVAL;
650 730
651 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 731 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
652 if (IS_ERR(cd)) 732 if (IS_ERR(cd))
653 ret = PTR_ERR(cd); 733 return PTR_ERR(cd);
654 734
655 if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) 735 pwrdm_lock(cd->clkdm->pwrdm.ptr);
656 ret = -EINVAL; 736 ret = _clkdm_del_sleepdep(clkdm1, clkdm2);
657 737 pwrdm_unlock(cd->clkdm->pwrdm.ptr);
658 if (ret) {
659 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
660 clkdm1->name, clkdm2->name);
661 return ret;
662 }
663
664 if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
665 pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
666 clkdm1->name, clkdm2->name);
667
668 ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
669 }
670 738
671 return ret; 739 return ret;
672} 740}
@@ -708,7 +776,7 @@ int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
708 return ret; 776 return ret;
709 } 777 }
710 778
711 /* XXX It's faster to return the atomic sleepdep_usecount */ 779 /* XXX It's faster to return the sleepdep_usecount */
712 return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); 780 return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
713} 781}
714 782
@@ -734,18 +802,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
734} 802}
735 803
736/** 804/**
737 * clkdm_sleep - force clockdomain sleep transition 805 * clkdm_sleep_nolock - force clockdomain sleep transition (lockless)
738 * @clkdm: struct clockdomain * 806 * @clkdm: struct clockdomain *
739 * 807 *
740 * Instruct the CM to force a sleep transition on the specified 808 * Instruct the CM to force a sleep transition on the specified
741 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if 809 * clockdomain @clkdm. Only for use by the powerdomain code. Returns
742 * clockdomain does not support software-initiated sleep; 0 upon 810 * -EINVAL if @clkdm is NULL or if clockdomain does not support
743 * success. 811 * software-initiated sleep; 0 upon success.
744 */ 812 */
745int clkdm_sleep(struct clockdomain *clkdm) 813int clkdm_sleep_nolock(struct clockdomain *clkdm)
746{ 814{
747 int ret; 815 int ret;
748 unsigned long flags;
749 816
750 if (!clkdm) 817 if (!clkdm)
751 return -EINVAL; 818 return -EINVAL;
@@ -761,26 +828,45 @@ int clkdm_sleep(struct clockdomain *clkdm)
761 828
762 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 829 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
763 830
764 spin_lock_irqsave(&clkdm->lock, flags);
765 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 831 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
766 ret = arch_clkdm->clkdm_sleep(clkdm); 832 ret = arch_clkdm->clkdm_sleep(clkdm);
767 spin_unlock_irqrestore(&clkdm->lock, flags); 833 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
834
768 return ret; 835 return ret;
769} 836}
770 837
771/** 838/**
772 * clkdm_wakeup - force clockdomain wakeup transition 839 * clkdm_sleep - force clockdomain sleep transition
773 * @clkdm: struct clockdomain * 840 * @clkdm: struct clockdomain *
774 * 841 *
775 * Instruct the CM to force a wakeup transition on the specified 842 * Instruct the CM to force a sleep transition on the specified
776 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the 843 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
777 * clockdomain does not support software-controlled wakeup; 0 upon 844 * clockdomain does not support software-initiated sleep; 0 upon
778 * success. 845 * success.
779 */ 846 */
780int clkdm_wakeup(struct clockdomain *clkdm) 847int clkdm_sleep(struct clockdomain *clkdm)
848{
849 int ret;
850
851 pwrdm_lock(clkdm->pwrdm.ptr);
852 ret = clkdm_sleep_nolock(clkdm);
853 pwrdm_unlock(clkdm->pwrdm.ptr);
854
855 return ret;
856}
857
858/**
859 * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless)
860 * @clkdm: struct clockdomain *
861 *
862 * Instruct the CM to force a wakeup transition on the specified
863 * clockdomain @clkdm. Only for use by the powerdomain code. Returns
864 * -EINVAL if @clkdm is NULL or if the clockdomain does not support
865 * software-controlled wakeup; 0 upon success.
866 */
867int clkdm_wakeup_nolock(struct clockdomain *clkdm)
781{ 868{
782 int ret; 869 int ret;
783 unsigned long flags;
784 870
785 if (!clkdm) 871 if (!clkdm)
786 return -EINVAL; 872 return -EINVAL;
@@ -796,28 +882,46 @@ int clkdm_wakeup(struct clockdomain *clkdm)
796 882
797 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 883 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
798 884
799 spin_lock_irqsave(&clkdm->lock, flags);
800 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 885 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
801 ret = arch_clkdm->clkdm_wakeup(clkdm); 886 ret = arch_clkdm->clkdm_wakeup(clkdm);
802 ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); 887 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
803 spin_unlock_irqrestore(&clkdm->lock, flags); 888
804 return ret; 889 return ret;
805} 890}
806 891
807/** 892/**
808 * clkdm_allow_idle - enable hwsup idle transitions for clkdm 893 * clkdm_wakeup - force clockdomain wakeup transition
809 * @clkdm: struct clockdomain * 894 * @clkdm: struct clockdomain *
810 * 895 *
811 * Allow the hardware to automatically switch the clockdomain @clkdm into 896 * Instruct the CM to force a wakeup transition on the specified
812 * active or idle states, as needed by downstream clocks. If the 897 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
898 * clockdomain does not support software-controlled wakeup; 0 upon
899 * success.
900 */
901int clkdm_wakeup(struct clockdomain *clkdm)
902{
903 int ret;
904
905 pwrdm_lock(clkdm->pwrdm.ptr);
906 ret = clkdm_wakeup_nolock(clkdm);
907 pwrdm_unlock(clkdm->pwrdm.ptr);
908
909 return ret;
910}
911
912/**
913 * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm
914 * @clkdm: struct clockdomain *
915 *
916 * Allow the hardware to automatically switch the clockdomain @clkdm
917 * into active or idle states, as needed by downstream clocks. If the
813 * clockdomain has any downstream clocks enabled in the clock 918 * clockdomain has any downstream clocks enabled in the clock
814 * framework, wkdep/sleepdep autodependencies are added; this is so 919 * framework, wkdep/sleepdep autodependencies are added; this is so
815 * device drivers can read and write to the device. No return value. 920 * device drivers can read and write to the device. Only for use by
921 * the powerdomain code. No return value.
816 */ 922 */
817void clkdm_allow_idle(struct clockdomain *clkdm) 923void clkdm_allow_idle_nolock(struct clockdomain *clkdm)
818{ 924{
819 unsigned long flags;
820
821 if (!clkdm) 925 if (!clkdm)
822 return; 926 return;
823 927
@@ -833,11 +937,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
833 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 937 pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
834 clkdm->name); 938 clkdm->name);
835 939
836 spin_lock_irqsave(&clkdm->lock, flags);
837 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; 940 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
838 arch_clkdm->clkdm_allow_idle(clkdm); 941 arch_clkdm->clkdm_allow_idle(clkdm);
839 pwrdm_state_switch(clkdm->pwrdm.ptr); 942 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
840 spin_unlock_irqrestore(&clkdm->lock, flags); 943}
944
945/**
946 * clkdm_allow_idle - enable hwsup idle transitions for clkdm
947 * @clkdm: struct clockdomain *
948 *
949 * Allow the hardware to automatically switch the clockdomain @clkdm into
950 * active or idle states, as needed by downstream clocks. If the
951 * clockdomain has any downstream clocks enabled in the clock
952 * framework, wkdep/sleepdep autodependencies are added; this is so
953 * device drivers can read and write to the device. No return value.
954 */
955void clkdm_allow_idle(struct clockdomain *clkdm)
956{
957 pwrdm_lock(clkdm->pwrdm.ptr);
958 clkdm_allow_idle_nolock(clkdm);
959 pwrdm_unlock(clkdm->pwrdm.ptr);
841} 960}
842 961
843/** 962/**
@@ -847,12 +966,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
847 * Prevent the hardware from automatically switching the clockdomain 966 * Prevent the hardware from automatically switching the clockdomain
848 * @clkdm into inactive or idle states. If the clockdomain has 967 * @clkdm into inactive or idle states. If the clockdomain has
849 * downstream clocks enabled in the clock framework, wkdep/sleepdep 968 * downstream clocks enabled in the clock framework, wkdep/sleepdep
850 * autodependencies are removed. No return value. 969 * autodependencies are removed. Only for use by the powerdomain
970 * code. No return value.
851 */ 971 */
852void clkdm_deny_idle(struct clockdomain *clkdm) 972void clkdm_deny_idle_nolock(struct clockdomain *clkdm)
853{ 973{
854 unsigned long flags;
855
856 if (!clkdm) 974 if (!clkdm)
857 return; 975 return;
858 976
@@ -868,11 +986,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
868 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 986 pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
869 clkdm->name); 987 clkdm->name);
870 988
871 spin_lock_irqsave(&clkdm->lock, flags);
872 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 989 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
873 arch_clkdm->clkdm_deny_idle(clkdm); 990 arch_clkdm->clkdm_deny_idle(clkdm);
874 pwrdm_state_switch(clkdm->pwrdm.ptr); 991 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
875 spin_unlock_irqrestore(&clkdm->lock, flags); 992}
993
994/**
995 * clkdm_deny_idle - disable hwsup idle transitions for clkdm
996 * @clkdm: struct clockdomain *
997 *
998 * Prevent the hardware from automatically switching the clockdomain
999 * @clkdm into inactive or idle states. If the clockdomain has
1000 * downstream clocks enabled in the clock framework, wkdep/sleepdep
1001 * autodependencies are removed. No return value.
1002 */
1003void clkdm_deny_idle(struct clockdomain *clkdm)
1004{
1005 pwrdm_lock(clkdm->pwrdm.ptr);
1006 clkdm_deny_idle_nolock(clkdm);
1007 pwrdm_unlock(clkdm->pwrdm.ptr);
876} 1008}
877 1009
878/** 1010/**
@@ -889,14 +1021,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
889bool clkdm_in_hwsup(struct clockdomain *clkdm) 1021bool clkdm_in_hwsup(struct clockdomain *clkdm)
890{ 1022{
891 bool ret; 1023 bool ret;
892 unsigned long flags;
893 1024
894 if (!clkdm) 1025 if (!clkdm)
895 return false; 1026 return false;
896 1027
897 spin_lock_irqsave(&clkdm->lock, flags);
898 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; 1028 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
899 spin_unlock_irqrestore(&clkdm->lock, flags);
900 1029
901 return ret; 1030 return ret;
902} 1031}
@@ -918,30 +1047,91 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm)
918 return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; 1047 return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false;
919} 1048}
920 1049
1050/* Public autodep handling functions (deprecated) */
1051
1052/**
1053 * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
1054 * @clkdm: struct clockdomain *
1055 *
1056 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
1057 * in hardware-supervised mode. Meant to be called from clock framework
1058 * when a clock inside clockdomain 'clkdm' is enabled. No return value.
1059 *
1060 * XXX autodeps are deprecated and should be removed at the earliest
1061 * opportunity
1062 */
1063void clkdm_add_autodeps(struct clockdomain *clkdm)
1064{
1065 struct clkdm_autodep *autodep;
1066
1067 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
1068 return;
1069
1070 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
1071 if (IS_ERR(autodep->clkdm.ptr))
1072 continue;
1073
1074 pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
1075 clkdm->name, autodep->clkdm.ptr->name);
1076
1077 _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
1078 _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
1079 }
1080}
1081
1082/**
1083 * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm
1084 * @clkdm: struct clockdomain *
1085 *
1086 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
1087 * in hardware-supervised mode. Meant to be called from clock framework
1088 * when a clock inside clockdomain 'clkdm' is disabled. No return value.
1089 *
1090 * XXX autodeps are deprecated and should be removed at the earliest
1091 * opportunity
1092 */
1093void clkdm_del_autodeps(struct clockdomain *clkdm)
1094{
1095 struct clkdm_autodep *autodep;
1096
1097 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
1098 return;
1099
1100 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
1101 if (IS_ERR(autodep->clkdm.ptr))
1102 continue;
1103
1104 pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
1105 clkdm->name, autodep->clkdm.ptr->name);
1106
1107 _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
1108 _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
1109 }
1110}
1111
921/* Clockdomain-to-clock/hwmod framework interface code */ 1112/* Clockdomain-to-clock/hwmod framework interface code */
922 1113
923static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) 1114static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
924{ 1115{
925 unsigned long flags;
926
927 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) 1116 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
928 return -EINVAL; 1117 return -EINVAL;
929 1118
930 spin_lock_irqsave(&clkdm->lock, flags); 1119 pwrdm_lock(clkdm->pwrdm.ptr);
931 1120
932 /* 1121 /*
933 * For arch's with no autodeps, clkcm_clk_enable 1122 * For arch's with no autodeps, clkcm_clk_enable
934 * should be called for every clock instance or hwmod that is 1123 * should be called for every clock instance or hwmod that is
935 * enabled, so the clkdm can be force woken up. 1124 * enabled, so the clkdm can be force woken up.
936 */ 1125 */
937 if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { 1126 clkdm->usecount++;
938 spin_unlock_irqrestore(&clkdm->lock, flags); 1127 if (clkdm->usecount > 1 && autodeps) {
1128 pwrdm_unlock(clkdm->pwrdm.ptr);
939 return 0; 1129 return 0;
940 } 1130 }
941 1131
942 arch_clkdm->clkdm_clk_enable(clkdm); 1132 arch_clkdm->clkdm_clk_enable(clkdm);
943 pwrdm_state_switch(clkdm->pwrdm.ptr); 1133 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
944 spin_unlock_irqrestore(&clkdm->lock, flags); 1134 pwrdm_unlock(clkdm->pwrdm.ptr);
945 1135
946 pr_debug("clockdomain: %s: enabled\n", clkdm->name); 1136 pr_debug("clockdomain: %s: enabled\n", clkdm->name);
947 1137
@@ -990,36 +1180,34 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
990 */ 1180 */
991int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 1181int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
992{ 1182{
993 unsigned long flags;
994
995 if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1183 if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
996 return -EINVAL; 1184 return -EINVAL;
997 1185
998 spin_lock_irqsave(&clkdm->lock, flags); 1186 pwrdm_lock(clkdm->pwrdm.ptr);
999 1187
1000 /* corner case: disabling unused clocks */ 1188 /* corner case: disabling unused clocks */
1001 if ((__clk_get_enable_count(clk) == 0) && 1189 if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
1002 (atomic_read(&clkdm->usecount) == 0))
1003 goto ccd_exit; 1190 goto ccd_exit;
1004 1191
1005 if (atomic_read(&clkdm->usecount) == 0) { 1192 if (clkdm->usecount == 0) {
1006 spin_unlock_irqrestore(&clkdm->lock, flags); 1193 pwrdm_unlock(clkdm->pwrdm.ptr);
1007 WARN_ON(1); /* underflow */ 1194 WARN_ON(1); /* underflow */
1008 return -ERANGE; 1195 return -ERANGE;
1009 } 1196 }
1010 1197
1011 if (atomic_dec_return(&clkdm->usecount) > 0) { 1198 clkdm->usecount--;
1012 spin_unlock_irqrestore(&clkdm->lock, flags); 1199 if (clkdm->usecount > 0) {
1200 pwrdm_unlock(clkdm->pwrdm.ptr);
1013 return 0; 1201 return 0;
1014 } 1202 }
1015 1203
1016 arch_clkdm->clkdm_clk_disable(clkdm); 1204 arch_clkdm->clkdm_clk_disable(clkdm);
1017 pwrdm_state_switch(clkdm->pwrdm.ptr); 1205 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
1018 1206
1019 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1207 pr_debug("clockdomain: %s: disabled\n", clkdm->name);
1020 1208
1021ccd_exit: 1209ccd_exit:
1022 spin_unlock_irqrestore(&clkdm->lock, flags); 1210 pwrdm_unlock(clkdm->pwrdm.ptr);
1023 1211
1024 return 0; 1212 return 0;
1025} 1213}
@@ -1072,8 +1260,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1072 */ 1260 */
1073int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) 1261int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1074{ 1262{
1075 unsigned long flags;
1076
1077 /* The clkdm attribute does not exist yet prior OMAP4 */ 1263 /* The clkdm attribute does not exist yet prior OMAP4 */
1078 if (cpu_is_omap24xx() || cpu_is_omap34xx()) 1264 if (cpu_is_omap24xx() || cpu_is_omap34xx())
1079 return 0; 1265 return 0;
@@ -1086,22 +1272,23 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1086 if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1272 if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
1087 return -EINVAL; 1273 return -EINVAL;
1088 1274
1089 spin_lock_irqsave(&clkdm->lock, flags); 1275 pwrdm_lock(clkdm->pwrdm.ptr);
1090 1276
1091 if (atomic_read(&clkdm->usecount) == 0) { 1277 if (clkdm->usecount == 0) {
1092 spin_unlock_irqrestore(&clkdm->lock, flags); 1278 pwrdm_unlock(clkdm->pwrdm.ptr);
1093 WARN_ON(1); /* underflow */ 1279 WARN_ON(1); /* underflow */
1094 return -ERANGE; 1280 return -ERANGE;
1095 } 1281 }
1096 1282
1097 if (atomic_dec_return(&clkdm->usecount) > 0) { 1283 clkdm->usecount--;
1098 spin_unlock_irqrestore(&clkdm->lock, flags); 1284 if (clkdm->usecount > 0) {
1285 pwrdm_unlock(clkdm->pwrdm.ptr);
1099 return 0; 1286 return 0;
1100 } 1287 }
1101 1288
1102 arch_clkdm->clkdm_clk_disable(clkdm); 1289 arch_clkdm->clkdm_clk_disable(clkdm);
1103 pwrdm_state_switch(clkdm->pwrdm.ptr); 1290 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
1104 spin_unlock_irqrestore(&clkdm->lock, flags); 1291 pwrdm_unlock(clkdm->pwrdm.ptr);
1105 1292
1106 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1293 pr_debug("clockdomain: %s: disabled\n", clkdm->name);
1107 1294