clk-mpll.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * This file is provided under a dual BSD/GPLv2 license. When using or
  3. * redistributing this file, you may do so under either license.
  4. *
  5. * GPL LICENSE SUMMARY
  6. *
  7. * Copyright (c) 2016 AmLogic, Inc.
  8. * Author: Michael Turquette <mturquette@baylibre.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of version 2 of the GNU General Public License as
  12. * published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  22. * The full GNU General Public License is included in this distribution
  23. * in the file called COPYING
  24. *
  25. * BSD LICENSE
  26. *
  27. * Copyright (c) 2016 AmLogic, Inc.
  28. * Author: Michael Turquette <mturquette@baylibre.com>
  29. *
  30. * Redistribution and use in source and binary forms, with or without
  31. * modification, are permitted provided that the following conditions
  32. * are met:
  33. *
  34. * * Redistributions of source code must retain the above copyright
  35. * notice, this list of conditions and the following disclaimer.
  36. * * Redistributions in binary form must reproduce the above copyright
  37. * notice, this list of conditions and the following disclaimer in
  38. * the documentation and/or other materials provided with the
  39. * distribution.
  40. * * Neither the name of Intel Corporation nor the names of its
  41. * contributors may be used to endorse or promote products derived
  42. * from this software without specific prior written permission.
  43. *
  44. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  45. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  46. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  47. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  48. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  49. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  50. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  51. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  52. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  53. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  54. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  55. */
  56. /*
  57. * MultiPhase Locked Loops are outputs from a PLL with additional frequency
  58. * scaling capabilities. MPLL rates are calculated as:
  59. *
  60. * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384)
  61. */
  62. #include <linux/clk-provider.h>
  63. #include "clkc.h"
  64. #define SDM_DEN 16384
  65. #define N2_MIN 4
  66. #define N2_MAX 511
  67. static inline struct meson_clk_mpll_data *
  68. meson_clk_mpll_data(struct clk_regmap *clk)
  69. {
  70. return (struct meson_clk_mpll_data *)clk->data;
  71. }
  72. static long rate_from_params(unsigned long parent_rate,
  73. unsigned int sdm,
  74. unsigned int n2)
  75. {
  76. unsigned long divisor = (SDM_DEN * n2) + sdm;
  77. if (n2 < N2_MIN)
  78. return -EINVAL;
  79. return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor);
  80. }
  81. static void params_from_rate(unsigned long requested_rate,
  82. unsigned long parent_rate,
  83. unsigned int *sdm,
  84. unsigned int *n2)
  85. {
  86. uint64_t div = parent_rate;
  87. unsigned long rem = do_div(div, requested_rate);
  88. if (div < N2_MIN) {
  89. *n2 = N2_MIN;
  90. *sdm = 0;
  91. } else if (div > N2_MAX) {
  92. *n2 = N2_MAX;
  93. *sdm = SDM_DEN - 1;
  94. } else {
  95. *n2 = div;
  96. *sdm = DIV_ROUND_UP_ULL((u64)rem * SDM_DEN, requested_rate);
  97. }
  98. }
  99. static unsigned long mpll_recalc_rate(struct clk_hw *hw,
  100. unsigned long parent_rate)
  101. {
  102. struct clk_regmap *clk = to_clk_regmap(hw);
  103. struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
  104. unsigned int sdm, n2;
  105. long rate;
  106. sdm = meson_parm_read(clk->map, &mpll->sdm);
  107. n2 = meson_parm_read(clk->map, &mpll->n2);
  108. rate = rate_from_params(parent_rate, sdm, n2);
  109. return rate < 0 ? 0 : rate;
  110. }
  111. static long mpll_round_rate(struct clk_hw *hw,
  112. unsigned long rate,
  113. unsigned long *parent_rate)
  114. {
  115. unsigned int sdm, n2;
  116. params_from_rate(rate, *parent_rate, &sdm, &n2);
  117. return rate_from_params(*parent_rate, sdm, n2);
  118. }
  119. static int mpll_set_rate(struct clk_hw *hw,
  120. unsigned long rate,
  121. unsigned long parent_rate)
  122. {
  123. struct clk_regmap *clk = to_clk_regmap(hw);
  124. struct meson_clk_mpll_data *mpll = meson_clk_mpll_data(clk);
  125. unsigned int sdm, n2;
  126. unsigned long flags = 0;
  127. params_from_rate(rate, parent_rate, &sdm, &n2);
  128. if (mpll->lock)
  129. spin_lock_irqsave(mpll->lock, flags);
  130. else
  131. __acquire(mpll->lock);
  132. /* Enable and set the fractional part */
  133. meson_parm_write(clk->map, &mpll->sdm, sdm);
  134. meson_parm_write(clk->map, &mpll->sdm_en, 1);
  135. /* Set additional fractional part enable if required */
  136. if (MESON_PARM_APPLICABLE(&mpll->ssen))
  137. meson_parm_write(clk->map, &mpll->ssen, 1);
  138. /* Set the integer divider part */
  139. meson_parm_write(clk->map, &mpll->n2, n2);
  140. /* Set the magic misc bit if required */
  141. if (MESON_PARM_APPLICABLE(&mpll->misc))
  142. meson_parm_write(clk->map, &mpll->misc, 1);
  143. if (mpll->lock)
  144. spin_unlock_irqrestore(mpll->lock, flags);
  145. else
  146. __release(mpll->lock);
  147. return 0;
  148. }
  149. const struct clk_ops meson_clk_mpll_ro_ops = {
  150. .recalc_rate = mpll_recalc_rate,
  151. .round_rate = mpll_round_rate,
  152. };
  153. const struct clk_ops meson_clk_mpll_ops = {
  154. .recalc_rate = mpll_recalc_rate,
  155. .round_rate = mpll_round_rate,
  156. .set_rate = mpll_set_rate,
  157. };