Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clockdomain.c
Go to the documentation of this file.
1 /*
2  * OMAP2/3/4 clockdomain framework functions
3  *
4  * Copyright (C) 2008-2011 Texas Instruments, Inc.
5  * Copyright (C) 2008-2011 Nokia Corporation
6  *
7  * Written by Paul Walmsley and Jouni Högander
8  * Added OMAP4 specific support by Abhijit Pagare <[email protected]>
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/kernel.h>
17 #include <linux/device.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <linux/string.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 <plat/clock.h>
31 #include "clockdomain.h"
32 
33 /* clkdm_list contains all registered struct clockdomains */
34 static LIST_HEAD(clkdm_list);
35 
36 /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
37 static struct clkdm_autodep *autodeps;
38 
39 static struct clkdm_ops *arch_clkdm;
40 
41 /* Private functions */
42 
43 static struct clockdomain *_clkdm_lookup(const char *name)
44 {
45  struct clockdomain *clkdm, *temp_clkdm;
46 
47  if (!name)
48  return NULL;
49 
50  clkdm = NULL;
51 
52  list_for_each_entry(temp_clkdm, &clkdm_list, node) {
53  if (!strcmp(name, temp_clkdm->name)) {
54  clkdm = temp_clkdm;
55  break;
56  }
57  }
58 
59  return clkdm;
60 }
61 
70 static int _clkdm_register(struct clockdomain *clkdm)
71 {
72  struct powerdomain *pwrdm;
73 
74  if (!clkdm || !clkdm->name)
75  return -EINVAL;
76 
77  pwrdm = pwrdm_lookup(clkdm->pwrdm.name);
78  if (!pwrdm) {
79  pr_err("clockdomain: %s: powerdomain %s does not exist\n",
80  clkdm->name, clkdm->pwrdm.name);
81  return -EINVAL;
82  }
83  clkdm->pwrdm.ptr = pwrdm;
84 
85  /* Verify that the clockdomain is not already registered */
86  if (_clkdm_lookup(clkdm->name))
87  return -EEXIST;
88 
89  list_add(&clkdm->node, &clkdm_list);
90 
91  pwrdm_add_clkdm(pwrdm, clkdm);
92 
93  spin_lock_init(&clkdm->lock);
94 
95  pr_debug("clockdomain: registered %s\n", clkdm->name);
96 
97  return 0;
98 }
99 
100 /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */
101 static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm,
102  struct clkdm_dep *deps)
103 {
104  struct clkdm_dep *cd;
105 
106  if (!clkdm || !deps)
107  return ERR_PTR(-EINVAL);
108 
109  for (cd = deps; cd->clkdm_name; cd++) {
110  if (!cd->clkdm && cd->clkdm_name)
111  cd->clkdm = _clkdm_lookup(cd->clkdm_name);
112 
113  if (cd->clkdm == clkdm)
114  break;
115  }
116 
117  if (!cd->clkdm_name)
118  return ERR_PTR(-ENOENT);
119 
120  return cd;
121 }
122 
123 /*
124  * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store
125  * @autodep: struct clkdm_autodep * to resolve
126  *
127  * Resolve autodep clockdomain names to clockdomain pointers via
128  * clkdm_lookup() and store the pointers in the autodep structure. An
129  * "autodep" is a clockdomain sleep/wakeup dependency that is
130  * automatically added and removed whenever clocks in the associated
131  * clockdomain are enabled or disabled (respectively) when the
132  * clockdomain is in hardware-supervised mode. Meant to be called
133  * once at clockdomain layer initialization, since these should remain
134  * fixed for a particular architecture. No return value.
135  *
136  * XXX autodeps are deprecated and should be removed at the earliest
137  * opportunity
138  */
139 static void _autodep_lookup(struct clkdm_autodep *autodep)
140 {
141  struct clockdomain *clkdm;
142 
143  if (!autodep)
144  return;
145 
146  clkdm = clkdm_lookup(autodep->clkdm.name);
147  if (!clkdm) {
148  pr_err("clockdomain: autodeps: clockdomain %s does not exist\n",
149  autodep->clkdm.name);
150  clkdm = ERR_PTR(-ENOENT);
151  }
152  autodep->clkdm.ptr = clkdm;
153 }
154 
155 /*
156  * _clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
157  * @clkdm: struct clockdomain *
158  *
159  * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
160  * in hardware-supervised mode. Meant to be called from clock framework
161  * when a clock inside clockdomain 'clkdm' is enabled. No return value.
162  *
163  * XXX autodeps are deprecated and should be removed at the earliest
164  * opportunity
165  */
166 void _clkdm_add_autodeps(struct clockdomain *clkdm)
167 {
168  struct clkdm_autodep *autodep;
169 
170  if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
171  return;
172 
173  for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
174  if (IS_ERR(autodep->clkdm.ptr))
175  continue;
176 
177  pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
178  clkdm->name, autodep->clkdm.ptr->name);
179 
180  clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
181  clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
182  }
183 }
184 
185 /*
186  * _clkdm_add_autodeps - remove auto sleepdeps/wkdeps from clkdm
187  * @clkdm: struct clockdomain *
188  *
189  * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
190  * in hardware-supervised mode. Meant to be called from clock framework
191  * when a clock inside clockdomain 'clkdm' is disabled. No return value.
192  *
193  * XXX autodeps are deprecated and should be removed at the earliest
194  * opportunity
195  */
196 void _clkdm_del_autodeps(struct clockdomain *clkdm)
197 {
198  struct clkdm_autodep *autodep;
199 
200  if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
201  return;
202 
203  for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
204  if (IS_ERR(autodep->clkdm.ptr))
205  continue;
206 
207  pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
208  clkdm->name, autodep->clkdm.ptr->name);
209 
210  clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
211  clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
212  }
213 }
214 
224 static void _resolve_clkdm_deps(struct clockdomain *clkdm,
225  struct clkdm_dep *clkdm_deps)
226 {
227  struct clkdm_dep *cd;
228 
229  for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) {
230  if (cd->clkdm)
231  continue;
232  cd->clkdm = _clkdm_lookup(cd->clkdm_name);
233 
234  WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen",
235  clkdm->name, cd->clkdm_name);
236  }
237 }
238 
239 /* Public functions */
240 
252 {
253  if (!co)
254  return -EINVAL;
255 
256  if (arch_clkdm)
257  return -EEXIST;
258 
259  arch_clkdm = co;
260 
261  return 0;
262 };
263 
275 {
276  struct clockdomain **c = NULL;
277 
278  if (!arch_clkdm)
279  return -EACCES;
280 
281  if (!cs)
282  return -EINVAL;
283 
284  for (c = cs; *c; c++)
285  _clkdm_register(*c);
286 
287  return 0;
288 }
289 
315 {
316  struct clkdm_autodep *a = NULL;
317 
318  if (list_empty(&clkdm_list))
319  return -EACCES;
320 
321  if (!ia)
322  return -EINVAL;
323 
324  if (autodeps)
325  return -EEXIST;
326 
327  autodeps = ia;
328  for (a = autodeps; a->clkdm.ptr; a++)
329  _autodep_lookup(a);
330 
331  return 0;
332 }
333 
343 {
344  struct clockdomain *clkdm;
345 
346  if (list_empty(&clkdm_list))
347  return -EACCES;
348 
349  list_for_each_entry(clkdm, &clkdm_list, node) {
350  if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
351  clkdm_wakeup(clkdm);
352  else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
353  clkdm_deny_idle(clkdm);
354 
355  _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
356  clkdm_clear_all_wkdeps(clkdm);
357 
358  _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs);
360  }
361 
362  return 0;
363 }
364 
372 struct clockdomain *clkdm_lookup(const char *name)
373 {
374  struct clockdomain *clkdm, *temp_clkdm;
375 
376  if (!name)
377  return NULL;
378 
379  clkdm = NULL;
380 
381  list_for_each_entry(temp_clkdm, &clkdm_list, node) {
382  if (!strcmp(name, temp_clkdm->name)) {
383  clkdm = temp_clkdm;
384  break;
385  }
386  }
387 
388  return clkdm;
389 }
390 
405 int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user),
406  void *user)
407 {
408  struct clockdomain *clkdm;
409  int ret = 0;
410 
411  if (!fn)
412  return -EINVAL;
413 
414  list_for_each_entry(clkdm, &clkdm_list, node) {
415  ret = (*fn)(clkdm, user);
416  if (ret)
417  break;
418  }
419 
420  return ret;
421 }
422 
423 
432 {
433  if (!clkdm)
434  return NULL;
435 
436  return clkdm->pwrdm.ptr;
437 }
438 
439 
440 /* Hardware clockdomain control */
441 
454 int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
455 {
456  struct clkdm_dep *cd;
457  int ret = 0;
458 
459  if (!clkdm1 || !clkdm2)
460  return -EINVAL;
461 
462  cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
463  if (IS_ERR(cd))
464  ret = PTR_ERR(cd);
465 
466  if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep)
467  ret = -EINVAL;
468 
469  if (ret) {
470  pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
471  clkdm1->name, clkdm2->name);
472  return ret;
473  }
474 
475  if (atomic_inc_return(&cd->wkdep_usecount) == 1) {
476  pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n",
477  clkdm1->name, clkdm2->name);
478 
479  ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2);
480  }
481 
482  return ret;
483 }
484 
495 int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
496 {
497  struct clkdm_dep *cd;
498  int ret = 0;
499 
500  if (!clkdm1 || !clkdm2)
501  return -EINVAL;
502 
503  cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
504  if (IS_ERR(cd))
505  ret = PTR_ERR(cd);
506 
507  if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep)
508  ret = -EINVAL;
509 
510  if (ret) {
511  pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
512  clkdm1->name, clkdm2->name);
513  return ret;
514  }
515 
516  if (atomic_dec_return(&cd->wkdep_usecount) == 0) {
517  pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n",
518  clkdm1->name, clkdm2->name);
519 
520  ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2);
521  }
522 
523  return ret;
524 }
525 
540 int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
541 {
542  struct clkdm_dep *cd;
543  int ret = 0;
544 
545  if (!clkdm1 || !clkdm2)
546  return -EINVAL;
547 
548  cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs);
549  if (IS_ERR(cd))
550  ret = PTR_ERR(cd);
551 
552  if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep)
553  ret = -EINVAL;
554 
555  if (ret) {
556  pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n",
557  clkdm1->name, clkdm2->name);
558  return ret;
559  }
560 
561  /* XXX It's faster to return the atomic wkdep_usecount */
562  return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2);
563 }
564 
576 {
577  if (!clkdm)
578  return -EINVAL;
579 
580  if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps)
581  return -EINVAL;
582 
583  return arch_clkdm->clkdm_clear_all_wkdeps(clkdm);
584 }
585 
598 int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
599 {
600  struct clkdm_dep *cd;
601  int ret = 0;
602 
603  if (!clkdm1 || !clkdm2)
604  return -EINVAL;
605 
606  cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
607  if (IS_ERR(cd))
608  ret = PTR_ERR(cd);
609 
610  if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep)
611  ret = -EINVAL;
612 
613  if (ret) {
614  pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
615  clkdm1->name, clkdm2->name);
616  return ret;
617  }
618 
619  if (atomic_inc_return(&cd->sleepdep_usecount) == 1) {
620  pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n",
621  clkdm1->name, clkdm2->name);
622 
623  ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2);
624  }
625 
626  return ret;
627 }
628 
641 int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
642 {
643  struct clkdm_dep *cd;
644  int ret = 0;
645 
646  if (!clkdm1 || !clkdm2)
647  return -EINVAL;
648 
649  cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
650  if (IS_ERR(cd))
651  ret = PTR_ERR(cd);
652 
653  if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep)
654  ret = -EINVAL;
655 
656  if (ret) {
657  pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
658  clkdm1->name, clkdm2->name);
659  return ret;
660  }
661 
662  if (atomic_dec_return(&cd->sleepdep_usecount) == 0) {
663  pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n",
664  clkdm1->name, clkdm2->name);
665 
666  ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2);
667  }
668 
669  return ret;
670 }
671 
688 int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2)
689 {
690  struct clkdm_dep *cd;
691  int ret = 0;
692 
693  if (!clkdm1 || !clkdm2)
694  return -EINVAL;
695 
696  cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs);
697  if (IS_ERR(cd))
698  ret = PTR_ERR(cd);
699 
700  if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep)
701  ret = -EINVAL;
702 
703  if (ret) {
704  pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n",
705  clkdm1->name, clkdm2->name);
706  return ret;
707  }
708 
709  /* XXX It's faster to return the atomic sleepdep_usecount */
710  return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2);
711 }
712 
724 {
725  if (!clkdm)
726  return -EINVAL;
727 
728  if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps)
729  return -EINVAL;
730 
731  return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm);
732 }
733 
743 int clkdm_sleep(struct clockdomain *clkdm)
744 {
745  int ret;
746  unsigned long flags;
747 
748  if (!clkdm)
749  return -EINVAL;
750 
751  if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) {
752  pr_debug("clockdomain: %s does not support forcing sleep via software\n",
753  clkdm->name);
754  return -EINVAL;
755  }
756 
757  if (!arch_clkdm || !arch_clkdm->clkdm_sleep)
758  return -EINVAL;
759 
760  pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
761 
762  spin_lock_irqsave(&clkdm->lock, flags);
764  ret = arch_clkdm->clkdm_sleep(clkdm);
765  spin_unlock_irqrestore(&clkdm->lock, flags);
766  return ret;
767 }
768 
778 int clkdm_wakeup(struct clockdomain *clkdm)
779 {
780  int ret;
781  unsigned long flags;
782 
783  if (!clkdm)
784  return -EINVAL;
785 
786  if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) {
787  pr_debug("clockdomain: %s does not support forcing wakeup via software\n",
788  clkdm->name);
789  return -EINVAL;
790  }
791 
792  if (!arch_clkdm || !arch_clkdm->clkdm_wakeup)
793  return -EINVAL;
794 
795  pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
796 
797  spin_lock_irqsave(&clkdm->lock, flags);
799  ret = arch_clkdm->clkdm_wakeup(clkdm);
800  ret |= pwrdm_state_switch(clkdm->pwrdm.ptr);
801  spin_unlock_irqrestore(&clkdm->lock, flags);
802  return ret;
803 }
804 
815 void clkdm_allow_idle(struct clockdomain *clkdm)
816 {
817  unsigned long flags;
818 
819  if (!clkdm)
820  return;
821 
822  if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
823  pr_debug("clock: %s: automatic idle transitions cannot be enabled\n",
824  clkdm->name);
825  return;
826  }
827 
828  if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
829  return;
830 
831  pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
832  clkdm->name);
833 
834  spin_lock_irqsave(&clkdm->lock, flags);
836  arch_clkdm->clkdm_allow_idle(clkdm);
837  pwrdm_state_switch(clkdm->pwrdm.ptr);
838  spin_unlock_irqrestore(&clkdm->lock, flags);
839 }
840 
850 void clkdm_deny_idle(struct clockdomain *clkdm)
851 {
852  unsigned long flags;
853 
854  if (!clkdm)
855  return;
856 
857  if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
858  pr_debug("clockdomain: %s: automatic idle transitions cannot be disabled\n",
859  clkdm->name);
860  return;
861  }
862 
863  if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
864  return;
865 
866  pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
867  clkdm->name);
868 
869  spin_lock_irqsave(&clkdm->lock, flags);
871  arch_clkdm->clkdm_deny_idle(clkdm);
872  pwrdm_state_switch(clkdm->pwrdm.ptr);
873  spin_unlock_irqrestore(&clkdm->lock, flags);
874 }
875 
887 bool clkdm_in_hwsup(struct clockdomain *clkdm)
888 {
889  bool ret;
890  unsigned long flags;
891 
892  if (!clkdm)
893  return false;
894 
895  spin_lock_irqsave(&clkdm->lock, flags);
896  ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
897  spin_unlock_irqrestore(&clkdm->lock, flags);
898 
899  return ret;
900 }
901 
912 {
913  if (!clkdm)
914  return false;
915 
916  return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false;
917 }
918 
919 /* Clockdomain-to-clock/hwmod framework interface code */
920 
921 static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
922 {
923  unsigned long flags;
924 
925  if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
926  return -EINVAL;
927 
928  spin_lock_irqsave(&clkdm->lock, flags);
929 
930  /*
931  * For arch's with no autodeps, clkcm_clk_enable
932  * should be called for every clock instance or hwmod that is
933  * enabled, so the clkdm can be force woken up.
934  */
935  if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) {
936  spin_unlock_irqrestore(&clkdm->lock, flags);
937  return 0;
938  }
939 
940  arch_clkdm->clkdm_clk_enable(clkdm);
941  pwrdm_state_switch(clkdm->pwrdm.ptr);
942  spin_unlock_irqrestore(&clkdm->lock, flags);
943 
944  pr_debug("clockdomain: %s: enabled\n", clkdm->name);
945 
946  return 0;
947 }
948 
949 static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
950 {
951  unsigned long flags;
952 
953  if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
954  return -EINVAL;
955 
956  spin_lock_irqsave(&clkdm->lock, flags);
957 
958  if (atomic_read(&clkdm->usecount) == 0) {
959  spin_unlock_irqrestore(&clkdm->lock, flags);
960  WARN_ON(1); /* underflow */
961  return -ERANGE;
962  }
963 
964  if (atomic_dec_return(&clkdm->usecount) > 0) {
965  spin_unlock_irqrestore(&clkdm->lock, flags);
966  return 0;
967  }
968 
969  arch_clkdm->clkdm_clk_disable(clkdm);
970  pwrdm_state_switch(clkdm->pwrdm.ptr);
971  spin_unlock_irqrestore(&clkdm->lock, flags);
972 
973  pr_debug("clockdomain: %s: disabled\n", clkdm->name);
974 
975  return 0;
976 }
977 
992 int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
993 {
994  /*
995  * XXX Rewrite this code to maintain a list of enabled
996  * downstream clocks for debugging purposes?
997  */
998 
999  if (!clk)
1000  return -EINVAL;
1001 
1002  return _clkdm_clk_hwmod_enable(clkdm);
1003 }
1004 
1018 int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1019 {
1020  /*
1021  * XXX Rewrite this code to maintain a list of enabled
1022  * downstream clocks for debugging purposes?
1023  */
1024 
1025  if (!clk)
1026  return -EINVAL;
1027 
1028  return _clkdm_clk_hwmod_disable(clkdm);
1029 }
1030 
1046 int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1047 {
1048  /* The clkdm attribute does not exist yet prior OMAP4 */
1049  if (cpu_is_omap24xx() || cpu_is_omap34xx())
1050  return 0;
1051 
1052  /*
1053  * XXX Rewrite this code to maintain a list of enabled
1054  * downstream hwmods for debugging purposes?
1055  */
1056 
1057  if (!oh)
1058  return -EINVAL;
1059 
1060  return _clkdm_clk_hwmod_enable(clkdm);
1061 }
1062 
1077 int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1078 {
1079  /* The clkdm attribute does not exist yet prior OMAP4 */
1080  if (cpu_is_omap24xx() || cpu_is_omap34xx())
1081  return 0;
1082 
1083  /*
1084  * XXX Rewrite this code to maintain a list of enabled
1085  * downstream hwmods for debugging purposes?
1086  */
1087 
1088  if (!oh)
1089  return -EINVAL;
1090 
1091  return _clkdm_clk_hwmod_disable(clkdm);
1092 }
1093