Commit 92283c86 authored by Takashi Iwai's avatar Takashi Iwai Committed by Mark Brown

ASoC: nau8824: Implement hw constraint for rates

nau8824 driver restricts the sample rate with over sampling rate, but
currently it barely bails out at hw_params with -EINVAL error (with a
kernel message); this doesn't help for user-space to recognize which
rate can be actually used.

This patch introduces the proper hw constraint for adjusting the
available range of the sample rate depending on the OSR setup, as well
as some code cleanup, for improving the communication with
user-space.  Now applications can know the valid rate beforehand and
reduces the rate appropriately without errors.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Link: https://lore.kernel.org/r/20220823081000.2965-4-tiwai@suse.deSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 5628560e
...@@ -1014,27 +1014,42 @@ static irqreturn_t nau8824_interrupt(int irq, void *data) ...@@ -1014,27 +1014,42 @@ static irqreturn_t nau8824_interrupt(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int nau8824_clock_check(struct nau8824 *nau8824, static const struct nau8824_osr_attr *
int stream, int rate, int osr) nau8824_get_osr(struct nau8824 *nau8824, int stream)
{ {
int osrate; unsigned int osr;
if (stream == SNDRV_PCM_STREAM_PLAYBACK) { if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
regmap_read(nau8824->regmap,
NAU8824_REG_DAC_FILTER_CTRL_1, &osr);
osr &= NAU8824_DAC_OVERSAMPLE_MASK;
if (osr >= ARRAY_SIZE(osr_dac_sel)) if (osr >= ARRAY_SIZE(osr_dac_sel))
return -EINVAL; return NULL;
osrate = osr_dac_sel[osr].osr; return &osr_dac_sel[osr];
} else { } else {
regmap_read(nau8824->regmap,
NAU8824_REG_ADC_FILTER_CTRL, &osr);
osr &= NAU8824_ADC_SYNC_DOWN_MASK;
if (osr >= ARRAY_SIZE(osr_adc_sel)) if (osr >= ARRAY_SIZE(osr_adc_sel))
return -EINVAL; return NULL;
osrate = osr_adc_sel[osr].osr; return &osr_adc_sel[osr];
} }
}
if (!osrate || rate * osr > CLK_DA_AD_MAX) { static int nau8824_dai_startup(struct snd_pcm_substream *substream,
dev_err(nau8824->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
const struct nau8824_osr_attr *osr;
osr = nau8824_get_osr(nau8824, substream->stream);
if (!osr || !osr->osr)
return -EINVAL; return -EINVAL;
}
return 0; return snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_RATE,
0, CLK_DA_AD_MAX / osr->osr);
} }
static int nau8824_hw_params(struct snd_pcm_substream *substream, static int nau8824_hw_params(struct snd_pcm_substream *substream,
...@@ -1042,7 +1057,8 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, ...@@ -1042,7 +1057,8 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
{ {
struct snd_soc_component *component = dai->component; struct snd_soc_component *component = dai->component;
struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component); struct nau8824 *nau8824 = snd_soc_component_get_drvdata(component);
unsigned int val_len = 0, osr, ctrl_val, bclk_fs, bclk_div; unsigned int val_len = 0, ctrl_val, bclk_fs, bclk_div;
const struct nau8824_osr_attr *osr;
int err = -EINVAL; int err = -EINVAL;
nau8824_sema_acquire(nau8824, HZ); nau8824_sema_acquire(nau8824, HZ);
...@@ -1054,27 +1070,19 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream, ...@@ -1054,27 +1070,19 @@ static int nau8824_hw_params(struct snd_pcm_substream *substream,
* than 6.144 MHz. * than 6.144 MHz.
*/ */
nau8824->fs = params_rate(params); nau8824->fs = params_rate(params);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { osr = nau8824_get_osr(nau8824, substream->stream);
regmap_read(nau8824->regmap, if (!osr || !osr->osr)
NAU8824_REG_DAC_FILTER_CTRL_1, &osr); goto error;
osr &= NAU8824_DAC_OVERSAMPLE_MASK; if (nau8824->fs * osr->osr > CLK_DA_AD_MAX)
if (nau8824_clock_check(nau8824, substream->stream, goto error;
nau8824->fs, osr)) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
goto error;
regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER, regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
NAU8824_CLK_DAC_SRC_MASK, NAU8824_CLK_DAC_SRC_MASK,
osr_dac_sel[osr].clk_src << NAU8824_CLK_DAC_SRC_SFT); osr->clk_src << NAU8824_CLK_DAC_SRC_SFT);
} else { else
regmap_read(nau8824->regmap,
NAU8824_REG_ADC_FILTER_CTRL, &osr);
osr &= NAU8824_ADC_SYNC_DOWN_MASK;
if (nau8824_clock_check(nau8824, substream->stream,
nau8824->fs, osr))
goto error;
regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER, regmap_update_bits(nau8824->regmap, NAU8824_REG_CLK_DIVIDER,
NAU8824_CLK_ADC_SRC_MASK, NAU8824_CLK_ADC_SRC_MASK,
osr_adc_sel[osr].clk_src << NAU8824_CLK_ADC_SRC_SFT); osr->clk_src << NAU8824_CLK_ADC_SRC_SFT);
}
/* make BCLK and LRC divde configuration if the codec as master. */ /* make BCLK and LRC divde configuration if the codec as master. */
regmap_read(nau8824->regmap, regmap_read(nau8824->regmap,
...@@ -1550,6 +1558,7 @@ static const struct snd_soc_component_driver nau8824_component_driver = { ...@@ -1550,6 +1558,7 @@ static const struct snd_soc_component_driver nau8824_component_driver = {
}; };
static const struct snd_soc_dai_ops nau8824_dai_ops = { static const struct snd_soc_dai_ops nau8824_dai_ops = {
.startup = nau8824_dai_startup,
.hw_params = nau8824_hw_params, .hw_params = nau8824_hw_params,
.set_fmt = nau8824_set_fmt, .set_fmt = nau8824_set_fmt,
.set_tdm_slot = nau8824_set_tdm_slot, .set_tdm_slot = nau8824_set_tdm_slot,
......
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