vclk.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2024 Neil Armstrong <neil.armstrong@linaro.org>
  4. */
  5. #include <linux/module.h>
  6. #include "vclk.h"
  7. /* The VCLK gate has a supplementary reset bit to pulse after ungating */
  8. static inline struct meson_vclk_gate_data *
  9. clk_get_meson_vclk_gate_data(struct clk_regmap *clk)
  10. {
  11. return (struct meson_vclk_gate_data *)clk->data;
  12. }
  13. static int meson_vclk_gate_enable(struct clk_hw *hw)
  14. {
  15. struct clk_regmap *clk = to_clk_regmap(hw);
  16. struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
  17. meson_parm_write(clk->map, &vclk->enable, 1);
  18. /* Do a reset pulse */
  19. meson_parm_write(clk->map, &vclk->reset, 1);
  20. meson_parm_write(clk->map, &vclk->reset, 0);
  21. return 0;
  22. }
  23. static void meson_vclk_gate_disable(struct clk_hw *hw)
  24. {
  25. struct clk_regmap *clk = to_clk_regmap(hw);
  26. struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
  27. meson_parm_write(clk->map, &vclk->enable, 0);
  28. }
  29. static int meson_vclk_gate_is_enabled(struct clk_hw *hw)
  30. {
  31. struct clk_regmap *clk = to_clk_regmap(hw);
  32. struct meson_vclk_gate_data *vclk = clk_get_meson_vclk_gate_data(clk);
  33. return meson_parm_read(clk->map, &vclk->enable);
  34. }
  35. const struct clk_ops meson_vclk_gate_ops = {
  36. .enable = meson_vclk_gate_enable,
  37. .disable = meson_vclk_gate_disable,
  38. .is_enabled = meson_vclk_gate_is_enabled,
  39. };
  40. EXPORT_SYMBOL_NS_GPL(meson_vclk_gate_ops, CLK_MESON);
  41. /* The VCLK Divider has supplementary reset & enable bits */
  42. static inline struct meson_vclk_div_data *
  43. clk_get_meson_vclk_div_data(struct clk_regmap *clk)
  44. {
  45. return (struct meson_vclk_div_data *)clk->data;
  46. }
  47. static unsigned long meson_vclk_div_recalc_rate(struct clk_hw *hw,
  48. unsigned long prate)
  49. {
  50. struct clk_regmap *clk = to_clk_regmap(hw);
  51. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  52. return divider_recalc_rate(hw, prate, meson_parm_read(clk->map, &vclk->div),
  53. vclk->table, vclk->flags, vclk->div.width);
  54. }
  55. static int meson_vclk_div_determine_rate(struct clk_hw *hw,
  56. struct clk_rate_request *req)
  57. {
  58. struct clk_regmap *clk = to_clk_regmap(hw);
  59. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  60. return divider_determine_rate(hw, req, vclk->table, vclk->div.width,
  61. vclk->flags);
  62. }
  63. static int meson_vclk_div_set_rate(struct clk_hw *hw, unsigned long rate,
  64. unsigned long parent_rate)
  65. {
  66. struct clk_regmap *clk = to_clk_regmap(hw);
  67. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  68. int ret;
  69. ret = divider_get_val(rate, parent_rate, vclk->table, vclk->div.width,
  70. vclk->flags);
  71. if (ret < 0)
  72. return ret;
  73. meson_parm_write(clk->map, &vclk->div, ret);
  74. return 0;
  75. };
  76. static int meson_vclk_div_enable(struct clk_hw *hw)
  77. {
  78. struct clk_regmap *clk = to_clk_regmap(hw);
  79. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  80. /* Unreset the divider when ungating */
  81. meson_parm_write(clk->map, &vclk->reset, 0);
  82. meson_parm_write(clk->map, &vclk->enable, 1);
  83. return 0;
  84. }
  85. static void meson_vclk_div_disable(struct clk_hw *hw)
  86. {
  87. struct clk_regmap *clk = to_clk_regmap(hw);
  88. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  89. /* Reset the divider when gating */
  90. meson_parm_write(clk->map, &vclk->enable, 0);
  91. meson_parm_write(clk->map, &vclk->reset, 1);
  92. }
  93. static int meson_vclk_div_is_enabled(struct clk_hw *hw)
  94. {
  95. struct clk_regmap *clk = to_clk_regmap(hw);
  96. struct meson_vclk_div_data *vclk = clk_get_meson_vclk_div_data(clk);
  97. return meson_parm_read(clk->map, &vclk->enable);
  98. }
  99. const struct clk_ops meson_vclk_div_ops = {
  100. .recalc_rate = meson_vclk_div_recalc_rate,
  101. .determine_rate = meson_vclk_div_determine_rate,
  102. .set_rate = meson_vclk_div_set_rate,
  103. .enable = meson_vclk_div_enable,
  104. .disable = meson_vclk_div_disable,
  105. .is_enabled = meson_vclk_div_is_enabled,
  106. };
  107. EXPORT_SYMBOL_NS_GPL(meson_vclk_div_ops, CLK_MESON);
  108. MODULE_DESCRIPTION("Amlogic vclk clock driver");
  109. MODULE_AUTHOR("Neil Armstrong <neil.armstrong@linaro.org>");
  110. MODULE_LICENSE("GPL");
  111. MODULE_IMPORT_NS(CLK_MESON);