clk-aux-synth.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright (C) 2012 ST Microelectronics
  3. * Viresh Kumar <vireshk@kernel.org>
  4. *
  5. * This file is licensed under the terms of the GNU General Public
  6. * License version 2. This program is licensed "as is" without any
  7. * warranty of any kind, whether express or implied.
  8. *
  9. * Auxiliary Synthesizer clock implementation
  10. */
  11. #define pr_fmt(fmt) "clk-aux-synth: " fmt
  12. #include <linux/clk-provider.h>
  13. #include <linux/slab.h>
  14. #include <linux/io.h>
  15. #include <linux/err.h>
  16. #include "clk.h"
  17. /*
  18. * DOC: Auxiliary Synthesizer clock
  19. *
  20. * Aux synth gives rate for different values of eq, x and y
  21. *
  22. * Fout from synthesizer can be given from two equations:
  23. * Fout1 = (Fin * X/Y)/2 EQ1
  24. * Fout2 = Fin * X/Y EQ2
  25. */
  26. #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw)
  27. static struct aux_clk_masks default_aux_masks = {
  28. .eq_sel_mask = AUX_EQ_SEL_MASK,
  29. .eq_sel_shift = AUX_EQ_SEL_SHIFT,
  30. .eq1_mask = AUX_EQ1_SEL,
  31. .eq2_mask = AUX_EQ2_SEL,
  32. .xscale_sel_mask = AUX_XSCALE_MASK,
  33. .xscale_sel_shift = AUX_XSCALE_SHIFT,
  34. .yscale_sel_mask = AUX_YSCALE_MASK,
  35. .yscale_sel_shift = AUX_YSCALE_SHIFT,
  36. .enable_bit = AUX_SYNT_ENB,
  37. };
  38. static unsigned long aux_calc_rate(struct clk_hw *hw, unsigned long prate,
  39. int index)
  40. {
  41. struct clk_aux *aux = to_clk_aux(hw);
  42. struct aux_rate_tbl *rtbl = aux->rtbl;
  43. u8 eq = rtbl[index].eq ? 1 : 2;
  44. return (((prate / 10000) * rtbl[index].xscale) /
  45. (rtbl[index].yscale * eq)) * 10000;
  46. }
  47. static long clk_aux_round_rate(struct clk_hw *hw, unsigned long drate,
  48. unsigned long *prate)
  49. {
  50. struct clk_aux *aux = to_clk_aux(hw);
  51. int unused;
  52. return clk_round_rate_index(hw, drate, *prate, aux_calc_rate,
  53. aux->rtbl_cnt, &unused);
  54. }
  55. static unsigned long clk_aux_recalc_rate(struct clk_hw *hw,
  56. unsigned long parent_rate)
  57. {
  58. struct clk_aux *aux = to_clk_aux(hw);
  59. unsigned int num = 1, den = 1, val, eqn;
  60. unsigned long flags = 0;
  61. if (aux->lock)
  62. spin_lock_irqsave(aux->lock, flags);
  63. val = readl_relaxed(aux->reg);
  64. if (aux->lock)
  65. spin_unlock_irqrestore(aux->lock, flags);
  66. eqn = (val >> aux->masks->eq_sel_shift) & aux->masks->eq_sel_mask;
  67. if (eqn == aux->masks->eq1_mask)
  68. den = 2;
  69. /* calculate numerator */
  70. num = (val >> aux->masks->xscale_sel_shift) &
  71. aux->masks->xscale_sel_mask;
  72. /* calculate denominator */
  73. den *= (val >> aux->masks->yscale_sel_shift) &
  74. aux->masks->yscale_sel_mask;
  75. if (!den)
  76. return 0;
  77. return (((parent_rate / 10000) * num) / den) * 10000;
  78. }
  79. /* Configures new clock rate of aux */
  80. static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate,
  81. unsigned long prate)
  82. {
  83. struct clk_aux *aux = to_clk_aux(hw);
  84. struct aux_rate_tbl *rtbl = aux->rtbl;
  85. unsigned long val, flags = 0;
  86. int i;
  87. clk_round_rate_index(hw, drate, prate, aux_calc_rate, aux->rtbl_cnt,
  88. &i);
  89. if (aux->lock)
  90. spin_lock_irqsave(aux->lock, flags);
  91. val = readl_relaxed(aux->reg) &
  92. ~(aux->masks->eq_sel_mask << aux->masks->eq_sel_shift);
  93. val |= (rtbl[i].eq & aux->masks->eq_sel_mask) <<
  94. aux->masks->eq_sel_shift;
  95. val &= ~(aux->masks->xscale_sel_mask << aux->masks->xscale_sel_shift);
  96. val |= (rtbl[i].xscale & aux->masks->xscale_sel_mask) <<
  97. aux->masks->xscale_sel_shift;
  98. val &= ~(aux->masks->yscale_sel_mask << aux->masks->yscale_sel_shift);
  99. val |= (rtbl[i].yscale & aux->masks->yscale_sel_mask) <<
  100. aux->masks->yscale_sel_shift;
  101. writel_relaxed(val, aux->reg);
  102. if (aux->lock)
  103. spin_unlock_irqrestore(aux->lock, flags);
  104. return 0;
  105. }
  106. static struct clk_ops clk_aux_ops = {
  107. .recalc_rate = clk_aux_recalc_rate,
  108. .round_rate = clk_aux_round_rate,
  109. .set_rate = clk_aux_set_rate,
  110. };
  111. struct clk *clk_register_aux(const char *aux_name, const char *gate_name,
  112. const char *parent_name, unsigned long flags, void __iomem *reg,
  113. struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl,
  114. u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk)
  115. {
  116. struct clk_aux *aux;
  117. struct clk_init_data init;
  118. struct clk *clk;
  119. if (!aux_name || !parent_name || !reg || !rtbl || !rtbl_cnt) {
  120. pr_err("Invalid arguments passed");
  121. return ERR_PTR(-EINVAL);
  122. }
  123. aux = kzalloc(sizeof(*aux), GFP_KERNEL);
  124. if (!aux) {
  125. pr_err("could not allocate aux clk\n");
  126. return ERR_PTR(-ENOMEM);
  127. }
  128. /* struct clk_aux assignments */
  129. if (!masks)
  130. aux->masks = &default_aux_masks;
  131. else
  132. aux->masks = masks;
  133. aux->reg = reg;
  134. aux->rtbl = rtbl;
  135. aux->rtbl_cnt = rtbl_cnt;
  136. aux->lock = lock;
  137. aux->hw.init = &init;
  138. init.name = aux_name;
  139. init.ops = &clk_aux_ops;
  140. init.flags = flags;
  141. init.parent_names = &parent_name;
  142. init.num_parents = 1;
  143. clk = clk_register(NULL, &aux->hw);
  144. if (IS_ERR_OR_NULL(clk))
  145. goto free_aux;
  146. if (gate_name) {
  147. struct clk *tgate_clk;
  148. tgate_clk = clk_register_gate(NULL, gate_name, aux_name,
  149. CLK_SET_RATE_PARENT, reg,
  150. aux->masks->enable_bit, 0, lock);
  151. if (IS_ERR_OR_NULL(tgate_clk))
  152. goto free_aux;
  153. if (gate_clk)
  154. *gate_clk = tgate_clk;
  155. }
  156. return clk;
  157. free_aux:
  158. kfree(aux);
  159. pr_err("clk register failed\n");
  160. return NULL;
  161. }