clockdomain.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * OMAP clockdomain support
  3. *
  4. * Copyright (C) 2013 Texas Instruments, Inc.
  5. *
  6. * Tero Kristo <t-kristo@ti.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. *
  12. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13. * kind, whether express or implied; without even the implied warranty
  14. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. */
  17. #include <linux/clk.h>
  18. #include <linux/clk-provider.h>
  19. #include <linux/slab.h>
  20. #include <linux/of.h>
  21. #include <linux/of_address.h>
  22. #include <linux/clk/ti.h>
  23. #include "clock.h"
  24. #undef pr_fmt
  25. #define pr_fmt(fmt) "%s: " fmt, __func__
  26. /**
  27. * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw
  28. * @hw: struct clk_hw * of the clock being enabled
  29. *
  30. * Increment the usecount of the clockdomain of the clock pointed to
  31. * by @hw; if the usecount is 1, the clockdomain will be "enabled."
  32. * Only needed for clocks that don't use omap2_dflt_clk_enable() as
  33. * their enable function pointer. Passes along the return value of
  34. * clkdm_clk_enable(), -EINVAL if @hw is not associated with a
  35. * clockdomain, or 0 if clock framework-based clockdomain control is
  36. * not implemented.
  37. */
  38. int omap2_clkops_enable_clkdm(struct clk_hw *hw)
  39. {
  40. struct clk_hw_omap *clk;
  41. int ret = 0;
  42. clk = to_clk_hw_omap(hw);
  43. if (unlikely(!clk->clkdm)) {
  44. pr_err("%s: %s: no clkdm set ?!\n", __func__,
  45. clk_hw_get_name(hw));
  46. return -EINVAL;
  47. }
  48. if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
  49. pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
  50. __func__, clk_hw_get_name(hw));
  51. return 0;
  52. }
  53. ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
  54. WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
  55. __func__, clk_hw_get_name(hw), clk->clkdm_name, ret);
  56. return ret;
  57. }
  58. /**
  59. * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
  60. * @hw: struct clk_hw * of the clock being disabled
  61. *
  62. * Decrement the usecount of the clockdomain of the clock pointed to
  63. * by @hw; if the usecount is 0, the clockdomain will be "disabled."
  64. * Only needed for clocks that don't use omap2_dflt_clk_disable() as their
  65. * disable function pointer. No return value.
  66. */
  67. void omap2_clkops_disable_clkdm(struct clk_hw *hw)
  68. {
  69. struct clk_hw_omap *clk;
  70. clk = to_clk_hw_omap(hw);
  71. if (unlikely(!clk->clkdm)) {
  72. pr_err("%s: %s: no clkdm set ?!\n", __func__,
  73. clk_hw_get_name(hw));
  74. return;
  75. }
  76. if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
  77. pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
  78. __func__, clk_hw_get_name(hw));
  79. return;
  80. }
  81. ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
  82. }
  83. /**
  84. * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
  85. * @clk: OMAP clock struct ptr to use
  86. *
  87. * Convert a clockdomain name stored in a struct clk 'clk' into a
  88. * clockdomain pointer, and save it into the struct clk. Intended to be
  89. * called during clk_register(). Returns 0 on success, -EERROR otherwise.
  90. */
  91. int omap2_init_clk_clkdm(struct clk_hw *hw)
  92. {
  93. struct clk_hw_omap *clk = to_clk_hw_omap(hw);
  94. struct clockdomain *clkdm;
  95. const char *clk_name;
  96. if (!clk->clkdm_name)
  97. return 0;
  98. clk_name = __clk_get_name(hw->clk);
  99. clkdm = ti_clk_ll_ops->clkdm_lookup(clk->clkdm_name);
  100. if (clkdm) {
  101. pr_debug("clock: associated clk %s to clkdm %s\n",
  102. clk_name, clk->clkdm_name);
  103. clk->clkdm = clkdm;
  104. } else {
  105. pr_debug("clock: could not associate clk %s to clkdm %s\n",
  106. clk_name, clk->clkdm_name);
  107. }
  108. return 0;
  109. }
  110. static void __init of_ti_clockdomain_setup(struct device_node *node)
  111. {
  112. struct clk *clk;
  113. struct clk_hw *clk_hw;
  114. const char *clkdm_name = node->name;
  115. int i;
  116. unsigned int num_clks;
  117. num_clks = of_clk_get_parent_count(node);
  118. for (i = 0; i < num_clks; i++) {
  119. clk = of_clk_get(node, i);
  120. if (IS_ERR(clk)) {
  121. pr_err("%s: Failed get %pOF' clock nr %d (%ld)\n",
  122. __func__, node, i, PTR_ERR(clk));
  123. continue;
  124. }
  125. clk_hw = __clk_get_hw(clk);
  126. if (!omap2_clk_is_hw_omap(clk_hw)) {
  127. pr_warn("can't setup clkdm for basic clk %s\n",
  128. __clk_get_name(clk));
  129. clk_put(clk);
  130. continue;
  131. }
  132. to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
  133. omap2_init_clk_clkdm(clk_hw);
  134. clk_put(clk);
  135. }
  136. }
  137. static const struct of_device_id ti_clkdm_match_table[] __initconst = {
  138. { .compatible = "ti,clockdomain" },
  139. { }
  140. };
  141. /**
  142. * ti_dt_clockdomains_setup - setup device tree clockdomains
  143. *
  144. * Initializes clockdomain nodes for a SoC. This parses through all the
  145. * nodes with compatible = "ti,clockdomain", and add the clockdomain
  146. * info for all the clocks listed under these. This function shall be
  147. * called after rest of the DT clock init has completed and all
  148. * clock nodes have been registered.
  149. */
  150. void __init ti_dt_clockdomains_setup(void)
  151. {
  152. struct device_node *np;
  153. for_each_matching_node(np, ti_clkdm_match_table) {
  154. of_ti_clockdomain_setup(np);
  155. }
  156. }