Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 182790
b: refs/heads/master
c: 255173b
h: refs/heads/master
v: v3
  • Loading branch information
Peter Meerwald authored and Mark Brown committed Dec 16, 2009
1 parent b12b83e commit 015b034
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 27 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3497b91946a3df42830c826939424d98251a3b0d
refs/heads/master: 255173b40db448ce063a2caa680a552fb637ad20
75 changes: 49 additions & 26 deletions trunk/sound/soc/codecs/tlv320aic3x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -833,48 +834,70 @@ 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 (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;

/* 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;
}

/* Early exit for exact matches */
if (clk == codec_clk)
goto found;
}
}

if (j > 63)
continue;
/* try with d != 0 */
for (p = 1; p <= 8; p++) {
j = codec_clk * p / 1000;

if (d != 0 && aic3x->sysclk < 10000000)
continue;
if (j < 4 || j > 11)
continue;

/* 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);
/* do not use codec_clk here since we'd loose precision */
d = ((2048 * p * fsref) - j * aic3x->sysclk)
* 100 / (aic3x->sysclk/100);

/* 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;
}
clk = (10000 * j + d) / (10 * p);

/* Early exit for exact matches */
if (clk == codec_clk)
break;
/* 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);
Expand Down

0 comments on commit 015b034

Please sign in to comment.