gate.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * OMAP gate clock support
  4. *
  5. * Copyright (C) 2013 Texas Instruments, Inc.
  6. *
  7. * Tero Kristo <[email protected]>
  8. */
  9. #include <linux/clk-provider.h>
  10. #include <linux/slab.h>
  11. #include <linux/io.h>
  12. #include <linux/of.h>
  13. #include <linux/of_address.h>
  14. #include <linux/clk/ti.h>
  15. #include "clock.h"
  16. #undef pr_fmt
  17. #define pr_fmt(fmt) "%s: " fmt, __func__
  18. static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk);
  19. static const struct clk_ops omap_gate_clkdm_clk_ops = {
  20. .init = &omap2_init_clk_clkdm,
  21. .enable = &omap2_clkops_enable_clkdm,
  22. .disable = &omap2_clkops_disable_clkdm,
  23. .restore_context = clk_gate_restore_context,
  24. };
  25. const struct clk_ops omap_gate_clk_ops = {
  26. .init = &omap2_init_clk_clkdm,
  27. .enable = &omap2_dflt_clk_enable,
  28. .disable = &omap2_dflt_clk_disable,
  29. .is_enabled = &omap2_dflt_clk_is_enabled,
  30. .restore_context = clk_gate_restore_context,
  31. };
  32. static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
  33. .init = &omap2_init_clk_clkdm,
  34. .enable = &omap36xx_gate_clk_enable_with_hsdiv_restore,
  35. .disable = &omap2_dflt_clk_disable,
  36. .is_enabled = &omap2_dflt_clk_is_enabled,
  37. .restore_context = clk_gate_restore_context,
  38. };
  39. /**
  40. * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering
  41. * from HSDivider PWRDN problem Implements Errata ID: i556.
  42. * @hw: DPLL output struct clk_hw
  43. *
  44. * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
  45. * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
  46. * valueafter their respective PWRDN bits are set. Any dummy write
  47. * (Any other value different from the Read value) to the
  48. * corresponding CM_CLKSEL register will refresh the dividers.
  49. */
  50. static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *hw)
  51. {
  52. struct clk_omap_divider *parent;
  53. struct clk_hw *parent_hw;
  54. u32 dummy_v, orig_v;
  55. int ret;
  56. /* Clear PWRDN bit of HSDIVIDER */
  57. ret = omap2_dflt_clk_enable(hw);
  58. /* Parent is the x2 node, get parent of parent for the m2 div */
  59. parent_hw = clk_hw_get_parent(clk_hw_get_parent(hw));
  60. parent = to_clk_omap_divider(parent_hw);
  61. /* Restore the dividers */
  62. if (!ret) {
  63. orig_v = ti_clk_ll_ops->clk_readl(&parent->reg);
  64. dummy_v = orig_v;
  65. /* Write any other value different from the Read value */
  66. dummy_v ^= (1 << parent->shift);
  67. ti_clk_ll_ops->clk_writel(dummy_v, &parent->reg);
  68. /* Write the original divider */
  69. ti_clk_ll_ops->clk_writel(orig_v, &parent->reg);
  70. }
  71. return ret;
  72. }
  73. static struct clk *_register_gate(struct device_node *node, const char *name,
  74. const char *parent_name, unsigned long flags,
  75. struct clk_omap_reg *reg, u8 bit_idx,
  76. u8 clk_gate_flags, const struct clk_ops *ops,
  77. const struct clk_hw_omap_ops *hw_ops)
  78. {
  79. struct clk_init_data init = { NULL };
  80. struct clk_hw_omap *clk_hw;
  81. struct clk *clk;
  82. clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
  83. if (!clk_hw)
  84. return ERR_PTR(-ENOMEM);
  85. clk_hw->hw.init = &init;
  86. init.name = name;
  87. init.ops = ops;
  88. memcpy(&clk_hw->enable_reg, reg, sizeof(*reg));
  89. clk_hw->enable_bit = bit_idx;
  90. clk_hw->ops = hw_ops;
  91. clk_hw->flags = clk_gate_flags;
  92. init.parent_names = &parent_name;
  93. init.num_parents = 1;
  94. init.flags = flags;
  95. clk = of_ti_clk_register_omap_hw(node, &clk_hw->hw, name);
  96. if (IS_ERR(clk))
  97. kfree(clk_hw);
  98. return clk;
  99. }
  100. static void __init _of_ti_gate_clk_setup(struct device_node *node,
  101. const struct clk_ops *ops,
  102. const struct clk_hw_omap_ops *hw_ops)
  103. {
  104. struct clk *clk;
  105. const char *parent_name;
  106. struct clk_omap_reg reg;
  107. const char *name;
  108. u8 enable_bit = 0;
  109. u32 val;
  110. u32 flags = 0;
  111. u8 clk_gate_flags = 0;
  112. if (ops != &omap_gate_clkdm_clk_ops) {
  113. if (ti_clk_get_reg_addr(node, 0, &reg))
  114. return;
  115. if (!of_property_read_u32(node, "ti,bit-shift", &val))
  116. enable_bit = val;
  117. }
  118. if (of_clk_get_parent_count(node) != 1) {
  119. pr_err("%pOFn must have 1 parent\n", node);
  120. return;
  121. }
  122. parent_name = of_clk_get_parent_name(node, 0);
  123. if (of_property_read_bool(node, "ti,set-rate-parent"))
  124. flags |= CLK_SET_RATE_PARENT;
  125. if (of_property_read_bool(node, "ti,set-bit-to-disable"))
  126. clk_gate_flags |= INVERT_ENABLE;
  127. name = ti_dt_clk_name(node);
  128. clk = _register_gate(node, name, parent_name, flags, &reg,
  129. enable_bit, clk_gate_flags, ops, hw_ops);
  130. if (!IS_ERR(clk))
  131. of_clk_add_provider(node, of_clk_src_simple_get, clk);
  132. }
  133. static void __init
  134. _of_ti_composite_gate_clk_setup(struct device_node *node,
  135. const struct clk_hw_omap_ops *hw_ops)
  136. {
  137. struct clk_hw_omap *gate;
  138. u32 val = 0;
  139. gate = kzalloc(sizeof(*gate), GFP_KERNEL);
  140. if (!gate)
  141. return;
  142. if (ti_clk_get_reg_addr(node, 0, &gate->enable_reg))
  143. goto cleanup;
  144. of_property_read_u32(node, "ti,bit-shift", &val);
  145. gate->enable_bit = val;
  146. gate->ops = hw_ops;
  147. if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
  148. return;
  149. cleanup:
  150. kfree(gate);
  151. }
  152. static void __init
  153. of_ti_composite_no_wait_gate_clk_setup(struct device_node *node)
  154. {
  155. _of_ti_composite_gate_clk_setup(node, NULL);
  156. }
  157. CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock",
  158. of_ti_composite_no_wait_gate_clk_setup);
  159. #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
  160. static void __init of_ti_composite_interface_clk_setup(struct device_node *node)
  161. {
  162. _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait);
  163. }
  164. CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock",
  165. of_ti_composite_interface_clk_setup);
  166. #endif
  167. static void __init of_ti_composite_gate_clk_setup(struct device_node *node)
  168. {
  169. _of_ti_composite_gate_clk_setup(node, &clkhwops_wait);
  170. }
  171. CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock",
  172. of_ti_composite_gate_clk_setup);
  173. static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node)
  174. {
  175. _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL);
  176. }
  177. CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock",
  178. of_ti_clkdm_gate_clk_setup);
  179. static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node)
  180. {
  181. _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops,
  182. &clkhwops_wait);
  183. }
  184. CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock",
  185. of_ti_hsdiv_gate_clk_setup);
  186. static void __init of_ti_gate_clk_setup(struct device_node *node)
  187. {
  188. _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
  189. }
  190. CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
  191. static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
  192. {
  193. _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait);
  194. }
  195. CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock",
  196. of_ti_wait_gate_clk_setup);
  197. #ifdef CONFIG_ARCH_OMAP3
  198. static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node)
  199. {
  200. _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
  201. &clkhwops_am35xx_ipss_module_wait);
  202. }
  203. CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock",
  204. of_ti_am35xx_gate_clk_setup);
  205. static void __init of_ti_dss_gate_clk_setup(struct device_node *node)
  206. {
  207. _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
  208. &clkhwops_omap3430es2_dss_usbhost_wait);
  209. }
  210. CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock",
  211. of_ti_dss_gate_clk_setup);
  212. #endif