clk-periph.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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.h>
  17. #include <linux/clk-provider.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. mux_hw->clk = hw->clk;
  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. mux_hw->clk = hw->clk;
  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. div_hw->clk = hw->clk;
  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. div_hw->clk = hw->clk;
  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. div_hw->clk = hw->clk;
  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. gate_hw->clk = hw->clk;
  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. gate_hw->clk = hw->clk;
  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. void tegra_periph_reset_deassert(struct clk *c)
  88. {
  89. struct clk_hw *hw = __clk_get_hw(c);
  90. struct tegra_clk_periph *periph = to_clk_periph(hw);
  91. struct tegra_clk_periph_gate *gate;
  92. if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
  93. gate = to_clk_periph_gate(hw);
  94. if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
  95. WARN_ON(1);
  96. return;
  97. }
  98. } else {
  99. gate = &periph->gate;
  100. }
  101. tegra_periph_reset(gate, 0);
  102. }
  103. void tegra_periph_reset_assert(struct clk *c)
  104. {
  105. struct clk_hw *hw = __clk_get_hw(c);
  106. struct tegra_clk_periph *periph = to_clk_periph(hw);
  107. struct tegra_clk_periph_gate *gate;
  108. if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
  109. gate = to_clk_periph_gate(hw);
  110. if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
  111. WARN_ON(1);
  112. return;
  113. }
  114. } else {
  115. gate = &periph->gate;
  116. }
  117. tegra_periph_reset(gate, 1);
  118. }
  119. const struct clk_ops tegra_clk_periph_ops = {
  120. .get_parent = clk_periph_get_parent,
  121. .set_parent = clk_periph_set_parent,
  122. .recalc_rate = clk_periph_recalc_rate,
  123. .round_rate = clk_periph_round_rate,
  124. .set_rate = clk_periph_set_rate,
  125. .is_enabled = clk_periph_is_enabled,
  126. .enable = clk_periph_enable,
  127. .disable = clk_periph_disable,
  128. };
  129. const struct clk_ops tegra_clk_periph_nodiv_ops = {
  130. .get_parent = clk_periph_get_parent,
  131. .set_parent = clk_periph_set_parent,
  132. .is_enabled = clk_periph_is_enabled,
  133. .enable = clk_periph_enable,
  134. .disable = clk_periph_disable,
  135. };
  136. static struct clk *_tegra_clk_register_periph(const char *name,
  137. const char **parent_names, int num_parents,
  138. struct tegra_clk_periph *periph,
  139. void __iomem *clk_base, u32 offset, bool div)
  140. {
  141. struct clk *clk;
  142. struct clk_init_data init;
  143. init.name = name;
  144. init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
  145. init.flags = div ? 0 : CLK_SET_RATE_PARENT;
  146. init.parent_names = parent_names;
  147. init.num_parents = num_parents;
  148. /* Data in .init is copied by clk_register(), so stack variable OK */
  149. periph->hw.init = &init;
  150. periph->magic = TEGRA_CLK_PERIPH_MAGIC;
  151. periph->mux.reg = clk_base + offset;
  152. periph->divider.reg = div ? (clk_base + offset) : NULL;
  153. periph->gate.clk_base = clk_base;
  154. clk = clk_register(NULL, &periph->hw);
  155. if (IS_ERR(clk))
  156. return clk;
  157. periph->mux.hw.clk = clk;
  158. periph->divider.hw.clk = div ? clk : NULL;
  159. periph->gate.hw.clk = clk;
  160. return clk;
  161. }
  162. struct clk *tegra_clk_register_periph(const char *name,
  163. const char **parent_names, int num_parents,
  164. struct tegra_clk_periph *periph, void __iomem *clk_base,
  165. u32 offset)
  166. {
  167. return _tegra_clk_register_periph(name, parent_names, num_parents,
  168. periph, clk_base, offset, true);
  169. }
  170. struct clk *tegra_clk_register_periph_nodiv(const char *name,
  171. const char **parent_names, int num_parents,
  172. struct tegra_clk_periph *periph, void __iomem *clk_base,
  173. u32 offset)
  174. {
  175. return _tegra_clk_register_periph(name, parent_names, num_parents,
  176. periph, clk_base, offset, false);
  177. }