[alsa-devel] PLL computation in TLV320AIC3x SoC driver
Peter Meerwald
pmeerw at pmeerw.net
Mon Dec 14 11:24:58 CET 2009
> >>>>>> I'm trying to use the SoC TLV320AIC3x codec driver with sysclk
> >>>>>> 16384000 and
> > I have put the proposed code at http://pmeerw.net/clk/ for review;
> I confirm that it handles all cases with best precision now.
> I'm ok to submit.
fix precision of PLL computation for TLV320AIC3x SoC driver,
test results are at http://pmeerw.net/clk
Signed-off-by: Peter Meerwald <pmeerw at pmeerw.net>
---
sound/soc/codecs/tlv320aic3x.c | 80 ++++++++++++++++++++++++---------------
1 files changed, 49 insertions(+), 31 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 2b4dc2b..6f81a00 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -765,9 +765,10 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec;
struct aic3x_priv *aic3x = codec->private_data;
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
- u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
- u16 pll_d = 1;
+ u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
+ u16 d, pll_d = 1;
u8 reg;
+ int clk;
/* select data word length */
data =
@@ -833,48 +834,65 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
if (bypass_pll)
return 0;
- /* Use PLL
- * find an apropriate setup for j, d, r and p by iterating over
- * p and r - j and d are calculated for each fraction.
- * Up to 128 values are probed, the closest one wins the game.
+ /* Use PLL, compute apropriate setup for j, d, r and p, the closest
+ * one wins the game. Try with d==0 first, next with d!=0.
+ * Constraints for j are according to the datasheet.
* The sysclk is divided by 1000 to prevent integer overflows.
*/
+
codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000);
- for (r = 1; r <= 16; r++)
- for (p = 1; p <= 8; p++) {
- int clk, tmp = (codec_clk * pll_r * 10) / pll_p;
- u8 j = tmp / 10000;
- u16 d = tmp % 10000;
+ for (r = 1; r <= 16; r++)
+ for (p = 1; p <= 8; p++) {
+ for (j = 4; j <= 55; j++) {
+ /* This is actually 1000 * ((j + (d/10000)) * r) / p
+ * The term had to be converted to get rid of the
+ * division by 10000; d = 0 here */
+ int clk = (1000 * j * r) / p;
- if (j > 63)
- continue;
+ /* check whether this values get closer than the best
+ * ones we had before */
+ if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
+ pll_j = j; pll_d = 0; pll_r = r; pll_p = p;
+ last_clk = clk;
+ }
- if (d != 0 && aic3x->sysclk < 10000000)
- continue;
+ /* Early exit for exact matches */
+ if (clk == codec_clk)
+ goto found;
+ }
+ }
- /* This is actually 1000 * ((j + (d/10000)) * r) / p
- * The term had to be converted to get rid of the
- * division by 10000 */
- clk = ((10000 * j * r) + (d * r)) / (10 * p);
-
- /* check whether this values get closer than the best
- * ones we had before */
- if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
- pll_j = j; pll_d = d; pll_r = r; pll_p = p;
- last_clk = clk;
- }
-
- /* Early exit for exact matches */
- if (clk == codec_clk)
- break;
- }
+ /* try with d != 0 */
+ for (p = 1; p <= 8; p++) {
+
+ j = codec_clk * p / 1000;
+
+ if (j < 4 || j > 11) continue;
+
+ /* do not use codec_clk here since we'd loose precision */
+ d = ((2048 * p * fsref) - j * aic3x->sysclk) * 100 / (aic3x->sysclk/100);
+
+ clk = (10000 * j + d) / (10 * p);
+
+ /* check whether this values get closer than the best
+ * ones we had before */
+ if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) {
+ pll_j = j; pll_d = d; pll_r = 1; pll_p = p;
+ last_clk = clk;
+ }
+
+ /* Early exit for exact matches */
+ if (clk == codec_clk)
+ goto found;
+ }
if (last_clk == 0) {
printk(KERN_ERR "%s(): unable to setup PLL\n", __func__);
return -EINVAL;
}
+found:
data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT));
aic3x_write(codec, AIC3X_OVRF_STATUS_AND_PLLR_REG, pll_r << PLLR_SHIFT);
--
Peter Meerwald
Kaigasse 3 / 8
A-5020 Salzburg / AUSTRIA
+43-664-2444418 (mobile)
More information about the Alsa-devel
mailing list