On Thu, Nov 27, 2025 at 10:27 AM Chancel Liu <[email protected]> wrote: > > The range control register can't directly adjust volume gain according > to specification. It's the dynamic range of the CIC filter. The range > value should meet some conditions otherwise the channel data is not > reliable. Add an array in soc data to store const value in formula > with which range with all quality on different platforms can be > calculated. If the value set to range control exceeds the max range > there'll be warning logs. > > Signed-off-by: Chancel Liu <[email protected]>
Acked-by: Shengjiu Wang <[email protected]> Best regards Shengjiu wang > --- > sound/soc/fsl/fsl_micfil.c | 125 ++++++++++++++++++++++++++++++------- > 1 file changed, 103 insertions(+), 22 deletions(-) > > diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c > index 86678fee7a57..d6cde2757c6d 100644 > --- a/sound/soc/fsl/fsl_micfil.c > +++ b/sound/soc/fsl/fsl_micfil.c > @@ -17,6 +17,7 @@ > #include <linux/sysfs.h> > #include <linux/types.h> > #include <linux/dma/imx-dma.h> > +#include <linux/log2.h> > #include <sound/dmaengine_pcm.h> > #include <sound/pcm.h> > #include <sound/pcm_params.h> > @@ -93,6 +94,8 @@ struct fsl_micfil_soc_data { > u64 formats; > int fifo_offset; > enum quality default_quality; > + /* stores const value in formula to calculate range */ > + int rangeadj_const[3][2]; > }; > > static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { > @@ -115,6 +118,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { > .volume_sx = false, > .fifo_offset = 0, > .default_quality = QUALITY_MEDIUM, > + .rangeadj_const = {{27, 7}, {27, 7}, {26, 7}}, > }; > > static struct fsl_micfil_soc_data fsl_micfil_imx93 = { > @@ -128,6 +132,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { > .volume_sx = false, > .fifo_offset = 0, > .default_quality = QUALITY_MEDIUM, > + .rangeadj_const = {{30, 6}, {30, 6}, {29, 6}}, > }; > > static struct fsl_micfil_soc_data fsl_micfil_imx943 = { > @@ -141,6 +146,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = { > .volume_sx = false, > .fifo_offset = -4, > .default_quality = QUALITY_MEDIUM, > + .rangeadj_const = {{34, 6}, {34, 6}, {33, 6}}, > }; > > static const struct of_device_id fsl_micfil_dt_ids[] = { > @@ -167,9 +173,69 @@ static const struct soc_enum fsl_micfil_quality_enum = > > static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); > > +static int micfil_get_max_range(struct fsl_micfil *micfil) > +{ > + int max_range; > + > + switch (micfil->quality) { > + case QUALITY_HIGH: > + case QUALITY_VLOW0: > + max_range = micfil->soc->rangeadj_const[0][0] - > micfil->soc->rangeadj_const[0][1] * > + ilog2(2 * MICFIL_OSR_DEFAULT); > + break; > + case QUALITY_MEDIUM: > + case QUALITY_VLOW1: > + max_range = micfil->soc->rangeadj_const[1][0] - > micfil->soc->rangeadj_const[1][1] * > + ilog2(MICFIL_OSR_DEFAULT); > + break; > + case QUALITY_LOW: > + case QUALITY_VLOW2: > + max_range = micfil->soc->rangeadj_const[2][0] - > micfil->soc->rangeadj_const[2][1] * > + ilog2(MICFIL_OSR_DEFAULT); > + break; > + default: > + return 0; > + } > + max_range = max_range < 0 ? 0 : max_range; > + > + return max_range; > +} > + > +static int micfil_range_set(struct snd_kcontrol *kcontrol, > + struct snd_ctl_elem_value *ucontrol) > +{ > + struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); > + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); > + struct soc_mixer_control *mc = > + (struct soc_mixer_control *)kcontrol->private_value; > + unsigned int shift = mc->shift; > + int max_range, new_range; > + > + new_range = ucontrol->value.integer.value[0]; > + max_range = micfil_get_max_range(micfil); > + if (new_range > max_range) > + dev_warn(&micfil->pdev->dev, "range makes channel %d data > unreliable\n", shift / 4); > + > + regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, > new_range << shift); > + > + return 0; > +} > + > static int micfil_set_quality(struct fsl_micfil *micfil) > { > - u32 qsel; > + int range, max_range; > + u32 qsel, val; > + int i; > + > + if (!micfil->soc->volume_sx) { > + regmap_read(micfil->regmap, REG_MICFIL_OUT_CTRL, &val); > + max_range = micfil_get_max_range(micfil); > + for (i = 0; i < micfil->soc->fifos; i++) { > + range = (val >> MICFIL_OUTGAIN_CHX_SHIFT(i)) & 0xF; > + if (range > max_range) > + dev_warn(&micfil->pdev->dev, "please reset > channel %d range\n", i); > + } > + } > > switch (micfil->quality) { > case QUALITY_HIGH: > @@ -367,23 +433,31 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol, > return 0; > } > > -static const struct snd_kcontrol_new fsl_micfil_volume_controls[] = { > - SOC_SINGLE_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, gain_tlv), > - SOC_SINGLE_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, > - MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, gain_tlv), > +static const struct snd_kcontrol_new fsl_micfil_range_controls[] = { > + SOC_SINGLE_EXT("CH0 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH1 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH2 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH3 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH4 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH5 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH6 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > + SOC_SINGLE_EXT("CH7 Range", REG_MICFIL_OUT_CTRL, > + MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, > + snd_soc_get_volsw, micfil_range_set), > }; > > static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls[] = { > @@ -895,13 +969,20 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai > *cpu_dai) > struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); > struct device *dev = cpu_dai->dev; > unsigned int val = 0; > - int ret, i; > + int ret, i, max_range; > > micfil->quality = micfil->soc->default_quality; > micfil->card = cpu_dai->component->card; > > /* set default gain to 2 */ > - regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); > + if (micfil->soc->volume_sx) { > + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); > + } else { > + max_range = micfil_get_max_range(micfil); > + for (i = 1; i < micfil->soc->fifos; i++) > + max_range |= max_range << 4; > + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, max_range); > + } > > /* set DC Remover in bypass mode*/ > for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) > @@ -935,8 +1016,8 @@ static int fsl_micfil_component_probe(struct > snd_soc_component *component) > snd_soc_add_component_controls(component, > fsl_micfil_volume_sx_controls, > > ARRAY_SIZE(fsl_micfil_volume_sx_controls)); > else > - snd_soc_add_component_controls(component, > fsl_micfil_volume_controls, > - > ARRAY_SIZE(fsl_micfil_volume_controls)); > + snd_soc_add_component_controls(component, > fsl_micfil_range_controls, > + > ARRAY_SIZE(fsl_micfil_range_controls)); > > return 0; > } > -- > 2.50.1 >
