clockdomain.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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 (unlikely(clk->enable_reg))
  49. pr_err("%s: %s: should use dflt_clk_enable ?!\n", __func__,
  50. clk_hw_get_name(hw));
  51. if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
  52. pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
  53. __func__, clk_hw_get_name(hw));
  54. return 0;
  55. }
  56. ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk);
  57. WARN(ret, "%s: could not enable %s's clockdomain %s: %d\n",
  58. __func__, clk_hw_get_name(hw), clk->clkdm_name, ret);
  59. return ret;
  60. }
  61. /**
  62. * omap2_clkops_disable_clkdm - decrement usecount on clkdm of @hw
  63. * @hw: struct clk_hw * of the clock being disabled
  64. *
  65. * Decrement the usecount of the clockdomain of the clock pointed to
  66. * by @hw; if the usecount is 0, the clockdomain will be "disabled."
  67. * Only needed for clocks that don't use omap2_dflt_clk_disable() as their
  68. * disable function pointer. No return value.
  69. */
  70. void omap2_clkops_disable_clkdm(struct clk_hw *hw)
  71. {
  72. struct clk_hw_omap *clk;
  73. clk = to_clk_hw_omap(hw);
  74. if (unlikely(!clk->clkdm)) {
  75. pr_err("%s: %s: no clkdm set ?!\n", __func__,
  76. clk_hw_get_name(hw));
  77. return;
  78. }
  79. if (unlikely(clk->enable_reg))
  80. pr_err("%s: %s: should use dflt_clk_disable ?!\n", __func__,
  81. clk_hw_get_name(hw));
  82. if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) {
  83. pr_err("%s: %s: clkfw-based clockdomain control disabled ?!\n",
  84. __func__, clk_hw_get_name(hw));
  85. return;
  86. }
  87. ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk);
  88. }
  89. static void __init of_ti_clockdomain_setup(struct device_node *node)
  90. {
  91. struct clk *clk;
  92. struct clk_hw *clk_hw;
  93. const char *clkdm_name = node->name;
  94. int i;
  95. unsigned int num_clks;
  96. num_clks = of_clk_get_parent_count(node);
  97. for (i = 0; i < num_clks; i++) {
  98. clk = of_clk_get(node, i);
  99. if (IS_ERR(clk)) {
  100. pr_err("%s: Failed get %s' clock nr %d (%ld)\n",
  101. __func__, node->full_name, i, PTR_ERR(clk));
  102. continue;
  103. }
  104. clk_hw = __clk_get_hw(clk);
  105. if (clk_hw_get_flags(clk_hw) & CLK_IS_BASIC) {
  106. pr_warn("can't setup clkdm for basic clk %s\n",
  107. __clk_get_name(clk));
  108. continue;
  109. }
  110. to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
  111. omap2_init_clk_clkdm(clk_hw);
  112. }
  113. }
  114. static const struct of_device_id ti_clkdm_match_table[] __initconst = {
  115. { .compatible = "ti,clockdomain" },
  116. { }
  117. };
  118. /**
  119. * ti_dt_clockdomains_setup - setup device tree clockdomains
  120. *
  121. * Initializes clockdomain nodes for a SoC. This parses through all the
  122. * nodes with compatible = "ti,clockdomain", and add the clockdomain
  123. * info for all the clocks listed under these. This function shall be
  124. * called after rest of the DT clock init has completed and all
  125. * clock nodes have been registered.
  126. */
  127. void __init ti_dt_clockdomains_setup(void)
  128. {
  129. struct device_node *np;
  130. for_each_matching_node(np, ti_clkdm_match_table) {
  131. of_ti_clockdomain_setup(np);
  132. }
  133. }