divider.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Zynq UltraScale+ MPSoC Divider support
  4. *
  5. * Copyright (C) 2016-2018 Xilinx
  6. *
  7. * Adjustable divider clock implementation
  8. */
  9. #include <linux/clk.h>
  10. #include <linux/clk-provider.h>
  11. #include <linux/slab.h>
  12. #include "clk-zynqmp.h"
  13. /*
  14. * DOC: basic adjustable divider clock that cannot gate
  15. *
  16. * Traits of this clock:
  17. * prepare - clk_prepare only ensures that parents are prepared
  18. * enable - clk_enable only ensures that parents are enabled
  19. * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor)
  20. * parent - fixed parent. No clk_set_parent support
  21. */
  22. #define to_zynqmp_clk_divider(_hw) \
  23. container_of(_hw, struct zynqmp_clk_divider, hw)
  24. #define CLK_FRAC BIT(13) /* has a fractional parent */
  25. /**
  26. * struct zynqmp_clk_divider - adjustable divider clock
  27. * @hw: handle between common and hardware-specific interfaces
  28. * @flags: Hardware specific flags
  29. * @clk_id: Id of clock
  30. * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2)
  31. */
  32. struct zynqmp_clk_divider {
  33. struct clk_hw hw;
  34. u8 flags;
  35. u32 clk_id;
  36. u32 div_type;
  37. };
  38. static inline int zynqmp_divider_get_val(unsigned long parent_rate,
  39. unsigned long rate)
  40. {
  41. return DIV_ROUND_CLOSEST(parent_rate, rate);
  42. }
  43. /**
  44. * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock
  45. * @hw: handle between common and hardware-specific interfaces
  46. * @parent_rate: rate of parent clock
  47. *
  48. * Return: 0 on success else error+reason
  49. */
  50. static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
  51. unsigned long parent_rate)
  52. {
  53. struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
  54. const char *clk_name = clk_hw_get_name(hw);
  55. u32 clk_id = divider->clk_id;
  56. u32 div_type = divider->div_type;
  57. u32 div, value;
  58. int ret;
  59. const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  60. ret = eemi_ops->clock_getdivider(clk_id, &div);
  61. if (ret)
  62. pr_warn_once("%s() get divider failed for %s, ret = %d\n",
  63. __func__, clk_name, ret);
  64. if (div_type == TYPE_DIV1)
  65. value = div & 0xFFFF;
  66. else
  67. value = div >> 16;
  68. return DIV_ROUND_UP_ULL(parent_rate, value);
  69. }
  70. /**
  71. * zynqmp_clk_divider_round_rate() - Round rate of divider clock
  72. * @hw: handle between common and hardware-specific interfaces
  73. * @rate: rate of clock to be set
  74. * @prate: rate of parent clock
  75. *
  76. * Return: 0 on success else error+reason
  77. */
  78. static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
  79. unsigned long rate,
  80. unsigned long *prate)
  81. {
  82. struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
  83. const char *clk_name = clk_hw_get_name(hw);
  84. u32 clk_id = divider->clk_id;
  85. u32 div_type = divider->div_type;
  86. u32 bestdiv;
  87. int ret;
  88. const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  89. /* if read only, just return current value */
  90. if (divider->flags & CLK_DIVIDER_READ_ONLY) {
  91. ret = eemi_ops->clock_getdivider(clk_id, &bestdiv);
  92. if (ret)
  93. pr_warn_once("%s() get divider failed for %s, ret = %d\n",
  94. __func__, clk_name, ret);
  95. if (div_type == TYPE_DIV1)
  96. bestdiv = bestdiv & 0xFFFF;
  97. else
  98. bestdiv = bestdiv >> 16;
  99. return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
  100. }
  101. bestdiv = zynqmp_divider_get_val(*prate, rate);
  102. if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) &&
  103. (divider->flags & CLK_FRAC))
  104. bestdiv = rate % *prate ? 1 : bestdiv;
  105. *prate = rate * bestdiv;
  106. return rate;
  107. }
  108. /**
  109. * zynqmp_clk_divider_set_rate() - Set rate of divider clock
  110. * @hw: handle between common and hardware-specific interfaces
  111. * @rate: rate of clock to be set
  112. * @parent_rate: rate of parent clock
  113. *
  114. * Return: 0 on success else error+reason
  115. */
  116. static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
  117. unsigned long parent_rate)
  118. {
  119. struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
  120. const char *clk_name = clk_hw_get_name(hw);
  121. u32 clk_id = divider->clk_id;
  122. u32 div_type = divider->div_type;
  123. u32 value, div;
  124. int ret;
  125. const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
  126. value = zynqmp_divider_get_val(parent_rate, rate);
  127. if (div_type == TYPE_DIV1) {
  128. div = value & 0xFFFF;
  129. div |= 0xffff << 16;
  130. } else {
  131. div = 0xffff;
  132. div |= value << 16;
  133. }
  134. ret = eemi_ops->clock_setdivider(clk_id, div);
  135. if (ret)
  136. pr_warn_once("%s() set divider failed for %s, ret = %d\n",
  137. __func__, clk_name, ret);
  138. return ret;
  139. }
  140. static const struct clk_ops zynqmp_clk_divider_ops = {
  141. .recalc_rate = zynqmp_clk_divider_recalc_rate,
  142. .round_rate = zynqmp_clk_divider_round_rate,
  143. .set_rate = zynqmp_clk_divider_set_rate,
  144. };
  145. /**
  146. * zynqmp_clk_register_divider() - Register a divider clock
  147. * @name: Name of this clock
  148. * @clk_id: Id of clock
  149. * @parents: Name of this clock's parents
  150. * @num_parents: Number of parents
  151. * @nodes: Clock topology node
  152. *
  153. * Return: clock hardware to registered clock divider
  154. */
  155. struct clk_hw *zynqmp_clk_register_divider(const char *name,
  156. u32 clk_id,
  157. const char * const *parents,
  158. u8 num_parents,
  159. const struct clock_topology *nodes)
  160. {
  161. struct zynqmp_clk_divider *div;
  162. struct clk_hw *hw;
  163. struct clk_init_data init;
  164. int ret;
  165. /* allocate the divider */
  166. div = kzalloc(sizeof(*div), GFP_KERNEL);
  167. if (!div)
  168. return ERR_PTR(-ENOMEM);
  169. init.name = name;
  170. init.ops = &zynqmp_clk_divider_ops;
  171. init.flags = nodes->flag;
  172. init.parent_names = parents;
  173. init.num_parents = 1;
  174. /* struct clk_divider assignments */
  175. div->flags = nodes->type_flag;
  176. div->hw.init = &init;
  177. div->clk_id = clk_id;
  178. div->div_type = nodes->type;
  179. hw = &div->hw;
  180. ret = clk_hw_register(NULL, hw);
  181. if (ret) {
  182. kfree(div);
  183. hw = ERR_PTR(ret);
  184. }
  185. return hw;
  186. }
  187. EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider);