Loading sound/soc/fsl/fsl_micfil.c +109 −23 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -92,6 +93,9 @@ struct fsl_micfil_soc_data { bool volume_sx; 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 = { Loading @@ -102,6 +106,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { .formats = SNDRV_PCM_FMTBIT_S16_LE, .volume_sx = true, .fifo_offset = 0, .default_quality = QUALITY_VLOW0, }; static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { Loading @@ -112,6 +117,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { .formats = SNDRV_PCM_FMTBIT_S32_LE, .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 = { Loading @@ -124,6 +131,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { .use_verid = true, .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 = { Loading @@ -136,6 +145,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = { .use_verid = true, .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[] = { Loading @@ -162,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: Loading Loading @@ -362,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[] = { Loading Loading @@ -890,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 = QUALITY_VLOW0; micfil->quality = micfil->soc->default_quality; micfil->card = cpu_dai->component->card; /* set default gain to 2 */ 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++) Loading Loading @@ -930,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; } Loading Loading
sound/soc/fsl/fsl_micfil.c +109 −23 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -92,6 +93,9 @@ struct fsl_micfil_soc_data { bool volume_sx; 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 = { Loading @@ -102,6 +106,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { .formats = SNDRV_PCM_FMTBIT_S16_LE, .volume_sx = true, .fifo_offset = 0, .default_quality = QUALITY_VLOW0, }; static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { Loading @@ -112,6 +117,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { .formats = SNDRV_PCM_FMTBIT_S32_LE, .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 = { Loading @@ -124,6 +131,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = { .use_verid = true, .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 = { Loading @@ -136,6 +145,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = { .use_verid = true, .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[] = { Loading @@ -162,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: Loading Loading @@ -362,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[] = { Loading Loading @@ -890,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 = QUALITY_VLOW0; micfil->quality = micfil->soc->default_quality; micfil->card = cpu_dai->component->card; /* set default gain to 2 */ 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++) Loading Loading @@ -930,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; } Loading