clk-periph.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <linux/clk-provider.h>
  17. #include <linux/export.h>
  18. #include <linux/slab.h>
  19. #include <linux/err.h>
  20. #include "clk.h"
  21. static u8 clk_periph_get_parent(struct clk_hw *hw)
  22. {
  23. struct tegra_clk_periph *periph = to_clk_periph(hw);
  24. const struct clk_ops *mux_ops = periph->mux_ops;
  25. struct clk_hw *mux_hw = &periph->mux.hw;
  26. __clk_hw_set_clk(mux_hw, hw);
  27. return mux_ops->get_parent(mux_hw);
  28. }
  29. static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
  30. {
  31. struct tegra_clk_periph *periph = to_clk_periph(hw);
  32. const struct clk_ops *mux_ops = periph->mux_ops;
  33. struct clk_hw *mux_hw = &periph->mux.hw;
  34. __clk_hw_set_clk(mux_hw, hw);
  35. return mux_ops->set_parent(mux_hw, index);
  36. }
  37. static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
  38. unsigned long parent_rate)
  39. {
  40. struct tegra_clk_periph *periph = to_clk_periph(hw);
  41. const struct clk_ops *div_ops = periph->div_ops;
  42. struct clk_hw *div_hw = &periph->divider.hw;
  43. __clk_hw_set_clk(div_hw, hw);
  44. return div_ops->recalc_rate(div_hw, parent_rate);
  45. }
  46. static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
  47. unsigned long *prate)
  48. {
  49. struct tegra_clk_periph *periph = to_clk_periph(hw);
  50. const struct clk_ops *div_ops = periph->div_ops;
  51. struct clk_hw *div_hw = &periph->divider.hw;
  52. __clk_hw_set_clk(div_hw, hw);
  53. return div_ops->round_rate(div_hw, rate, prate);
  54. }
  55. static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
  56. unsigned long parent_rate)
  57. {
  58. struct tegra_clk_periph *periph = to_clk_periph(hw);
  59. const struct clk_ops *div_ops = periph->div_ops;
  60. struct clk_hw *div_hw = &periph->divider.hw;
  61. __clk_hw_set_clk(div_hw, hw);
  62. return div_ops->set_rate(div_hw, rate, parent_rate);
  63. }
  64. static int clk_periph_is_enabled(struct clk_hw *hw)
  65. {
  66. struct tegra_clk_periph *periph = to_clk_periph(hw);
  67. const struct clk_ops *gate_ops = periph->gate_ops;
  68. struct clk_hw *gate_hw = &periph->gate.hw;
  69. __clk_hw_set_clk(gate_hw, hw);
  70. return gate_ops->is_enabled(gate_hw);
  71. }
  72. static int clk_periph_enable(struct clk_hw *hw)
  73. {
  74. struct tegra_clk_periph *periph = to_clk_periph(hw);
  75. const struct clk_ops *gate_ops = periph->gate_ops;
  76. struct clk_hw *gate_hw = &periph->gate.hw;
  77. __clk_hw_set_clk(gate_hw, hw);
  78. return gate_ops->enable(gate_hw);
  79. }
  80. static void clk_periph_disable(struct clk_hw *hw)
  81. {
  82. struct tegra_clk_periph *periph = to_clk_periph(hw);
  83. const struct clk_ops *gate_ops = periph->gate_ops;
  84. struct clk_hw *gate_hw = &periph->gate.hw;
  85. gate_ops->disable(gate_hw);
  86. }
  87. const struct clk_ops tegra_clk_periph_ops = {
  88. .get_parent = clk_periph_get_parent,
  89. .set_parent = clk_periph_set_parent,
  90. .recalc_rate = clk_periph_recalc_rate,
  91. .round_rate = clk_periph_round_rate,
  92. .set_rate = clk_periph_set_rate,
  93. .is_enabled = clk_periph_is_enabled,
  94. .enable = clk_periph_enable,
  95. .disable = clk_periph_disable,
  96. };
  97. static const struct clk_ops tegra_clk_periph_nodiv_ops = {
  98. .get_parent = clk_periph_get_parent,
  99. .set_parent = clk_periph_set_parent,
  100. .is_enabled = clk_periph_is_enabled,
  101. .enable = clk_periph_enable,
  102. .disable = clk_periph_disable,
  103. };
  104. static const struct clk_ops tegra_clk_periph_no_gate_ops = {
  105. .get_parent = clk_periph_get_parent,
  106. .set_parent = clk_periph_set_parent,
  107. .recalc_rate = clk_periph_recalc_rate,
  108. .round_rate = clk_periph_round_rate,
  109. .set_rate = clk_periph_set_rate,
  110. };
  111. static struct clk *_tegra_clk_register_periph(const char *name,
  112. const char **parent_names, int num_parents,
  113. struct tegra_clk_periph *periph,
  114. void __iomem *clk_base, u32 offset,
  115. unsigned long flags)
  116. {
  117. struct clk *clk;
  118. struct clk_init_data init;
  119. struct tegra_clk_periph_regs *bank;
  120. bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV);
  121. if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) {
  122. flags |= CLK_SET_RATE_PARENT;
  123. init.ops = &tegra_clk_periph_nodiv_ops;
  124. } else if (periph->gate.flags & TEGRA_PERIPH_NO_GATE)
  125. init.ops = &tegra_clk_periph_no_gate_ops;
  126. else
  127. init.ops = &tegra_clk_periph_ops;
  128. init.name = name;
  129. init.flags = flags;
  130. init.parent_names = parent_names;
  131. init.num_parents = num_parents;
  132. bank = get_reg_bank(periph->gate.clk_num);
  133. if (!bank)
  134. return ERR_PTR(-EINVAL);
  135. /* Data in .init is copied by clk_register(), so stack variable OK */
  136. periph->hw.init = &init;
  137. periph->magic = TEGRA_CLK_PERIPH_MAGIC;
  138. periph->mux.reg = clk_base + offset;
  139. periph->divider.reg = div ? (clk_base + offset) : NULL;
  140. periph->gate.clk_base = clk_base;
  141. periph->gate.regs = bank;
  142. periph->gate.enable_refcnt = periph_clk_enb_refcnt;
  143. clk = clk_register(NULL, &periph->hw);
  144. if (IS_ERR(clk))
  145. return clk;
  146. periph->mux.hw.clk = clk;
  147. periph->divider.hw.clk = div ? clk : NULL;
  148. periph->gate.hw.clk = clk;
  149. return clk;
  150. }
  151. struct clk *tegra_clk_register_periph(const char *name,
  152. const char **parent_names, int num_parents,
  153. struct tegra_clk_periph *periph, void __iomem *clk_base,
  154. u32 offset, unsigned long flags)
  155. {
  156. return _tegra_clk_register_periph(name, parent_names, num_parents,
  157. periph, clk_base, offset, flags);
  158. }
  159. struct clk *tegra_clk_register_periph_nodiv(const char *name,
  160. const char **parent_names, int num_parents,
  161. struct tegra_clk_periph *periph, void __iomem *clk_base,
  162. u32 offset)
  163. {
  164. periph->gate.flags |= TEGRA_PERIPH_NO_DIV;
  165. return _tegra_clk_register_periph(name, parent_names, num_parents,
  166. periph, clk_base, offset, CLK_SET_RATE_PARENT);
  167. }