Commit ccc8d6c7 authored by Dimitris Papavasiliou's avatar Dimitris Papavasiliou Committed by Mark Brown

ASoC: pcm512x: Implement the set_bclk_ratio interface

Some boards, such as the HiFiBerry DAC+ Pro, use a pair of external
oscillators, to generate 44.1 or 48kHz multiples and are forced to
resort to hacks [1] in order to support 24-bit data without ending up
with fractional dividers.  This patch allows the machine driver to use
32-bit frames for 24-bit data to avoid such issues.

Although the datasheet (p. 15) seems to suggest that only a handful
of ratios are supported, it's not very explicit about it, so we allow
the full range of values supported by the underlying register in the
callback, to avoid needlessly rejecting potentially usable
configurations.

[1] http://mailman.alsa-project.org/pipermail/alsa-devel/2018-December/143442.htmlSigned-off-by: default avatarDimitris Papavasiliou <dpapavas@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 720734a0
...@@ -55,6 +55,7 @@ struct pcm512x_priv { ...@@ -55,6 +55,7 @@ struct pcm512x_priv {
unsigned long overclock_dsp; unsigned long overclock_dsp;
int mute; int mute;
struct mutex mutex; struct mutex mutex;
unsigned int bclk_ratio;
}; };
/* /*
...@@ -915,11 +916,16 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai, ...@@ -915,11 +916,16 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
int fssp; int fssp;
int gpio; int gpio;
if (pcm512x->bclk_ratio > 0) {
lrclk_div = pcm512x->bclk_ratio;
} else {
lrclk_div = snd_soc_params_to_frame_size(params); lrclk_div = snd_soc_params_to_frame_size(params);
if (lrclk_div == 0) { if (lrclk_div == 0) {
dev_err(dev, "No LRCLK?\n"); dev_err(dev, "No LRCLK?\n");
return -EINVAL; return -EINVAL;
} }
}
if (!pcm512x->pll_out) { if (!pcm512x->pll_out) {
sck_rate = clk_get_rate(pcm512x->sclk); sck_rate = clk_get_rate(pcm512x->sclk);
...@@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) ...@@ -1383,6 +1389,19 @@ static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0; return 0;
} }
static int pcm512x_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
{
struct snd_soc_component *component = dai->component;
struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
if (ratio > 256)
return -EINVAL;
pcm512x->bclk_ratio = ratio;
return 0;
}
static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute) static int pcm512x_digital_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
...@@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = { ...@@ -1435,6 +1454,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = {
.hw_params = pcm512x_hw_params, .hw_params = pcm512x_hw_params,
.set_fmt = pcm512x_set_fmt, .set_fmt = pcm512x_set_fmt,
.digital_mute = pcm512x_digital_mute, .digital_mute = pcm512x_digital_mute,
.set_bclk_ratio = pcm512x_set_bclk_ratio,
}; };
static struct snd_soc_dai_driver pcm512x_dai = { static struct snd_soc_dai_driver pcm512x_dai = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment