1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // MediaTek ALSA SoC Audio DAI ADDA Control 4 // 5 // Copyright (c) 2018 MediaTek Inc. 6 // Author: KaiChieh Chuang <kaichieh.chuang@mediatek.com> 7 8 #include <linux/regmap.h> 9 #include <linux/delay.h> 10 #include "mt6797-afe-common.h" 11 #include "mt6797-interconnection.h" 12 #include "mt6797-reg.h" 13 #include "../common/mtk-dai-adda-common.h" 14 15 /* dai component */ 16 static const struct snd_kcontrol_new mtk_adda_dl_ch1_mix[] = { 17 SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN3, I_DL1_CH1, 1, 0), 18 SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN3, I_DL2_CH1, 1, 0), 19 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN3, I_DL3_CH1, 1, 0), 20 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN3, 21 I_ADDA_UL_CH2, 1, 0), 22 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN3, 23 I_ADDA_UL_CH1, 1, 0), 24 SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN3, 25 I_PCM_1_CAP_CH1, 1, 0), 26 SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN3, 27 I_PCM_2_CAP_CH1, 1, 0), 28 }; 29 30 static const struct snd_kcontrol_new mtk_adda_dl_ch2_mix[] = { 31 SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH1", AFE_CONN4, I_DL1_CH1, 1, 0), 32 SOC_DAPM_SINGLE_AUTODISABLE("DL1_CH2", AFE_CONN4, I_DL1_CH2, 1, 0), 33 SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1", AFE_CONN4, I_DL2_CH1, 1, 0), 34 SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2", AFE_CONN4, I_DL2_CH2, 1, 0), 35 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH1", AFE_CONN4, I_DL3_CH1, 1, 0), 36 SOC_DAPM_SINGLE_AUTODISABLE("DL3_CH2", AFE_CONN4, I_DL3_CH2, 1, 0), 37 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2", AFE_CONN4, 38 I_ADDA_UL_CH2, 1, 0), 39 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1", AFE_CONN4, 40 I_ADDA_UL_CH1, 1, 0), 41 SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH1", AFE_CONN4, 42 I_PCM_1_CAP_CH1, 1, 0), 43 SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH1", AFE_CONN4, 44 I_PCM_2_CAP_CH1, 1, 0), 45 SOC_DAPM_SINGLE_AUTODISABLE("PCM_1_CAP_CH2", AFE_CONN4, 46 I_PCM_1_CAP_CH2, 1, 0), 47 SOC_DAPM_SINGLE_AUTODISABLE("PCM_2_CAP_CH2", AFE_CONN4, 48 I_PCM_2_CAP_CH2, 1, 0), 49 }; 50 51 static int mtk_adda_ul_event(struct snd_soc_dapm_widget *w, 52 struct snd_kcontrol *kcontrol, 53 int event) 54 { 55 struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 56 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 57 58 dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", 59 __func__, w->name, event); 60 61 switch (event) { 62 case SND_SOC_DAPM_POST_PMD: 63 /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ 64 usleep_range(125, 135); 65 break; 66 default: 67 break; 68 } 69 70 return 0; 71 } 72 73 enum { 74 SUPPLY_SEQ_AUD_TOP_PDN, 75 SUPPLY_SEQ_ADDA_AFE_ON, 76 SUPPLY_SEQ_ADDA_DL_ON, 77 SUPPLY_SEQ_ADDA_UL_ON, 78 }; 79 80 static const struct snd_soc_dapm_widget mtk_dai_adda_widgets[] = { 81 /* adda */ 82 SND_SOC_DAPM_MIXER("ADDA_DL_CH1", SND_SOC_NOPM, 0, 0, 83 mtk_adda_dl_ch1_mix, 84 ARRAY_SIZE(mtk_adda_dl_ch1_mix)), 85 SND_SOC_DAPM_MIXER("ADDA_DL_CH2", SND_SOC_NOPM, 0, 0, 86 mtk_adda_dl_ch2_mix, 87 ARRAY_SIZE(mtk_adda_dl_ch2_mix)), 88 89 SND_SOC_DAPM_SUPPLY_S("ADDA Enable", SUPPLY_SEQ_ADDA_AFE_ON, 90 AFE_ADDA_UL_DL_CON0, ADDA_AFE_ON_SFT, 0, 91 NULL, 0), 92 93 SND_SOC_DAPM_SUPPLY_S("ADDA Playback Enable", SUPPLY_SEQ_ADDA_DL_ON, 94 AFE_ADDA_DL_SRC2_CON0, 95 DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, 96 NULL, 0), 97 98 SND_SOC_DAPM_SUPPLY_S("ADDA Capture Enable", SUPPLY_SEQ_ADDA_UL_ON, 99 AFE_ADDA_UL_SRC_CON0, 100 UL_SRC_ON_TMP_CTL_SFT, 0, 101 mtk_adda_ul_event, 102 SND_SOC_DAPM_POST_PMD), 103 104 SND_SOC_DAPM_SUPPLY_S("aud_dac_clk", SUPPLY_SEQ_AUD_TOP_PDN, 105 AUDIO_TOP_CON0, PDN_DAC_SFT, 1, 106 NULL, 0), 107 SND_SOC_DAPM_SUPPLY_S("aud_dac_predis_clk", SUPPLY_SEQ_AUD_TOP_PDN, 108 AUDIO_TOP_CON0, PDN_DAC_PREDIS_SFT, 1, 109 NULL, 0), 110 111 SND_SOC_DAPM_SUPPLY_S("aud_adc_clk", SUPPLY_SEQ_AUD_TOP_PDN, 112 AUDIO_TOP_CON0, PDN_ADC_SFT, 1, 113 NULL, 0), 114 115 SND_SOC_DAPM_CLOCK_SUPPLY("mtkaif_26m_clk"), 116 }; 117 118 static const struct snd_soc_dapm_route mtk_dai_adda_routes[] = { 119 /* playback */ 120 {"ADDA_DL_CH1", "DL1_CH1", "DL1"}, 121 {"ADDA_DL_CH2", "DL1_CH1", "DL1"}, 122 {"ADDA_DL_CH2", "DL1_CH2", "DL1"}, 123 124 {"ADDA_DL_CH1", "DL2_CH1", "DL2"}, 125 {"ADDA_DL_CH2", "DL2_CH1", "DL2"}, 126 {"ADDA_DL_CH2", "DL2_CH2", "DL2"}, 127 128 {"ADDA_DL_CH1", "DL3_CH1", "DL3"}, 129 {"ADDA_DL_CH2", "DL3_CH1", "DL3"}, 130 {"ADDA_DL_CH2", "DL3_CH2", "DL3"}, 131 132 {"ADDA Playback", NULL, "ADDA_DL_CH1"}, 133 {"ADDA Playback", NULL, "ADDA_DL_CH2"}, 134 135 /* adda enable */ 136 {"ADDA Playback", NULL, "ADDA Enable"}, 137 {"ADDA Playback", NULL, "ADDA Playback Enable"}, 138 {"ADDA Capture", NULL, "ADDA Enable"}, 139 {"ADDA Capture", NULL, "ADDA Capture Enable"}, 140 141 /* clk */ 142 {"ADDA Playback", NULL, "mtkaif_26m_clk"}, 143 {"ADDA Playback", NULL, "aud_dac_clk"}, 144 {"ADDA Playback", NULL, "aud_dac_predis_clk"}, 145 146 {"ADDA Capture", NULL, "mtkaif_26m_clk"}, 147 {"ADDA Capture", NULL, "aud_adc_clk"}, 148 }; 149 150 /* dai ops */ 151 static int mtk_dai_adda_hw_params(struct snd_pcm_substream *substream, 152 struct snd_pcm_hw_params *params, 153 struct snd_soc_dai *dai) 154 { 155 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 156 unsigned int rate = params_rate(params); 157 158 dev_dbg(afe->dev, "%s(), id %d, stream %d, rate %d\n", 159 __func__, dai->id, substream->stream, rate); 160 161 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 162 unsigned int dl_src2_con0 = 0; 163 unsigned int dl_src2_con1 = 0; 164 165 /* clean predistortion */ 166 regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON0, 0); 167 regmap_write(afe->regmap, AFE_ADDA_PREDIS_CON1, 0); 168 169 /* set input sampling rate */ 170 dl_src2_con0 = mtk_adda_dl_rate_transform(afe, rate) << 28; 171 172 /* set output mode */ 173 switch (rate) { 174 case 192000: 175 dl_src2_con0 |= (0x1 << 24); /* UP_SAMPLING_RATE_X2 */ 176 dl_src2_con0 |= 1 << 14; 177 break; 178 case 96000: 179 dl_src2_con0 |= (0x2 << 24); /* UP_SAMPLING_RATE_X4 */ 180 dl_src2_con0 |= 1 << 14; 181 break; 182 default: 183 dl_src2_con0 |= (0x3 << 24); /* UP_SAMPLING_RATE_X8 */ 184 break; 185 } 186 187 /* turn off mute function */ 188 dl_src2_con0 |= (0x03 << 11); 189 190 /* set voice input data if input sample rate is 8k or 16k */ 191 if (rate == 8000 || rate == 16000) 192 dl_src2_con0 |= 0x01 << 5; 193 194 if (rate < 96000) { 195 /* SA suggest apply -0.3db to audio/speech path */ 196 dl_src2_con1 = 0xf74f0000; 197 } else { 198 /* SA suggest apply -0.3db to audio/speech path 199 * with DL gain set to half, 200 * 0xFFFF = 0dB -> 0x8000 = 0dB when 96k, 192k 201 */ 202 dl_src2_con1 = 0x7ba70000; 203 } 204 205 /* turn on down-link gain */ 206 dl_src2_con0 = dl_src2_con0 | (0x01 << 1); 207 208 regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON0, dl_src2_con0); 209 regmap_write(afe->regmap, AFE_ADDA_DL_SRC2_CON1, dl_src2_con1); 210 } else { 211 unsigned int voice_mode = 0; 212 unsigned int ul_src_con0 = 0; /* default value */ 213 214 /* Using Internal ADC */ 215 regmap_update_bits(afe->regmap, 216 AFE_ADDA_TOP_CON0, 217 0x1 << 0, 218 0x0 << 0); 219 220 voice_mode = mtk_adda_ul_rate_transform(afe, rate); 221 222 ul_src_con0 |= (voice_mode << 17) & (0x7 << 17); 223 224 /* up8x txif sat on */ 225 regmap_write(afe->regmap, AFE_ADDA_NEWIF_CFG0, 0x03F87201); 226 227 if (rate >= 96000) { /* hires */ 228 /* use hires format [1 0 23] */ 229 regmap_update_bits(afe->regmap, 230 AFE_ADDA_NEWIF_CFG0, 231 0x1 << 5, 232 0x1 << 5); 233 234 regmap_update_bits(afe->regmap, 235 AFE_ADDA_NEWIF_CFG2, 236 0xf << 28, 237 voice_mode << 28); 238 } else { /* normal 8~48k */ 239 /* use fixed 260k anc path */ 240 regmap_update_bits(afe->regmap, 241 AFE_ADDA_NEWIF_CFG2, 242 0xf << 28, 243 8 << 28); 244 245 /* ul_use_cic_out */ 246 ul_src_con0 |= 0x1 << 20; 247 } 248 249 regmap_update_bits(afe->regmap, 250 AFE_ADDA_NEWIF_CFG2, 251 0xf << 28, 252 8 << 28); 253 254 regmap_update_bits(afe->regmap, 255 AFE_ADDA_UL_SRC_CON0, 256 0xfffffffe, 257 ul_src_con0); 258 } 259 260 return 0; 261 } 262 263 static const struct snd_soc_dai_ops mtk_dai_adda_ops = { 264 .hw_params = mtk_dai_adda_hw_params, 265 }; 266 267 /* dai driver */ 268 #define MTK_ADDA_PLAYBACK_RATES (SNDRV_PCM_RATE_8000_48000 |\ 269 SNDRV_PCM_RATE_96000 |\ 270 SNDRV_PCM_RATE_192000) 271 272 #define MTK_ADDA_CAPTURE_RATES (SNDRV_PCM_RATE_8000 |\ 273 SNDRV_PCM_RATE_16000 |\ 274 SNDRV_PCM_RATE_32000 |\ 275 SNDRV_PCM_RATE_48000 |\ 276 SNDRV_PCM_RATE_96000 |\ 277 SNDRV_PCM_RATE_192000) 278 279 #define MTK_ADDA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 280 SNDRV_PCM_FMTBIT_S24_LE |\ 281 SNDRV_PCM_FMTBIT_S32_LE) 282 283 static struct snd_soc_dai_driver mtk_dai_adda_driver[] = { 284 { 285 .name = "ADDA", 286 .id = MT6797_DAI_ADDA, 287 .playback = { 288 .stream_name = "ADDA Playback", 289 .channels_min = 1, 290 .channels_max = 2, 291 .rates = MTK_ADDA_PLAYBACK_RATES, 292 .formats = MTK_ADDA_FORMATS, 293 }, 294 .capture = { 295 .stream_name = "ADDA Capture", 296 .channels_min = 1, 297 .channels_max = 2, 298 .rates = MTK_ADDA_CAPTURE_RATES, 299 .formats = MTK_ADDA_FORMATS, 300 }, 301 .ops = &mtk_dai_adda_ops, 302 }, 303 }; 304 305 int mt6797_dai_adda_register(struct mtk_base_afe *afe) 306 { 307 struct mtk_base_afe_dai *dai; 308 309 dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); 310 if (!dai) 311 return -ENOMEM; 312 313 list_add(&dai->list, &afe->sub_dais); 314 315 dai->dai_drivers = mtk_dai_adda_driver; 316 dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_adda_driver); 317 318 dai->dapm_widgets = mtk_dai_adda_widgets; 319 dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_adda_widgets); 320 dai->dapm_routes = mtk_dai_adda_routes; 321 dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_adda_routes); 322 return 0; 323 } 324
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.