clk-regmap.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2018 BayLibre, SAS.
  4. * Author: Jerome Brunet <[email protected]>
  5. */
  6. #include <linux/module.h>
  7. #include "clk-regmap.h"
  8. static int clk_regmap_gate_endisable(struct clk_hw *hw, int enable)
  9. {
  10. struct clk_regmap *clk = to_clk_regmap(hw);
  11. struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
  12. int set = gate->flags & CLK_GATE_SET_TO_DISABLE ? 1 : 0;
  13. set ^= enable;
  14. return regmap_update_bits(clk->map, gate->offset, BIT(gate->bit_idx),
  15. set ? BIT(gate->bit_idx) : 0);
  16. }
  17. static int clk_regmap_gate_enable(struct clk_hw *hw)
  18. {
  19. return clk_regmap_gate_endisable(hw, 1);
  20. }
  21. static void clk_regmap_gate_disable(struct clk_hw *hw)
  22. {
  23. clk_regmap_gate_endisable(hw, 0);
  24. }
  25. static int clk_regmap_gate_is_enabled(struct clk_hw *hw)
  26. {
  27. struct clk_regmap *clk = to_clk_regmap(hw);
  28. struct clk_regmap_gate_data *gate = clk_get_regmap_gate_data(clk);
  29. unsigned int val;
  30. regmap_read(clk->map, gate->offset, &val);
  31. if (gate->flags & CLK_GATE_SET_TO_DISABLE)
  32. val ^= BIT(gate->bit_idx);
  33. val &= BIT(gate->bit_idx);
  34. return val ? 1 : 0;
  35. }
  36. const struct clk_ops clk_regmap_gate_ops = {
  37. .enable = clk_regmap_gate_enable,
  38. .disable = clk_regmap_gate_disable,
  39. .is_enabled = clk_regmap_gate_is_enabled,
  40. };
  41. EXPORT_SYMBOL_GPL(clk_regmap_gate_ops);
  42. const struct clk_ops clk_regmap_gate_ro_ops = {
  43. .is_enabled = clk_regmap_gate_is_enabled,
  44. };
  45. EXPORT_SYMBOL_GPL(clk_regmap_gate_ro_ops);
  46. static unsigned long clk_regmap_div_recalc_rate(struct clk_hw *hw,
  47. unsigned long prate)
  48. {
  49. struct clk_regmap *clk = to_clk_regmap(hw);
  50. struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
  51. unsigned int val;
  52. int ret;
  53. ret = regmap_read(clk->map, div->offset, &val);
  54. if (ret)
  55. /* Gives a hint that something is wrong */
  56. return 0;
  57. val >>= div->shift;
  58. val &= clk_div_mask(div->width);
  59. return divider_recalc_rate(hw, prate, val, div->table, div->flags,
  60. div->width);
  61. }
  62. static int clk_regmap_div_determine_rate(struct clk_hw *hw,
  63. struct clk_rate_request *req)
  64. {
  65. struct clk_regmap *clk = to_clk_regmap(hw);
  66. struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
  67. unsigned int val;
  68. int ret;
  69. /* if read only, just return current value */
  70. if (div->flags & CLK_DIVIDER_READ_ONLY) {
  71. ret = regmap_read(clk->map, div->offset, &val);
  72. if (ret)
  73. return ret;
  74. val >>= div->shift;
  75. val &= clk_div_mask(div->width);
  76. return divider_ro_determine_rate(hw, req, div->table,
  77. div->width, div->flags, val);
  78. }
  79. return divider_determine_rate(hw, req, div->table, div->width,
  80. div->flags);
  81. }
  82. static int clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
  83. unsigned long parent_rate)
  84. {
  85. struct clk_regmap *clk = to_clk_regmap(hw);
  86. struct clk_regmap_div_data *div = clk_get_regmap_div_data(clk);
  87. unsigned int val;
  88. int ret;
  89. ret = divider_get_val(rate, parent_rate, div->table, div->width,
  90. div->flags);
  91. if (ret < 0)
  92. return ret;
  93. val = (unsigned int)ret << div->shift;
  94. return regmap_update_bits(clk->map, div->offset,
  95. clk_div_mask(div->width) << div->shift, val);
  96. };
  97. /* Would prefer clk_regmap_div_ro_ops but clashes with qcom */
  98. const struct clk_ops clk_regmap_divider_ops = {
  99. .recalc_rate = clk_regmap_div_recalc_rate,
  100. .determine_rate = clk_regmap_div_determine_rate,
  101. .set_rate = clk_regmap_div_set_rate,
  102. };
  103. EXPORT_SYMBOL_GPL(clk_regmap_divider_ops);
  104. const struct clk_ops clk_regmap_divider_ro_ops = {
  105. .recalc_rate = clk_regmap_div_recalc_rate,
  106. .determine_rate = clk_regmap_div_determine_rate,
  107. };
  108. EXPORT_SYMBOL_GPL(clk_regmap_divider_ro_ops);
  109. static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
  110. {
  111. struct clk_regmap *clk = to_clk_regmap(hw);
  112. struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
  113. unsigned int val;
  114. int ret;
  115. ret = regmap_read(clk->map, mux->offset, &val);
  116. if (ret)
  117. return ret;
  118. val >>= mux->shift;
  119. val &= mux->mask;
  120. return clk_mux_val_to_index(hw, mux->table, mux->flags, val);
  121. }
  122. static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
  123. {
  124. struct clk_regmap *clk = to_clk_regmap(hw);
  125. struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
  126. unsigned int val = clk_mux_index_to_val(mux->table, mux->flags, index);
  127. return regmap_update_bits(clk->map, mux->offset,
  128. mux->mask << mux->shift,
  129. val << mux->shift);
  130. }
  131. static int clk_regmap_mux_determine_rate(struct clk_hw *hw,
  132. struct clk_rate_request *req)
  133. {
  134. struct clk_regmap *clk = to_clk_regmap(hw);
  135. struct clk_regmap_mux_data *mux = clk_get_regmap_mux_data(clk);
  136. return clk_mux_determine_rate_flags(hw, req, mux->flags);
  137. }
  138. const struct clk_ops clk_regmap_mux_ops = {
  139. .get_parent = clk_regmap_mux_get_parent,
  140. .set_parent = clk_regmap_mux_set_parent,
  141. .determine_rate = clk_regmap_mux_determine_rate,
  142. };
  143. EXPORT_SYMBOL_GPL(clk_regmap_mux_ops);
  144. const struct clk_ops clk_regmap_mux_ro_ops = {
  145. .get_parent = clk_regmap_mux_get_parent,
  146. };
  147. EXPORT_SYMBOL_GPL(clk_regmap_mux_ro_ops);
  148. MODULE_DESCRIPTION("Amlogic regmap backed clock driver");
  149. MODULE_AUTHOR("Jerome Brunet <[email protected]>");
  150. MODULE_LICENSE("GPL v2");