clk-periph.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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/export.h>
  19. #include <linux/slab.h>
  20. #include <linux/err.h>
  21. #include "clk.h"
  22. static u8 clk_periph_get_parent(struct clk_hw *hw)
  23. {
  24. struct tegra_clk_periph *periph = to_clk_periph(hw);
  25. const struct clk_ops *mux_ops = periph->mux_ops;
  26. struct clk_hw *mux_hw = &periph->mux.hw;
  27. mux_hw->clk = hw->clk;
  28. return mux_ops->get_parent(mux_hw);
  29. }
  30. static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
  31. {
  32. struct tegra_clk_periph *periph = to_clk_periph(hw);
  33. const struct clk_ops *mux_ops = periph->mux_ops;
  34. struct clk_hw *mux_hw = &periph->mux.hw;
  35. mux_hw->clk = hw->clk;
  36. return mux_ops->set_parent(mux_hw, index);
  37. }
  38. static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
  39. unsigned long parent_rate)
  40. {
  41. struct tegra_clk_periph *periph = to_clk_periph(hw);
  42. const struct clk_ops *div_ops = periph->div_ops;
  43. struct clk_hw *div_hw = &periph->divider.hw;
  44. div_hw->clk = hw->clk;
  45. return div_ops->recalc_rate(div_hw, parent_rate);
  46. }
  47. static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
  48. unsigned long *prate)
  49. {
  50. struct tegra_clk_periph *periph = to_clk_periph(hw);
  51. const struct clk_ops *div_ops = periph->div_ops;
  52. struct clk_hw *div_hw = &periph->divider.hw;
  53. div_hw->clk = hw->clk;
  54. return div_ops->round_rate(div_hw, rate, prate);
  55. }
  56. static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
  57. unsigned long parent_rate)
  58. {
  59. struct tegra_clk_periph *periph = to_clk_periph(hw);
  60. const struct clk_ops *div_ops = periph->div_ops;
  61. struct clk_hw *div_hw = &periph->divider.hw;
  62. div_hw->clk = hw->clk;
  63. return div_ops->set_rate(div_hw, rate, parent_rate);
  64. }
  65. static int clk_periph_is_enabled(struct clk_hw *hw)
  66. {
  67. struct tegra_clk_periph *periph = to_clk_periph(hw);
  68. const struct clk_ops *gate_ops = periph->gate_ops;
  69. struct clk_hw *gate_hw = &periph->gate.hw;
  70. gate_hw->clk = hw->clk;
  71. return gate_ops->is_enabled(gate_hw);
  72. }
  73. static int clk_periph_enable(struct clk_hw *hw)
  74. {
  75. struct tegra_clk_periph *periph = to_clk_periph(hw);
  76. const struct clk_ops *gate_ops = periph->gate_ops;
  77. struct clk_hw *gate_hw = &periph->gate.hw;
  78. gate_hw->clk = hw->clk;
  79. return gate_ops->enable(gate_hw);
  80. }
  81. static void clk_periph_disable(struct clk_hw *hw)
  82. {
  83. struct tegra_clk_periph *periph = to_clk_periph(hw);
  84. const struct clk_ops *gate_ops = periph->gate_ops;
  85. struct clk_hw *gate_hw = &periph->gate.hw;
  86. gate_ops->disable(gate_hw);
  87. }
  88. void tegra_periph_reset_deassert(struct clk *c)
  89. {
  90. struct clk_hw *hw = __clk_get_hw(c);
  91. struct tegra_clk_periph *periph = to_clk_periph(hw);
  92. struct tegra_clk_periph_gate *gate;
  93. if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
  94. gate = to_clk_periph_gate(hw);
  95. if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
  96. WARN_ON(1);
  97. return;
  98. }
  99. } else {
  100. gate = &periph->gate;
  101. }
  102. tegra_periph_reset(gate, 0);
  103. }
  104. EXPORT_SYMBOL(tegra_periph_reset_deassert);
  105. void tegra_periph_reset_assert(struct clk *c)
  106. {
  107. struct clk_hw *hw = __clk_get_hw(c);
  108. struct tegra_clk_periph *periph = to_clk_periph(hw);
  109. struct tegra_clk_periph_gate *gate;
  110. if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) {
  111. gate = to_clk_periph_gate(hw);
  112. if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) {
  113. WARN_ON(1);
  114. return;
  115. }
  116. } else {
  117. gate = &periph->gate;
  118. }
  119. tegra_periph_reset(gate, 1);
  120. }
  121. EXPORT_SYMBOL(tegra_periph_reset_assert);
  122. const struct clk_ops tegra_clk_periph_ops = {
  123. .get_parent = clk_periph_get_parent,
  124. .set_parent = clk_periph_set_parent,
  125. .recalc_rate = clk_periph_recalc_rate,
  126. .round_rate = clk_periph_round_rate,
  127. .set_rate = clk_periph_set_rate,
  128. .is_enabled = clk_periph_is_enabled,
  129. .enable = clk_periph_enable,
  130. .disable = clk_periph_disable,
  131. };
  132. const struct clk_ops tegra_clk_periph_nodiv_ops = {
  133. .get_parent = clk_periph_get_parent,
  134. .set_parent = clk_periph_set_parent,
  135. .is_enabled = clk_periph_is_enabled,
  136. .enable = clk_periph_enable,
  137. .disable = clk_periph_disable,
  138. };
  139. static struct clk *_tegra_clk_register_periph(const char *name,
  140. const char **parent_names, int num_parents,
  141. struct tegra_clk_periph *periph,
  142. void __iomem *clk_base, u32 offset, bool div,
  143. unsigned long flags)
  144. {
  145. struct clk *clk;
  146. struct clk_init_data init;
  147. init.name = name;
  148. init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops;
  149. init.flags = flags;
  150. init.parent_names = parent_names;
  151. init.num_parents = num_parents;
  152. /* Data in .init is copied by clk_register(), so stack variable OK */
  153. periph->hw.init = &init;
  154. periph->magic = TEGRA_CLK_PERIPH_MAGIC;
  155. periph->mux.reg = clk_base + offset;
  156. periph->divider.reg = div ? (clk_base + offset) : NULL;
  157. periph->gate.clk_base = clk_base;
  158. clk = clk_register(NULL, &periph->hw);
  159. if (IS_ERR(clk))
  160. return clk;
  161. periph->mux.hw.clk = clk;
  162. periph->divider.hw.clk = div ? clk : NULL;
  163. periph->gate.hw.clk = clk;
  164. return clk;
  165. }
  166. struct clk *tegra_clk_register_periph(const char *name,
  167. const char **parent_names, int num_parents,
  168. struct tegra_clk_periph *periph, void __iomem *clk_base,
  169. u32 offset, unsigned long flags)
  170. {
  171. return _tegra_clk_register_periph(name, parent_names, num_parents,
  172. periph, clk_base, offset, true, flags);
  173. }
  174. struct clk *tegra_clk_register_periph_nodiv(const char *name,
  175. const char **parent_names, int num_parents,
  176. struct tegra_clk_periph *periph, void __iomem *clk_base,
  177. u32 offset)
  178. {
  179. return _tegra_clk_register_periph(name, parent_names, num_parents,
  180. periph, clk_base, offset, false, CLK_SET_RATE_PARENT);
  181. }