Skip to content

Commit cf50718

Browse files
tiwaibroonie
authored andcommitted
ASoC: nau8821: Implement hw constraint for rates
nau8821 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: Takashi Iwai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 221ab1f commit cf50718

File tree

1 file changed

+36
-30
lines changed

1 file changed

+36
-30
lines changed

sound/soc/codecs/nau8821.c

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -670,36 +670,49 @@ static const struct snd_soc_dapm_route nau8821_dapm_routes[] = {
670670
{"HPOR", NULL, "Class G"},
671671
};
672672

673-
static int nau8821_clock_check(struct nau8821 *nau8821,
674-
int stream, int rate, int osr)
673+
static const struct nau8821_osr_attr *
674+
nau8821_get_osr(struct nau8821 *nau8821, int stream)
675675
{
676-
int osrate = 0;
676+
unsigned int osr;
677677

678678
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
679+
regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr);
680+
osr &= NAU8821_DAC_OVERSAMPLE_MASK;
679681
if (osr >= ARRAY_SIZE(osr_dac_sel))
680-
return -EINVAL;
681-
osrate = osr_dac_sel[osr].osr;
682+
return NULL;
683+
return &osr_dac_sel[osr];
682684
} else {
685+
regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr);
686+
osr &= NAU8821_ADC_SYNC_DOWN_MASK;
683687
if (osr >= ARRAY_SIZE(osr_adc_sel))
684-
return -EINVAL;
685-
osrate = osr_adc_sel[osr].osr;
688+
return NULL;
689+
return &osr_adc_sel[osr];
686690
}
691+
}
687692

688-
if (!osrate || rate * osrate > CLK_DA_AD_MAX) {
689-
dev_err(nau8821->dev,
690-
"exceed the maximum frequency of CLK_ADC or CLK_DAC");
693+
static int nau8821_dai_startup(struct snd_pcm_substream *substream,
694+
struct snd_soc_dai *dai)
695+
{
696+
struct snd_soc_component *component = dai->component;
697+
struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
698+
const struct nau8821_osr_attr *osr;
699+
700+
osr = nau8821_get_osr(nau8821, substream->stream);
701+
if (!osr || !osr->osr)
691702
return -EINVAL;
692-
}
693703

694-
return 0;
704+
return snd_pcm_hw_constraint_minmax(substream->runtime,
705+
SNDRV_PCM_HW_PARAM_RATE,
706+
0, CLK_DA_AD_MAX / osr->osr);
695707
}
696708

697709
static int nau8821_hw_params(struct snd_pcm_substream *substream,
698710
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
699711
{
700712
struct snd_soc_component *component = dai->component;
701713
struct nau8821 *nau8821 = snd_soc_component_get_drvdata(component);
702-
unsigned int val_len = 0, osr, ctrl_val, bclk_fs, clk_div;
714+
unsigned int val_len = 0, ctrl_val, bclk_fs, clk_div;
715+
const struct nau8821_osr_attr *osr;
703716

704717
nau8821->fs = params_rate(params);
705718
/* CLK_DAC or CLK_ADC = OSR * FS
@@ -708,27 +721,19 @@ static int nau8821_hw_params(struct snd_pcm_substream *substream,
708721
* values must be selected such that the maximum frequency is less
709722
* than 6.144 MHz.
710723
*/
711-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
712-
regmap_read(nau8821->regmap, NAU8821_R2C_DAC_CTRL1, &osr);
713-
osr &= NAU8821_DAC_OVERSAMPLE_MASK;
714-
if (nau8821_clock_check(nau8821, substream->stream,
715-
nau8821->fs, osr)) {
716-
return -EINVAL;
717-
}
724+
osr = nau8821_get_osr(nau8821, substream->stream);
725+
if (!osr || !osr->osr)
726+
return -EINVAL;
727+
if (nau8821->fs * osr->osr > CLK_DA_AD_MAX)
728+
return -EINVAL;
729+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
718730
regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER,
719731
NAU8821_CLK_DAC_SRC_MASK,
720-
osr_dac_sel[osr].clk_src << NAU8821_CLK_DAC_SRC_SFT);
721-
} else {
722-
regmap_read(nau8821->regmap, NAU8821_R2B_ADC_RATE, &osr);
723-
osr &= NAU8821_ADC_SYNC_DOWN_MASK;
724-
if (nau8821_clock_check(nau8821, substream->stream,
725-
nau8821->fs, osr)) {
726-
return -EINVAL;
727-
}
732+
osr->clk_src << NAU8821_CLK_DAC_SRC_SFT);
733+
else
728734
regmap_update_bits(nau8821->regmap, NAU8821_R03_CLK_DIVIDER,
729735
NAU8821_CLK_ADC_SRC_MASK,
730-
osr_adc_sel[osr].clk_src << NAU8821_CLK_ADC_SRC_SFT);
731-
}
736+
osr->clk_src << NAU8821_CLK_ADC_SRC_SFT);
732737

733738
/* make BCLK and LRC divde configuration if the codec as master. */
734739
regmap_read(nau8821->regmap, NAU8821_R1D_I2S_PCM_CTRL2, &ctrl_val);
@@ -843,6 +848,7 @@ static int nau8821_digital_mute(struct snd_soc_dai *dai, int mute,
843848
}
844849

845850
static const struct snd_soc_dai_ops nau8821_dai_ops = {
851+
.startup = nau8821_dai_startup,
846852
.hw_params = nau8821_hw_params,
847853
.set_fmt = nau8821_set_dai_fmt,
848854
.mute_stream = nau8821_digital_mute,

0 commit comments

Comments
 (0)