clk-multiplier.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * Copyright (C) 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. */
  8. #include <linux/bitops.h>
  9. #include <linux/clk-provider.h>
  10. #include <linux/err.h>
  11. #include <linux/export.h>
  12. #include <linux/kernel.h>
  13. #include <linux/of.h>
  14. #include <linux/slab.h>
  15. static unsigned long __get_mult(struct clk_multiplier *mult,
  16. unsigned long rate,
  17. unsigned long parent_rate)
  18. {
  19. if (mult->flags & CLK_MULTIPLIER_ROUND_CLOSEST)
  20. return DIV_ROUND_CLOSEST(rate, parent_rate);
  21. return rate / parent_rate;
  22. }
  23. static unsigned long clk_multiplier_recalc_rate(struct clk_hw *hw,
  24. unsigned long parent_rate)
  25. {
  26. struct clk_multiplier *mult = to_clk_multiplier(hw);
  27. unsigned long val;
  28. val = clk_readl(mult->reg) >> mult->shift;
  29. val &= GENMASK(mult->width - 1, 0);
  30. if (!val && mult->flags & CLK_MULTIPLIER_ZERO_BYPASS)
  31. val = 1;
  32. return parent_rate * val;
  33. }
  34. static bool __is_best_rate(unsigned long rate, unsigned long new,
  35. unsigned long best, unsigned long flags)
  36. {
  37. if (flags & CLK_MULTIPLIER_ROUND_CLOSEST)
  38. return abs(rate - new) < abs(rate - best);
  39. return new >= rate && new < best;
  40. }
  41. static unsigned long __bestmult(struct clk_hw *hw, unsigned long rate,
  42. unsigned long *best_parent_rate,
  43. u8 width, unsigned long flags)
  44. {
  45. struct clk_multiplier *mult = to_clk_multiplier(hw);
  46. unsigned long orig_parent_rate = *best_parent_rate;
  47. unsigned long parent_rate, current_rate, best_rate = ~0;
  48. unsigned int i, bestmult = 0;
  49. unsigned int maxmult = (1 << width) - 1;
  50. if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
  51. bestmult = rate / orig_parent_rate;
  52. /* Make sure we don't end up with a 0 multiplier */
  53. if ((bestmult == 0) &&
  54. !(mult->flags & CLK_MULTIPLIER_ZERO_BYPASS))
  55. bestmult = 1;
  56. /* Make sure we don't overflow the multiplier */
  57. if (bestmult > maxmult)
  58. bestmult = maxmult;
  59. return bestmult;
  60. }
  61. for (i = 1; i < maxmult; i++) {
  62. if (rate == orig_parent_rate * i) {
  63. /*
  64. * This is the best case for us if we have a
  65. * perfect match without changing the parent
  66. * rate.
  67. */
  68. *best_parent_rate = orig_parent_rate;
  69. return i;
  70. }
  71. parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
  72. rate / i);
  73. current_rate = parent_rate * i;
  74. if (__is_best_rate(rate, current_rate, best_rate, flags)) {
  75. bestmult = i;
  76. best_rate = current_rate;
  77. *best_parent_rate = parent_rate;
  78. }
  79. }
  80. return bestmult;
  81. }
  82. static long clk_multiplier_round_rate(struct clk_hw *hw, unsigned long rate,
  83. unsigned long *parent_rate)
  84. {
  85. struct clk_multiplier *mult = to_clk_multiplier(hw);
  86. unsigned long factor = __bestmult(hw, rate, parent_rate,
  87. mult->width, mult->flags);
  88. return *parent_rate * factor;
  89. }
  90. static int clk_multiplier_set_rate(struct clk_hw *hw, unsigned long rate,
  91. unsigned long parent_rate)
  92. {
  93. struct clk_multiplier *mult = to_clk_multiplier(hw);
  94. unsigned long factor = __get_mult(mult, rate, parent_rate);
  95. unsigned long flags = 0;
  96. unsigned long val;
  97. if (mult->lock)
  98. spin_lock_irqsave(mult->lock, flags);
  99. else
  100. __acquire(mult->lock);
  101. val = clk_readl(mult->reg);
  102. val &= ~GENMASK(mult->width + mult->shift - 1, mult->shift);
  103. val |= factor << mult->shift;
  104. clk_writel(val, mult->reg);
  105. if (mult->lock)
  106. spin_unlock_irqrestore(mult->lock, flags);
  107. else
  108. __release(mult->lock);
  109. return 0;
  110. }
  111. const struct clk_ops clk_multiplier_ops = {
  112. .recalc_rate = clk_multiplier_recalc_rate,
  113. .round_rate = clk_multiplier_round_rate,
  114. .set_rate = clk_multiplier_set_rate,
  115. };
  116. EXPORT_SYMBOL_GPL(clk_multiplier_ops);