1 // SPDX-License-Identifier: GPL-2.0 2 // 3 // MediaTek ALSA SoC Audio DAI I2S Control 4 // 5 // Copyright (c) 2022 MediaTek Inc. 6 // Author: Jiaxin Yu <jiaxin.yu@mediatek.com> 7 8 #include <linux/regmap.h> 9 #include <sound/pcm_params.h> 10 #include "mt8186-afe-common.h" 11 #include "mt8186-afe-gpio.h" 12 #include "mt8186-interconnection.h" 13 14 struct mtk_afe_pcm_priv { 15 unsigned int id; 16 unsigned int fmt; 17 unsigned int bck_invert; 18 unsigned int lck_invert; 19 }; 20 21 enum aud_tx_lch_rpt { 22 AUD_TX_LCH_RPT_NO_REPEAT = 0, 23 AUD_TX_LCH_RPT_REPEAT = 1 24 }; 25 26 enum aud_vbt_16k_mode { 27 AUD_VBT_16K_MODE_DISABLE = 0, 28 AUD_VBT_16K_MODE_ENABLE = 1 29 }; 30 31 enum aud_ext_modem { 32 AUD_EXT_MODEM_SELECT_INTERNAL = 0, 33 AUD_EXT_MODEM_SELECT_EXTERNAL = 1 34 }; 35 36 enum aud_pcm_sync_type { 37 /* bck sync length = 1 */ 38 AUD_PCM_ONE_BCK_CYCLE_SYNC = 0, 39 /* bck sync length = PCM_INTF_CON1[9:13] */ 40 AUD_PCM_EXTENDED_BCK_CYCLE_SYNC = 1 41 }; 42 43 enum aud_bt_mode { 44 AUD_BT_MODE_DUAL_MIC_ON_TX = 0, 45 AUD_BT_MODE_SINGLE_MIC_ON_TX = 1 46 }; 47 48 enum aud_pcm_afifo_src { 49 /* slave mode & external modem uses different crystal */ 50 AUD_PCM_AFIFO_ASRC = 0, 51 /* slave mode & external modem uses the same crystal */ 52 AUD_PCM_AFIFO_AFIFO = 1 53 }; 54 55 enum aud_pcm_clock_source { 56 AUD_PCM_CLOCK_MASTER_MODE = 0, 57 AUD_PCM_CLOCK_SLAVE_MODE = 1 58 }; 59 60 enum aud_pcm_wlen { 61 AUD_PCM_WLEN_PCM_32_BCK_CYCLES = 0, 62 AUD_PCM_WLEN_PCM_64_BCK_CYCLES = 1 63 }; 64 65 enum aud_pcm_24bit { 66 AUD_PCM_24BIT_PCM_16_BITS = 0, 67 AUD_PCM_24BIT_PCM_24_BITS = 1 68 }; 69 70 enum aud_pcm_mode { 71 AUD_PCM_MODE_PCM_MODE_8K = 0, 72 AUD_PCM_MODE_PCM_MODE_16K = 1, 73 AUD_PCM_MODE_PCM_MODE_32K = 2, 74 AUD_PCM_MODE_PCM_MODE_48K = 3, 75 }; 76 77 enum aud_pcm_fmt { 78 AUD_PCM_FMT_I2S = 0, 79 AUD_PCM_FMT_EIAJ = 1, 80 AUD_PCM_FMT_PCM_MODE_A = 2, 81 AUD_PCM_FMT_PCM_MODE_B = 3 82 }; 83 84 enum aud_bclk_out_inv { 85 AUD_BCLK_OUT_INV_NO_INVERSE = 0, 86 AUD_BCLK_OUT_INV_INVERSE = 1 87 }; 88 89 enum aud_lrclk_out_inv { 90 AUD_LRCLK_OUT_INV_NO_INVERSE = 0, 91 AUD_LRCLK_OUT_INV_INVERSE = 1 92 }; 93 94 enum aud_pcm_en { 95 AUD_PCM_EN_DISABLE = 0, 96 AUD_PCM_EN_ENABLE = 1 97 }; 98 99 /* dai component */ 100 static const struct snd_kcontrol_new mtk_pcm_1_playback_ch1_mix[] = { 101 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH1 Switch", AFE_CONN7, 102 I_ADDA_UL_CH1, 1, 0), 103 SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH1 Switch", AFE_CONN7, 104 I_DL2_CH1, 1, 0), 105 SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH1 Switch", AFE_CONN7_1, 106 I_DL4_CH1, 1, 0), 107 }; 108 109 static const struct snd_kcontrol_new mtk_pcm_1_playback_ch2_mix[] = { 110 SOC_DAPM_SINGLE_AUTODISABLE("ADDA_UL_CH2 Switch", AFE_CONN8, 111 I_ADDA_UL_CH2, 1, 0), 112 SOC_DAPM_SINGLE_AUTODISABLE("DL2_CH2 Switch", AFE_CONN8, 113 I_DL2_CH2, 1, 0), 114 SOC_DAPM_SINGLE_AUTODISABLE("DL4_CH2 Switch", AFE_CONN8_1, 115 I_DL4_CH2, 1, 0), 116 }; 117 118 static int mtk_pcm_en_event(struct snd_soc_dapm_widget *w, 119 struct snd_kcontrol *kcontrol, 120 int event) 121 { 122 struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 123 struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 124 125 dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", 126 __func__, w->name, event); 127 128 switch (event) { 129 case SND_SOC_DAPM_PRE_PMU: 130 mt8186_afe_gpio_request(afe->dev, true, MT8186_DAI_PCM, 0); 131 break; 132 case SND_SOC_DAPM_POST_PMD: 133 mt8186_afe_gpio_request(afe->dev, false, MT8186_DAI_PCM, 0); 134 break; 135 } 136 137 return 0; 138 } 139 140 /* pcm in/out lpbk */ 141 static const char * const pcm_lpbk_mux_map[] = { 142 "Normal", "Lpbk", 143 }; 144 145 static int pcm_lpbk_mux_map_value[] = { 146 0, 1, 147 }; 148 149 static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_in_lpbk_mux_map_enum, 150 PCM_INTF_CON1, 151 PCM_I2S_PCM_LOOPBACK_SFT, 152 1, 153 pcm_lpbk_mux_map, 154 pcm_lpbk_mux_map_value); 155 156 static const struct snd_kcontrol_new pcm_in_lpbk_mux_control = 157 SOC_DAPM_ENUM("PCM In Lpbk Select", pcm_in_lpbk_mux_map_enum); 158 159 static SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(pcm_out_lpbk_mux_map_enum, 160 PCM_INTF_CON1, 161 PCM_I2S_PCM_LOOPBACK_SFT, 162 1, 163 pcm_lpbk_mux_map, 164 pcm_lpbk_mux_map_value); 165 166 static const struct snd_kcontrol_new pcm_out_lpbk_mux_control = 167 SOC_DAPM_ENUM("PCM Out Lpbk Select", pcm_out_lpbk_mux_map_enum); 168 169 static const struct snd_soc_dapm_widget mtk_dai_pcm_widgets[] = { 170 /* inter-connections */ 171 SND_SOC_DAPM_MIXER("PCM_1_PB_CH1", SND_SOC_NOPM, 0, 0, 172 mtk_pcm_1_playback_ch1_mix, 173 ARRAY_SIZE(mtk_pcm_1_playback_ch1_mix)), 174 SND_SOC_DAPM_MIXER("PCM_1_PB_CH2", SND_SOC_NOPM, 0, 0, 175 mtk_pcm_1_playback_ch2_mix, 176 ARRAY_SIZE(mtk_pcm_1_playback_ch2_mix)), 177 178 SND_SOC_DAPM_SUPPLY("PCM_1_EN", 179 PCM_INTF_CON1, PCM_EN_SFT, 0, 180 mtk_pcm_en_event, 181 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 182 183 /* pcm in lpbk */ 184 SND_SOC_DAPM_MUX("PCM_In_Lpbk_Mux", 185 SND_SOC_NOPM, 0, 0, &pcm_in_lpbk_mux_control), 186 187 /* pcm out lpbk */ 188 SND_SOC_DAPM_MUX("PCM_Out_Lpbk_Mux", 189 SND_SOC_NOPM, 0, 0, &pcm_out_lpbk_mux_control), 190 }; 191 192 static const struct snd_soc_dapm_route mtk_dai_pcm_routes[] = { 193 {"PCM 1 Playback", NULL, "PCM_1_PB_CH1"}, 194 {"PCM 1 Playback", NULL, "PCM_1_PB_CH2"}, 195 196 {"PCM 1 Playback", NULL, "PCM_1_EN"}, 197 {"PCM 1 Capture", NULL, "PCM_1_EN"}, 198 199 {"PCM_1_PB_CH1", "DL2_CH1 Switch", "DL2"}, 200 {"PCM_1_PB_CH2", "DL2_CH2 Switch", "DL2"}, 201 202 {"PCM_1_PB_CH1", "DL4_CH1 Switch", "DL4"}, 203 {"PCM_1_PB_CH2", "DL4_CH2 Switch", "DL4"}, 204 205 /* pcm out lpbk */ 206 {"PCM_Out_Lpbk_Mux", "Lpbk", "PCM 1 Playback"}, 207 {"I2S0", NULL, "PCM_Out_Lpbk_Mux"}, 208 209 /* pcm in lpbk */ 210 {"PCM_In_Lpbk_Mux", "Lpbk", "PCM 1 Capture"}, 211 {"I2S3", NULL, "PCM_In_Lpbk_Mux"}, 212 }; 213 214 /* dai ops */ 215 static int mtk_dai_pcm_hw_params(struct snd_pcm_substream *substream, 216 struct snd_pcm_hw_params *params, 217 struct snd_soc_dai *dai) 218 { 219 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 220 struct mt8186_afe_private *afe_priv = afe->platform_priv; 221 int pcm_id = dai->id; 222 struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[pcm_id]; 223 unsigned int rate = params_rate(params); 224 unsigned int rate_reg = mt8186_rate_transform(afe->dev, rate, dai->id); 225 snd_pcm_format_t format = params_format(params); 226 unsigned int data_width = 227 snd_pcm_format_width(format); 228 unsigned int wlen_width = 229 snd_pcm_format_physical_width(format); 230 unsigned int pcm_con = 0; 231 232 dev_dbg(afe->dev, "%s(), id %d, stream %d, widget active p %d, c %d\n", 233 __func__, dai->id, substream->stream, dai->playback_widget->active, 234 dai->capture_widget->active); 235 dev_dbg(afe->dev, "%s(), rate %d, rate_reg %d, data_width %d, wlen_width %d\n", 236 __func__, rate, rate_reg, data_width, wlen_width); 237 238 if (dai->playback_widget->active || dai->capture_widget->active) 239 return 0; 240 241 switch (dai->id) { 242 case MT8186_DAI_PCM: 243 pcm_con |= AUD_TX_LCH_RPT_NO_REPEAT << PCM_TX_LCH_RPT_SFT; 244 pcm_con |= AUD_VBT_16K_MODE_DISABLE << PCM_VBT_16K_MODE_SFT; 245 pcm_con |= AUD_EXT_MODEM_SELECT_EXTERNAL << PCM_EXT_MODEM_SFT; 246 pcm_con |= AUD_PCM_ONE_BCK_CYCLE_SYNC << PCM_SYNC_TYPE_SFT; 247 pcm_con |= AUD_BT_MODE_DUAL_MIC_ON_TX << PCM_BT_MODE_SFT; 248 pcm_con |= AUD_PCM_AFIFO_AFIFO << PCM_BYP_ASRC_SFT; 249 pcm_con |= AUD_PCM_CLOCK_MASTER_MODE << PCM_SLAVE_SFT; 250 pcm_con |= 0 << PCM_SYNC_LENGTH_SFT; 251 252 /* sampling rate */ 253 pcm_con |= rate_reg << PCM_MODE_SFT; 254 255 /* format */ 256 pcm_con |= pcm_priv->fmt << PCM_FMT_SFT; 257 258 /* 24bit data width */ 259 if (data_width > 16) 260 pcm_con |= AUD_PCM_24BIT_PCM_24_BITS << PCM_24BIT_SFT; 261 else 262 pcm_con |= AUD_PCM_24BIT_PCM_16_BITS << PCM_24BIT_SFT; 263 264 /* wlen width*/ 265 if (wlen_width > 16) 266 pcm_con |= AUD_PCM_WLEN_PCM_64_BCK_CYCLES << PCM_WLEN_SFT; 267 else 268 pcm_con |= AUD_PCM_WLEN_PCM_32_BCK_CYCLES << PCM_WLEN_SFT; 269 270 /* clock invert */ 271 pcm_con |= pcm_priv->lck_invert << PCM_SYNC_OUT_INV_SFT; 272 pcm_con |= pcm_priv->bck_invert << PCM_BCLK_OUT_INV_SFT; 273 274 regmap_update_bits(afe->regmap, PCM_INTF_CON1, 0xfffffffe, pcm_con); 275 break; 276 default: 277 dev_err(afe->dev, "%s(), id %d not support\n", __func__, dai->id); 278 return -EINVAL; 279 } 280 281 return 0; 282 } 283 284 static int mtk_dai_pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 285 { 286 struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 287 struct mt8186_afe_private *afe_priv = afe->platform_priv; 288 struct mtk_afe_pcm_priv *pcm_priv = afe_priv->dai_priv[dai->id]; 289 290 /* DAI mode*/ 291 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 292 case SND_SOC_DAIFMT_I2S: 293 pcm_priv->fmt = AUD_PCM_FMT_I2S; 294 break; 295 case SND_SOC_DAIFMT_LEFT_J: 296 pcm_priv->fmt = AUD_PCM_FMT_EIAJ; 297 break; 298 case SND_SOC_DAIFMT_DSP_A: 299 pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_A; 300 break; 301 case SND_SOC_DAIFMT_DSP_B: 302 pcm_priv->fmt = AUD_PCM_FMT_PCM_MODE_B; 303 break; 304 default: 305 pcm_priv->fmt = AUD_PCM_FMT_I2S; 306 } 307 308 /* DAI clock inversion*/ 309 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 310 case SND_SOC_DAIFMT_NB_NF: 311 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; 312 pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; 313 break; 314 case SND_SOC_DAIFMT_NB_IF: 315 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; 316 pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE; 317 break; 318 case SND_SOC_DAIFMT_IB_NF: 319 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE; 320 pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; 321 break; 322 case SND_SOC_DAIFMT_IB_IF: 323 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_INVERSE; 324 pcm_priv->lck_invert = AUD_BCLK_OUT_INV_INVERSE; 325 break; 326 default: 327 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; 328 pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; 329 break; 330 } 331 332 return 0; 333 } 334 335 static const struct snd_soc_dai_ops mtk_dai_pcm_ops = { 336 .hw_params = mtk_dai_pcm_hw_params, 337 .set_fmt = mtk_dai_pcm_set_fmt, 338 }; 339 340 /* dai driver */ 341 #define MTK_PCM_RATES (SNDRV_PCM_RATE_8000 |\ 342 SNDRV_PCM_RATE_16000 |\ 343 SNDRV_PCM_RATE_32000 |\ 344 SNDRV_PCM_RATE_48000) 345 346 #define MTK_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 347 SNDRV_PCM_FMTBIT_S24_LE |\ 348 SNDRV_PCM_FMTBIT_S32_LE) 349 350 static struct snd_soc_dai_driver mtk_dai_pcm_driver[] = { 351 { 352 .name = "PCM 1", 353 .id = MT8186_DAI_PCM, 354 .playback = { 355 .stream_name = "PCM 1 Playback", 356 .channels_min = 1, 357 .channels_max = 2, 358 .rates = MTK_PCM_RATES, 359 .formats = MTK_PCM_FORMATS, 360 }, 361 .capture = { 362 .stream_name = "PCM 1 Capture", 363 .channels_min = 1, 364 .channels_max = 2, 365 .rates = MTK_PCM_RATES, 366 .formats = MTK_PCM_FORMATS, 367 }, 368 .ops = &mtk_dai_pcm_ops, 369 .symmetric_rate = 1, 370 .symmetric_sample_bits = 1, 371 }, 372 }; 373 374 static struct mtk_afe_pcm_priv *init_pcm_priv_data(struct mtk_base_afe *afe) 375 { 376 struct mtk_afe_pcm_priv *pcm_priv; 377 378 pcm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_pcm_priv), 379 GFP_KERNEL); 380 if (!pcm_priv) 381 return NULL; 382 383 pcm_priv->id = MT8186_DAI_PCM; 384 pcm_priv->fmt = AUD_PCM_FMT_I2S; 385 pcm_priv->bck_invert = AUD_BCLK_OUT_INV_NO_INVERSE; 386 pcm_priv->lck_invert = AUD_LRCLK_OUT_INV_NO_INVERSE; 387 388 return pcm_priv; 389 } 390 391 int mt8186_dai_pcm_register(struct mtk_base_afe *afe) 392 { 393 struct mt8186_afe_private *afe_priv = afe->platform_priv; 394 struct mtk_afe_pcm_priv *pcm_priv; 395 struct mtk_base_afe_dai *dai; 396 397 dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); 398 if (!dai) 399 return -ENOMEM; 400 401 list_add(&dai->list, &afe->sub_dais); 402 403 dai->dai_drivers = mtk_dai_pcm_driver; 404 dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_pcm_driver); 405 406 dai->dapm_widgets = mtk_dai_pcm_widgets; 407 dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_pcm_widgets); 408 dai->dapm_routes = mtk_dai_pcm_routes; 409 dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_pcm_routes); 410 411 pcm_priv = init_pcm_priv_data(afe); 412 if (!pcm_priv) 413 return -ENOMEM; 414 415 afe_priv->dai_priv[MT8186_DAI_PCM] = pcm_priv; 416 417 return 0; 418 } 419