Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 132935
b: refs/heads/master
c: e8523b6
h: refs/heads/master
i:
  132933: c455ac7
  132931: 1ee180c
  132927: dc79410
v: v3
  • Loading branch information
Mark Brown committed Mar 19, 2009
1 parent a2280f7 commit 5aaeaa9
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 24a51029fc3055f33684e650b5e3a59f77c9b05c
refs/heads/master: e8523b641cddedec754ae5e44ec579dbceea5ef4
129 changes: 129 additions & 0 deletions trunk/sound/soc/codecs/wm8400.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ struct wm8400_priv {
unsigned int sysclk;
unsigned int pcmclk;
struct work_struct work;
int fll_in, fll_out;
};

static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
Expand Down Expand Up @@ -931,6 +932,133 @@ static int wm8400_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return 0;
}

struct fll_factors {
u16 n;
u16 k;
u16 outdiv;
u16 fratio;
u16 freq_ref;
};

#define FIXED_FLL_SIZE ((1 << 16) * 10)

static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors,
unsigned int Fref, unsigned int Fout)
{
u64 Kpart;
unsigned int K, Nmod, target;

factors->outdiv = 2;
while (Fout * factors->outdiv < 90000000 ||
Fout * factors->outdiv > 100000000) {
factors->outdiv *= 2;
if (factors->outdiv > 32) {
dev_err(wm8400->wm8400->dev,
"Unsupported FLL output frequency %dHz\n",
Fout);
return -EINVAL;
}
}
target = Fout * factors->outdiv;
factors->outdiv = factors->outdiv >> 2;

if (Fref < 48000)
factors->freq_ref = 1;
else
factors->freq_ref = 0;

if (Fref < 1000000)
factors->fratio = 9;
else
factors->fratio = 0;

/* Ensure we have a fractional part */
do {
if (Fref < 1000000)
factors->fratio--;
else
factors->fratio++;

if (factors->fratio < 1 || factors->fratio > 8) {
dev_err(wm8400->wm8400->dev,
"Unable to calculate FRATIO\n");
return -EINVAL;
}

factors->n = target / (Fref * factors->fratio);
Nmod = target % (Fref * factors->fratio);
} while (Nmod == 0);

/* Calculate fractional part - scale up so we can round. */
Kpart = FIXED_FLL_SIZE * (long long)Nmod;

do_div(Kpart, (Fref * factors->fratio));

K = Kpart & 0xFFFFFFFF;

if ((K % 10) >= 5)
K += 5;

/* Move down to proper range now rounding is done */
factors->k = K / 10;

dev_dbg(wm8400->wm8400->dev,
"FLL: Fref=%d Fout=%d N=%x K=%x, FRATIO=%x OUTDIV=%x\n",
Fref, Fout,
factors->n, factors->k, factors->fratio, factors->outdiv);

return 0;
}

static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
unsigned int freq_in, unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct wm8400_priv *wm8400 = codec->private_data;
struct fll_factors factors;
int ret;
u16 reg;

if (freq_in == wm8400->fll_in && freq_out == wm8400->fll_out)
return 0;

if (freq_out != 0) {
ret = fll_factors(wm8400, &factors, freq_in, freq_out);
if (ret != 0)
return ret;
}

wm8400->fll_out = freq_out;
wm8400->fll_in = freq_in;

/* We *must* disable the FLL before any changes */
reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
reg &= ~WM8400_FLL_ENA;
wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);

reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
reg &= ~WM8400_FLL_OSC_ENA;
wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);

if (freq_out == 0)
return 0;

reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
reg |= WM8400_FLL_FRAC | factors.fratio;
reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);

wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);

reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
reg &= WM8400_FLL_OUTDIV_MASK;
reg |= factors.outdiv;
wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);

return 0;
}

/*
* Sets ADC and Voice DAC format.
*/
Expand Down Expand Up @@ -1188,6 +1316,7 @@ static struct snd_soc_dai_ops wm8400_dai_ops = {
.set_fmt = wm8400_set_dai_fmt,
.set_clkdiv = wm8400_set_dai_clkdiv,
.set_sysclk = wm8400_set_dai_sysclk,
.set_pll = wm8400_set_dai_pll,
};

/*
Expand Down

0 comments on commit 5aaeaa9

Please sign in to comment.