clk-periph.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. const struct clk_ops tegra_clk_periph_ops = {
  89. .get_parent = clk_periph_get_parent,
  90. .set_parent = clk_periph_set_parent,
  91. .recalc_rate = clk_periph_recalc_rate,
  92. .round_rate = clk_periph_round_rate,
  93. .set_rate = clk_periph_set_rate,
  94. .is_enabled = clk_periph_is_enabled,
  95. .enable = clk_periph_enable,
  96. .disable = clk_periph_disable,
  97. };
  98. static const struct clk_ops tegra_clk_periph_nodiv_ops = {
  99. .get_parent = clk_periph_get_parent,
  100. .set_parent = clk_periph_set_parent,
  101. .is_enabled = clk_periph_is_enabled,
  102. .enable = clk_periph_enable,
  103. .disable = clk_periph_disable,
  104. };
  105. static const struct clk_ops tegra_clk_periph_no_gate_ops = {
  106. .get_parent = clk_periph_get_parent,
  107. .set_parent = clk_periph_set_parent,
  108. .recalc_rate = clk_periph_recalc_rate,
  109. .round_rate = clk_periph_round_rate,
  110. .set_rate = clk_periph_set_rate,
  111. };
  112. static struct clk *_tegra_clk_register_periph(const char *name,
  113. const char **parent_names, int num_parents,
  114. struct tegra_clk_periph *periph,
  115. void __iomem *clk_base, u32 offset,
  116. unsigned long flags)
  117. {
  118. struct clk *clk;
  119. struct clk_init_data init;
  120. struct tegra_clk_periph_regs *bank;
  121. bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV);
  122. if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) {
  123. flags |= CLK_SET_RATE_PARENT;
  124. init.ops = &tegra_clk_periph_nodiv_ops;
  125. } else if (periph->gate.flags & TEGRA_PERIPH_NO_GATE)
  126. init.ops = &tegra_clk_periph_no_gate_ops;
  127. else
  128. init.ops = &tegra_clk_periph_ops;
  129. init.name = name;
  130. init.flags = flags;
  131. init.parent_names = parent_names;
  132. init.num_parents = num_parents;
  133. bank = get_reg_bank(periph->gate.clk_num);
  134. if (!bank)
  135. return ERR_PTR(-EINVAL);
  136. /* Data in .init is copied by clk_register(), so stack variable OK */
  137. periph->hw.init = &init;
  138. periph->magic = TEGRA_CLK_PERIPH_MAGIC;
  139. periph->mux.reg = clk_base + offset;
  140. periph->divider.reg = div ? (clk_base + offset) : NULL;
  141. periph->gate.clk_base = clk_base;
  142. periph->gate.regs = bank;
  143. periph->gate.enable_refcnt = periph_clk_enb_refcnt;
  144. clk = clk_register(NULL, &periph->hw);
  145. if (IS_ERR(clk))
  146. return clk;
  147. periph->mux.hw.clk = clk;
  148. periph->divider.hw.clk = div ? clk : NULL;
  149. periph->gate.hw.clk = clk;
  150. return clk;
  151. }
  152. struct clk *tegra_clk_register_periph(const char *name,
  153. const char **parent_names, int num_parents,
  154. struct tegra_clk_periph *periph, void __iomem *clk_base,
  155. u32 offset, unsigned long flags)
  156. {
  157. return _tegra_clk_register_periph(name, parent_names, num_parents,
  158. periph, clk_base, offset, flags);
  159. }
  160. struct clk *tegra_clk_register_periph_nodiv(const char *name,
  161. const char **parent_names, int num_parents,
  162. struct tegra_clk_periph *periph, void __iomem *clk_base,
  163. u32 offset)
  164. {
  165. periph->gate.flags |= TEGRA_PERIPH_NO_DIV;
  166. return _tegra_clk_register_periph(name, parent_names, num_parents,
  167. periph, clk_base, offset, CLK_SET_RATE_PARENT);
  168. }