Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: fsl_micfil: Set default quality and channel

Merge series from Chancel Liu <chancel.liu@nxp.com>:

Add default quality for different platforms.
Set channel range control.

+109 -23
+109 -23
sound/soc/fsl/fsl_micfil.c
··· 17 17 #include <linux/sysfs.h> 18 18 #include <linux/types.h> 19 19 #include <linux/dma/imx-dma.h> 20 + #include <linux/log2.h> 20 21 #include <sound/dmaengine_pcm.h> 21 22 #include <sound/pcm.h> 22 23 #include <sound/pcm_params.h> ··· 93 92 bool volume_sx; 94 93 u64 formats; 95 94 int fifo_offset; 95 + enum quality default_quality; 96 + /* stores const value in formula to calculate range */ 97 + int rangeadj_const[3][2]; 96 98 }; 97 99 98 100 static struct fsl_micfil_soc_data fsl_micfil_imx8mm = { ··· 106 102 .formats = SNDRV_PCM_FMTBIT_S16_LE, 107 103 .volume_sx = true, 108 104 .fifo_offset = 0, 105 + .default_quality = QUALITY_VLOW0, 109 106 }; 110 107 111 108 static struct fsl_micfil_soc_data fsl_micfil_imx8mp = { ··· 117 112 .formats = SNDRV_PCM_FMTBIT_S32_LE, 118 113 .volume_sx = false, 119 114 .fifo_offset = 0, 115 + .default_quality = QUALITY_MEDIUM, 116 + .rangeadj_const = {{27, 7}, {27, 7}, {26, 7}}, 120 117 }; 121 118 122 119 static struct fsl_micfil_soc_data fsl_micfil_imx93 = { ··· 131 124 .use_verid = true, 132 125 .volume_sx = false, 133 126 .fifo_offset = 0, 127 + .default_quality = QUALITY_MEDIUM, 128 + .rangeadj_const = {{30, 6}, {30, 6}, {29, 6}}, 134 129 }; 135 130 136 131 static struct fsl_micfil_soc_data fsl_micfil_imx943 = { ··· 145 136 .use_verid = true, 146 137 .volume_sx = false, 147 138 .fifo_offset = -4, 139 + .default_quality = QUALITY_MEDIUM, 140 + .rangeadj_const = {{34, 6}, {34, 6}, {33, 6}}, 148 141 }; 149 142 150 143 static const struct of_device_id fsl_micfil_dt_ids[] = { ··· 173 162 174 163 static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0); 175 164 165 + static int micfil_get_max_range(struct fsl_micfil *micfil) 166 + { 167 + int max_range; 168 + 169 + switch (micfil->quality) { 170 + case QUALITY_HIGH: 171 + case QUALITY_VLOW0: 172 + max_range = micfil->soc->rangeadj_const[0][0] - micfil->soc->rangeadj_const[0][1] * 173 + ilog2(2 * MICFIL_OSR_DEFAULT); 174 + break; 175 + case QUALITY_MEDIUM: 176 + case QUALITY_VLOW1: 177 + max_range = micfil->soc->rangeadj_const[1][0] - micfil->soc->rangeadj_const[1][1] * 178 + ilog2(MICFIL_OSR_DEFAULT); 179 + break; 180 + case QUALITY_LOW: 181 + case QUALITY_VLOW2: 182 + max_range = micfil->soc->rangeadj_const[2][0] - micfil->soc->rangeadj_const[2][1] * 183 + ilog2(MICFIL_OSR_DEFAULT); 184 + break; 185 + default: 186 + return 0; 187 + } 188 + max_range = max_range < 0 ? 0 : max_range; 189 + 190 + return max_range; 191 + } 192 + 193 + static int micfil_range_set(struct snd_kcontrol *kcontrol, 194 + struct snd_ctl_elem_value *ucontrol) 195 + { 196 + struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol); 197 + struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt); 198 + struct soc_mixer_control *mc = 199 + (struct soc_mixer_control *)kcontrol->private_value; 200 + unsigned int shift = mc->shift; 201 + int max_range, new_range; 202 + 203 + new_range = ucontrol->value.integer.value[0]; 204 + max_range = micfil_get_max_range(micfil); 205 + if (new_range > max_range) 206 + dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4); 207 + 208 + regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift); 209 + 210 + return 0; 211 + } 212 + 176 213 static int micfil_set_quality(struct fsl_micfil *micfil) 177 214 { 178 - u32 qsel; 215 + int range, max_range; 216 + u32 qsel, val; 217 + int i; 218 + 219 + if (!micfil->soc->volume_sx) { 220 + regmap_read(micfil->regmap, REG_MICFIL_OUT_CTRL, &val); 221 + max_range = micfil_get_max_range(micfil); 222 + for (i = 0; i < micfil->soc->fifos; i++) { 223 + range = (val >> MICFIL_OUTGAIN_CHX_SHIFT(i)) & 0xF; 224 + if (range > max_range) 225 + dev_warn(&micfil->pdev->dev, "please reset channel %d range\n", i); 226 + } 227 + } 179 228 180 229 switch (micfil->quality) { 181 230 case QUALITY_HIGH: ··· 433 362 return 0; 434 363 } 435 364 436 - static const struct snd_kcontrol_new fsl_micfil_volume_controls[] = { 437 - SOC_SINGLE_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL, 438 - MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, gain_tlv), 439 - SOC_SINGLE_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL, 440 - MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, gain_tlv), 441 - SOC_SINGLE_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL, 442 - MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, gain_tlv), 443 - SOC_SINGLE_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL, 444 - MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, gain_tlv), 445 - SOC_SINGLE_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL, 446 - MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, gain_tlv), 447 - SOC_SINGLE_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL, 448 - MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, gain_tlv), 449 - SOC_SINGLE_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL, 450 - MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, gain_tlv), 451 - SOC_SINGLE_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL, 452 - MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, gain_tlv), 365 + static const struct snd_kcontrol_new fsl_micfil_range_controls[] = { 366 + SOC_SINGLE_EXT("CH0 Range", REG_MICFIL_OUT_CTRL, 367 + MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, 368 + snd_soc_get_volsw, micfil_range_set), 369 + SOC_SINGLE_EXT("CH1 Range", REG_MICFIL_OUT_CTRL, 370 + MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, 371 + snd_soc_get_volsw, micfil_range_set), 372 + SOC_SINGLE_EXT("CH2 Range", REG_MICFIL_OUT_CTRL, 373 + MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, 374 + snd_soc_get_volsw, micfil_range_set), 375 + SOC_SINGLE_EXT("CH3 Range", REG_MICFIL_OUT_CTRL, 376 + MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, 377 + snd_soc_get_volsw, micfil_range_set), 378 + SOC_SINGLE_EXT("CH4 Range", REG_MICFIL_OUT_CTRL, 379 + MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, 380 + snd_soc_get_volsw, micfil_range_set), 381 + SOC_SINGLE_EXT("CH5 Range", REG_MICFIL_OUT_CTRL, 382 + MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, 383 + snd_soc_get_volsw, micfil_range_set), 384 + SOC_SINGLE_EXT("CH6 Range", REG_MICFIL_OUT_CTRL, 385 + MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, 386 + snd_soc_get_volsw, micfil_range_set), 387 + SOC_SINGLE_EXT("CH7 Range", REG_MICFIL_OUT_CTRL, 388 + MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, 389 + snd_soc_get_volsw, micfil_range_set), 453 390 }; 454 391 455 392 static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls[] = { ··· 969 890 struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); 970 891 struct device *dev = cpu_dai->dev; 971 892 unsigned int val = 0; 972 - int ret, i; 893 + int ret, i, max_range; 973 894 974 - micfil->quality = QUALITY_VLOW0; 895 + micfil->quality = micfil->soc->default_quality; 975 896 micfil->card = cpu_dai->component->card; 976 897 977 898 /* set default gain to 2 */ 978 - regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); 899 + if (micfil->soc->volume_sx) { 900 + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); 901 + } else { 902 + max_range = micfil_get_max_range(micfil); 903 + for (i = 1; i < micfil->soc->fifos; i++) 904 + max_range |= max_range << 4; 905 + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, max_range); 906 + } 979 907 980 908 /* set DC Remover in bypass mode*/ 981 909 for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) ··· 1016 930 snd_soc_add_component_controls(component, fsl_micfil_volume_sx_controls, 1017 931 ARRAY_SIZE(fsl_micfil_volume_sx_controls)); 1018 932 else 1019 - snd_soc_add_component_controls(component, fsl_micfil_volume_controls, 1020 - ARRAY_SIZE(fsl_micfil_volume_controls)); 933 + snd_soc_add_component_controls(component, fsl_micfil_range_controls, 934 + ARRAY_SIZE(fsl_micfil_range_controls)); 1021 935 1022 936 return 0; 1023 937 }