Choose clock source automatically if not provided. This will be the case with eg. audio-graph-card.
Signed-off-by: Michał Mirosław mirq-linux@rere.qmqm.pl --- sound/soc/codecs/wm8904.c | 42 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 033a38e408b5..2d8cb61a2d97 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -367,15 +367,34 @@ static int wm8904_enable_sysclk(struct wm8904_priv *priv) return err; }
+static int wm8904_bump_fll_sysclk(unsigned int *rate); + static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rate, int dir) { struct snd_soc_component *component = dai->component; struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component); unsigned int clock0, clock2; - int err; + int err, do_div = false;
switch (clk_id) { + case 0: + if (rate == clk_round_rate(wm8904->mclk, rate)) { + clk_id = WM8904_CLK_MCLK; + } else if (rate * 2 == clk_round_rate(wm8904->mclk, rate * 2)) { + rate *= 2; + clk_id = WM8904_CLK_MCLK; + do_div = true; + } else { + clk_id = WM8904_CLK_FLL; + err = wm8904_bump_fll_sysclk(&rate); + if (err) { + dev_dbg(component->dev, "Can't match %u over FLL 1406250 Hz minimum\n", rate); + return err; + } + } + break; + case WM8904_CLK_MCLK: case WM8904_CLK_FLL: break; @@ -419,7 +438,9 @@ static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id, }
/* SYSCLK shouldn't be over 13.5MHz */ - if (rate > 13500000) { + if (rate > 13500000) + do_div = true; + if (do_div) { clock0 = WM8904_MCLK_DIV; wm8904->sysclk_rate = rate / 2; } else { @@ -1334,6 +1355,23 @@ static struct { { 480, 20 }, };
+static int wm8904_bump_fll_sysclk(unsigned int *rate) +{ + int i; + + /* bump SYSCLK rate if below minimal FLL output */ + + for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { + if (*rate * bclk_divs[i].div >= 1406250 * 10) + break; + } + + if (i == ARRAY_SIZE(bclk_divs)) + return -ERANGE; + + *rate = (*rate * bclk_divs[i].div) / 10; + return 0; +}
static int wm8904_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params,