sun4i_dotclock.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2016 Free Electrons
  4. * Copyright (C) 2016 NextThing Co
  5. *
  6. * Maxime Ripard <maxime.ripard@free-electrons.com>
  7. */
  8. #include <linux/clk-provider.h>
  9. #include <linux/regmap.h>
  10. #include "sun4i_tcon.h"
  11. #include "sun4i_dotclock.h"
  12. struct sun4i_dclk {
  13. struct clk_hw hw;
  14. struct regmap *regmap;
  15. struct sun4i_tcon *tcon;
  16. };
  17. static inline struct sun4i_dclk *hw_to_dclk(struct clk_hw *hw)
  18. {
  19. return container_of(hw, struct sun4i_dclk, hw);
  20. }
  21. static void sun4i_dclk_disable(struct clk_hw *hw)
  22. {
  23. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  24. regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
  25. BIT(SUN4I_TCON0_DCLK_GATE_BIT), 0);
  26. }
  27. static int sun4i_dclk_enable(struct clk_hw *hw)
  28. {
  29. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  30. return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
  31. BIT(SUN4I_TCON0_DCLK_GATE_BIT),
  32. BIT(SUN4I_TCON0_DCLK_GATE_BIT));
  33. }
  34. static int sun4i_dclk_is_enabled(struct clk_hw *hw)
  35. {
  36. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  37. u32 val;
  38. regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
  39. return val & BIT(SUN4I_TCON0_DCLK_GATE_BIT);
  40. }
  41. static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
  42. unsigned long parent_rate)
  43. {
  44. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  45. u32 val;
  46. regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
  47. val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
  48. val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1;
  49. if (!val)
  50. val = 1;
  51. return parent_rate / val;
  52. }
  53. static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
  54. unsigned long *parent_rate)
  55. {
  56. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  57. struct sun4i_tcon *tcon = dclk->tcon;
  58. unsigned long best_parent = 0;
  59. u8 best_div = 1;
  60. int i;
  61. for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) {
  62. u64 ideal = (u64)rate * i;
  63. unsigned long rounded;
  64. /*
  65. * ideal has overflowed the max value that can be stored in an
  66. * unsigned long, and every clk operation we might do on a
  67. * truncated u64 value will give us incorrect results.
  68. * Let's just stop there since bigger dividers will result in
  69. * the same overflow issue.
  70. */
  71. if (ideal > ULONG_MAX)
  72. goto out;
  73. rounded = clk_hw_round_rate(clk_hw_get_parent(hw),
  74. ideal);
  75. if (rounded == ideal) {
  76. best_parent = rounded;
  77. best_div = i;
  78. goto out;
  79. }
  80. if (abs(rate - rounded / i) <
  81. abs(rate - best_parent / best_div)) {
  82. best_parent = rounded;
  83. best_div = i;
  84. }
  85. }
  86. out:
  87. *parent_rate = best_parent;
  88. return best_parent / best_div;
  89. }
  90. static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
  91. unsigned long parent_rate)
  92. {
  93. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  94. u8 div = parent_rate / rate;
  95. return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
  96. GENMASK(6, 0), div);
  97. }
  98. static int sun4i_dclk_get_phase(struct clk_hw *hw)
  99. {
  100. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  101. u32 val;
  102. regmap_read(dclk->regmap, SUN4I_TCON0_IO_POL_REG, &val);
  103. val >>= 28;
  104. val &= 3;
  105. return val * 120;
  106. }
  107. static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees)
  108. {
  109. struct sun4i_dclk *dclk = hw_to_dclk(hw);
  110. u32 val = degrees / 120;
  111. val <<= 28;
  112. regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG,
  113. GENMASK(29, 28),
  114. val);
  115. return 0;
  116. }
  117. static const struct clk_ops sun4i_dclk_ops = {
  118. .disable = sun4i_dclk_disable,
  119. .enable = sun4i_dclk_enable,
  120. .is_enabled = sun4i_dclk_is_enabled,
  121. .recalc_rate = sun4i_dclk_recalc_rate,
  122. .round_rate = sun4i_dclk_round_rate,
  123. .set_rate = sun4i_dclk_set_rate,
  124. .get_phase = sun4i_dclk_get_phase,
  125. .set_phase = sun4i_dclk_set_phase,
  126. };
  127. int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon)
  128. {
  129. const char *clk_name, *parent_name;
  130. struct clk_init_data init;
  131. struct sun4i_dclk *dclk;
  132. int ret;
  133. parent_name = __clk_get_name(tcon->sclk0);
  134. ret = of_property_read_string_index(dev->of_node,
  135. "clock-output-names", 0,
  136. &clk_name);
  137. if (ret)
  138. return ret;
  139. dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL);
  140. if (!dclk)
  141. return -ENOMEM;
  142. dclk->tcon = tcon;
  143. init.name = clk_name;
  144. init.ops = &sun4i_dclk_ops;
  145. init.parent_names = &parent_name;
  146. init.num_parents = 1;
  147. init.flags = CLK_SET_RATE_PARENT;
  148. dclk->regmap = tcon->regs;
  149. dclk->hw.init = &init;
  150. tcon->dclk = clk_register(dev, &dclk->hw);
  151. if (IS_ERR(tcon->dclk))
  152. return PTR_ERR(tcon->dclk);
  153. return 0;
  154. }
  155. EXPORT_SYMBOL(sun4i_dclk_create);
  156. int sun4i_dclk_free(struct sun4i_tcon *tcon)
  157. {
  158. clk_unregister(tcon->dclk);
  159. return 0;
  160. }
  161. EXPORT_SYMBOL(sun4i_dclk_free);