Advertisement
Guest User

relax bitclk squashed version

a guest
Mar 15th, 2017
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.53 KB | None | 0 0
  1. From 7261b24daf0ac9302d850ae44416a66104f4420c Mon Sep 17 00:00:00 2001
  2. From: Daniel Baluta <daniel.baluta@nxp.com>
  3. Date: Mon, 13 Mar 2017 18:57:23 +0200
  4. Subject: [PATCH] ASoC: codec: wm8960: Refactor sysclk freq search
  5.  
  6. Add a separate function for finding (sysclk, lrclk, bclk)
  7. when the clock is auto or mclk. This makes code easier to
  8. read and reduces the indentation level in wm8960_configure_clocking.
  9.  
  10. Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
  11.  
  12. ASoC: codec: wm8960: Relax bit clock computation
  13.  
  14. WM8960 derives bit clock from sysclock using BCLKDIV[3:0] of R8
  15. clocking register (See WM8960 datasheet, page 71).
  16.  
  17. There are use cases, like this:
  18. aplay -Dhw:0,0 -r 48000 -c 1 -f S20_3LE -t raw audio48k20b_3LE1c.pcm
  19.  
  20. where no BCLKDIV applied to sysclock can give us the exact requested
  21. bitclk, so driver fails to configure clocking and aplay fails to run.
  22.  
  23. Fix this by relaxing bitclk computation, so that when no exact value
  24. can be derived from sysclk pick the closest value greater than
  25. expected bitclk.
  26.  
  27. Suggested-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
  28. Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
  29. ---
  30. sound/soc/codecs/wm8960.c | 113 +++++++++++++++++++++++++++++++++++++---------
  31. 1 file changed, 91 insertions(+), 22 deletions(-)
  32.  
  33. diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
  34. index 3bf081a..1669b45 100644
  35. --- a/sound/soc/codecs/wm8960.c
  36. +++ b/sound/soc/codecs/wm8960.c
  37. @@ -604,12 +604,88 @@ static const int bclk_divs[] = {
  38. 120, 160, 220, 240, 320, 320, 320
  39. };
  40.  
  41. +/**
  42. + * wm8960_configure_sysclk - checks if there is a sysclk frequency available
  43. + * The sysclk must be chosen such that:
  44. + * - sysclk = MCLK / sysclk_divs
  45. + * - lrclk = sysclk / dac_divs
  46. + * - 10 * bclk = sysclk / bclk_divs
  47. + *
  48. + * If we cannot find an exact match for (sysclk, lrclk, bclk)
  49. + * triplet, we relax the bclk such that bclk is chosen as the
  50. + * closest available frequency greater than expected bclk.
  51. + *
  52. + * @wm8960_priv: wm8960 codec private data
  53. + * @mclk: MCLK used to derive sysclk
  54. + * @_i: sysclk_divs index for found sysclk
  55. + * @_j: dac_divs index for found lrclk
  56. + * @_k: bclk_divs index for found bclk
  57. + *
  58. + * Returns:
  59. + * -1, in case no sysclk frequency available found
  60. + * 0, in case an exact match is found. See @_i, @_j, @_k
  61. + * >0, in case a relaxed match is found. See @_i, @_j, @_k
  62. + */
  63. +int wm8960_configure_sysclk(struct wm8960_priv *wm8960, int mclk,
  64. + int *_i, int *_j, int *_k)
  65. +{
  66. + int sysclk, bclk, lrclk;
  67. + int i, j, k;
  68. + int diff, closest = mclk;
  69. +
  70. + bclk = wm8960->bclk;
  71. + lrclk = wm8960->lrclk;
  72. +
  73. + /* check if the sysclk frequency is available. */
  74. + for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
  75. + if (sysclk_divs[i] == -1)
  76. + continue;
  77. + sysclk = mclk / sysclk_divs[i];
  78. + for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
  79. + if (sysclk != dac_divs[j] * lrclk)
  80. + continue;
  81. + for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k) {
  82. + diff = sysclk - bclk * bclk_divs[k] / 10;
  83. + if (diff == 0) {
  84. + *_i = i;
  85. + *_j = j;
  86. + *_k = k;
  87. + break;
  88. + }
  89. + if (diff > 0 && closest > diff) {
  90. + *_i = i;
  91. + *_j = j;
  92. + *_k = k;
  93. + closest = diff;
  94. + }
  95. + }
  96. + if (k != ARRAY_SIZE(bclk_divs))
  97. + break;
  98. + }
  99. + if (j != ARRAY_SIZE(dac_divs))
  100. + break;
  101. + }
  102. +
  103. + /* exact match */
  104. + if (i != ARRAY_SIZE(sysclk_divs))
  105. + return 0;
  106. +
  107. + /* no match */
  108. + if (closest == mclk)
  109. + return -1;
  110. +
  111. + /* relaxed match */
  112. + return 1;
  113. +}
  114. +
  115. static int wm8960_configure_clocking(struct snd_soc_codec *codec)
  116. {
  117. struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
  118. int sysclk, bclk, lrclk, freq_out, freq_in;
  119. u16 iface1 = snd_soc_read(codec, WM8960_IFACE1);
  120. int i, j, k;
  121. + int best_sysclk_div, best_dac_div, best_bclk_div = -1;
  122. + int ret;
  123.  
  124. if (!(iface1 & (1<<6))) {
  125. dev_dbg(codec->dev,
  126. @@ -643,30 +719,17 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
  127. }
  128.  
  129. if (wm8960->clk_id != WM8960_SYSCLK_PLL) {
  130. - /* check if the sysclk frequency is available. */
  131. - for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
  132. - if (sysclk_divs[i] == -1)
  133. - continue;
  134. - sysclk = freq_out / sysclk_divs[i];
  135. - for (j = 0; j < ARRAY_SIZE(dac_divs); ++j) {
  136. - if (sysclk != dac_divs[j] * lrclk)
  137. - continue;
  138. - for (k = 0; k < ARRAY_SIZE(bclk_divs); ++k)
  139. - if (sysclk == bclk * bclk_divs[k] / 10)
  140. - break;
  141. - if (k != ARRAY_SIZE(bclk_divs))
  142. - break;
  143. - }
  144. - if (j != ARRAY_SIZE(dac_divs))
  145. - break;
  146. - }
  147. -
  148. - if (i != ARRAY_SIZE(sysclk_divs)) {
  149. + ret = wm8960_configure_sysclk(wm8960, freq_out, &i, &j, &k);
  150. + if (ret == 0)
  151. goto configure_clock;
  152. - } else if (wm8960->clk_id != WM8960_SYSCLK_AUTO) {
  153. + else if (ret < 0 && wm8960->clk_id != WM8960_SYSCLK_AUTO) {
  154. dev_err(codec->dev, "failed to configure clock\n");
  155. return -EINVAL;
  156. }
  157. + /* there is still hope, keep this if no PLL out available */
  158. + best_sysclk_div = i;
  159. + best_dac_div = j;
  160. + best_bclk_div = k;
  161. }
  162. /* get a available pll out frequency and set pll */
  163. for (i = 0; i < ARRAY_SIZE(sysclk_divs); ++i) {
  164. @@ -694,8 +757,14 @@ static int wm8960_configure_clocking(struct snd_soc_codec *codec)
  165. }
  166.  
  167. if (i == ARRAY_SIZE(sysclk_divs)) {
  168. - dev_err(codec->dev, "failed to configure clock\n");
  169. - return -EINVAL;
  170. + if (best_bclk_div != -1) {
  171. + i = best_sysclk_div;
  172. + j = best_dac_div;
  173. + k = best_bclk_div;
  174. + } else {
  175. + dev_err(codec->dev, "failed to configure clock\n");
  176. + return -EINVAL;
  177. + }
  178. }
  179.  
  180. configure_clock:
  181. --
  182. 2.7.4
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement