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

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: mediatek: mt8189: support TDM in platform driver

Add mt8189 TDM DAI driver support.

Signed-off-by: Cyril Chao <Cyril.Chao@mediatek.com>
Link: https://patch.msgid.link/20251031073216.8662-6-Cyril.Chao@mediatek.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Cyril Chao and committed by
Mark Brown
9f202872 34e43709

+672
+672
sound/soc/mediatek/mt8189/mt8189-dai-tdm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * MediaTek ALSA SoC Audio DAI TDM Control 4 + * 5 + * Copyright (c) 2025 MediaTek Inc. 6 + * Author: Darren Ye <darren.ye@mediatek.com> 7 + */ 8 + 9 + #include <linux/regmap.h> 10 + 11 + #include <sound/pcm_params.h> 12 + 13 + #include "mt8189-afe-clk.h" 14 + #include "mt8189-afe-common.h" 15 + #include "mt8189-interconnection.h" 16 + 17 + #define DPTX_CH_EN_MASK_2CH (0x3) 18 + #define DPTX_CH_EN_MASK_4CH (0xf) 19 + #define DPTX_CH_EN_MASK_6CH (0x3f) 20 + #define DPTX_CH_EN_MASK_8CH (0xff) 21 + 22 + enum { 23 + SUPPLY_SEQ_APLL, 24 + SUPPLY_SEQ_TDM_MCK_EN, 25 + SUPPLY_SEQ_TDM_BCK_EN, 26 + SUPPLY_SEQ_TDM_DPTX_MCK_EN, 27 + SUPPLY_SEQ_TDM_DPTX_BCK_EN, 28 + SUPPLY_SEQ_TDM_CG_EN, 29 + }; 30 + 31 + enum { 32 + TDM_WLEN_8_BIT, 33 + TDM_WLEN_16_BIT, 34 + TDM_WLEN_24_BIT, 35 + TDM_WLEN_32_BIT, 36 + }; 37 + 38 + enum { 39 + TDM_CHANNEL_BCK_16, 40 + TDM_CHANNEL_BCK_24, 41 + TDM_CHANNEL_BCK_32 42 + }; 43 + 44 + enum { 45 + TDM_CHANNEL_NUM_2, 46 + TDM_CHANNEL_NUM_4, 47 + TDM_CHANNEL_NUM_8 48 + }; 49 + 50 + enum { 51 + TDM_CH_START_O30_O31, 52 + TDM_CH_START_O32_O33, 53 + TDM_CH_START_O34_O35, 54 + TDM_CH_START_O36_O37, 55 + TDM_CH_ZERO, 56 + }; 57 + 58 + enum { 59 + DPTX_CHANNEL_2, 60 + DPTX_CHANNEL_8, 61 + }; 62 + 63 + enum { 64 + DPTX_WLEN_24_BIT, 65 + DPTX_WLEN_16_BIT, 66 + }; 67 + 68 + struct mtk_afe_tdm_priv { 69 + int bck_id; 70 + int bck_rate; 71 + 72 + int mclk_id; 73 + int mclk_multiple; /* according to sample rate */ 74 + int mclk_rate; 75 + int mclk_apll; 76 + }; 77 + 78 + static unsigned int get_tdm_wlen(snd_pcm_format_t format) 79 + { 80 + return snd_pcm_format_physical_width(format) <= 16 ? 81 + TDM_WLEN_16_BIT : TDM_WLEN_32_BIT; 82 + } 83 + 84 + static unsigned int get_tdm_channel_bck(snd_pcm_format_t format) 85 + { 86 + return snd_pcm_format_physical_width(format) <= 16 ? 87 + TDM_CHANNEL_BCK_16 : TDM_CHANNEL_BCK_32; 88 + } 89 + 90 + static unsigned int get_tdm_lrck_width(snd_pcm_format_t format) 91 + { 92 + return snd_pcm_format_physical_width(format) - 1; 93 + } 94 + 95 + static unsigned int get_tdm_ch(unsigned int ch) 96 + { 97 + switch (ch) { 98 + case 1: 99 + case 2: 100 + return TDM_CHANNEL_NUM_2; 101 + case 3: 102 + case 4: 103 + return TDM_CHANNEL_NUM_4; 104 + case 5: 105 + case 6: 106 + case 7: 107 + case 8: 108 + default: 109 + return TDM_CHANNEL_NUM_8; 110 + } 111 + } 112 + 113 + static unsigned int get_dptx_ch_enable_mask(unsigned int ch) 114 + { 115 + switch (ch) { 116 + case 1: 117 + case 2: 118 + return DPTX_CH_EN_MASK_2CH; 119 + case 3: 120 + case 4: 121 + return DPTX_CH_EN_MASK_4CH; 122 + case 5: 123 + case 6: 124 + return DPTX_CH_EN_MASK_6CH; 125 + case 7: 126 + case 8: 127 + return DPTX_CH_EN_MASK_8CH; 128 + default: 129 + return DPTX_CH_EN_MASK_2CH; 130 + } 131 + } 132 + 133 + static unsigned int get_dptx_ch(unsigned int ch) 134 + { 135 + if (ch == 2) 136 + return DPTX_CHANNEL_2; 137 + 138 + return DPTX_CHANNEL_8; 139 + } 140 + 141 + static unsigned int get_dptx_wlen(snd_pcm_format_t format) 142 + { 143 + return snd_pcm_format_physical_width(format) <= 16 ? 144 + DPTX_WLEN_16_BIT : DPTX_WLEN_24_BIT; 145 + } 146 + 147 + /* interconnection */ 148 + enum { 149 + HDMI_CONN_CH0, 150 + HDMI_CONN_CH1, 151 + HDMI_CONN_CH2, 152 + HDMI_CONN_CH3, 153 + HDMI_CONN_CH4, 154 + HDMI_CONN_CH5, 155 + HDMI_CONN_CH6, 156 + HDMI_CONN_CH7, 157 + }; 158 + 159 + static const char *const hdmi_conn_mux_map[] = { 160 + "CH0", "CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", 161 + }; 162 + 163 + static int hdmi_conn_mux_map_value[] = { 164 + HDMI_CONN_CH0, HDMI_CONN_CH1, HDMI_CONN_CH2, HDMI_CONN_CH3, 165 + HDMI_CONN_CH4, HDMI_CONN_CH5, HDMI_CONN_CH6, HDMI_CONN_CH7, 166 + }; 167 + 168 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch0_mux_map_enum, 169 + AFE_HDMI_CONN0, 170 + HDMI_O_0_SFT, 171 + HDMI_O_0_MASK, 172 + hdmi_conn_mux_map, 173 + hdmi_conn_mux_map_value); 174 + 175 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch1_mux_map_enum, 176 + AFE_HDMI_CONN0, 177 + HDMI_O_1_SFT, 178 + HDMI_O_1_MASK, 179 + hdmi_conn_mux_map, 180 + hdmi_conn_mux_map_value); 181 + 182 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch2_mux_map_enum, 183 + AFE_HDMI_CONN0, 184 + HDMI_O_2_SFT, 185 + HDMI_O_2_MASK, 186 + hdmi_conn_mux_map, 187 + hdmi_conn_mux_map_value); 188 + 189 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch3_mux_map_enum, 190 + AFE_HDMI_CONN0, 191 + HDMI_O_3_SFT, 192 + HDMI_O_3_MASK, 193 + hdmi_conn_mux_map, 194 + hdmi_conn_mux_map_value); 195 + 196 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch4_mux_map_enum, 197 + AFE_HDMI_CONN0, 198 + HDMI_O_4_SFT, 199 + HDMI_O_4_MASK, 200 + hdmi_conn_mux_map, 201 + hdmi_conn_mux_map_value); 202 + 203 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch5_mux_map_enum, 204 + AFE_HDMI_CONN0, 205 + HDMI_O_5_SFT, 206 + HDMI_O_5_MASK, 207 + hdmi_conn_mux_map, 208 + hdmi_conn_mux_map_value); 209 + 210 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch6_mux_map_enum, 211 + AFE_HDMI_CONN0, 212 + HDMI_O_6_SFT, 213 + HDMI_O_6_MASK, 214 + hdmi_conn_mux_map, 215 + hdmi_conn_mux_map_value); 216 + 217 + static SOC_VALUE_ENUM_SINGLE_DECL(hdmi_ch7_mux_map_enum, 218 + AFE_HDMI_CONN0, 219 + HDMI_O_7_SFT, 220 + HDMI_O_7_MASK, 221 + hdmi_conn_mux_map, 222 + hdmi_conn_mux_map_value); 223 + 224 + static const struct snd_kcontrol_new mtk_dai_tdm_controls[] = { 225 + SOC_ENUM("HDMI_CH0_MUX", hdmi_ch0_mux_map_enum), 226 + SOC_ENUM("HDMI_CH1_MUX", hdmi_ch1_mux_map_enum), 227 + SOC_ENUM("HDMI_CH2_MUX", hdmi_ch2_mux_map_enum), 228 + SOC_ENUM("HDMI_CH3_MUX", hdmi_ch3_mux_map_enum), 229 + SOC_ENUM("HDMI_CH4_MUX", hdmi_ch4_mux_map_enum), 230 + SOC_ENUM("HDMI_CH5_MUX", hdmi_ch5_mux_map_enum), 231 + SOC_ENUM("HDMI_CH6_MUX", hdmi_ch6_mux_map_enum), 232 + SOC_ENUM("HDMI_CH7_MUX", hdmi_ch7_mux_map_enum), 233 + }; 234 + 235 + static const char *const tdm_out_demux_texts[] = { 236 + "NONE", "TDMOUT", "DPTXOUT", 237 + }; 238 + 239 + static SOC_ENUM_SINGLE_DECL(tdm_out_demux_enum, 240 + SND_SOC_NOPM, 241 + 0, 242 + tdm_out_demux_texts); 243 + 244 + static const struct snd_kcontrol_new tdm_out_demux_control = 245 + SOC_DAPM_ENUM("TDM Playback Route", tdm_out_demux_enum); 246 + 247 + static int get_tdm_id_by_name(const char *name) 248 + { 249 + if (strstr(name, "DPTX")) 250 + return MT8189_DAI_TDM_DPTX; 251 + 252 + return MT8189_DAI_TDM; 253 + } 254 + 255 + static int mtk_tdm_bck_en_event(struct snd_soc_dapm_widget *w, 256 + struct snd_kcontrol *kcontrol, 257 + int event) 258 + { 259 + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 260 + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 261 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 262 + int dai_id = get_tdm_id_by_name(w->name); 263 + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 264 + 265 + dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, bck: %d\n", 266 + w->name, event, dai_id, tdm_priv->bck_rate); 267 + 268 + switch (event) { 269 + case SND_SOC_DAPM_PRE_PMU: 270 + mt8189_mck_enable(afe, tdm_priv->bck_id, tdm_priv->bck_rate); 271 + break; 272 + case SND_SOC_DAPM_POST_PMD: 273 + mt8189_mck_disable(afe, tdm_priv->bck_id); 274 + break; 275 + default: 276 + break; 277 + } 278 + 279 + return 0; 280 + } 281 + 282 + static int mtk_tdm_mck_en_event(struct snd_soc_dapm_widget *w, 283 + struct snd_kcontrol *kcontrol, 284 + int event) 285 + { 286 + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); 287 + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 288 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 289 + int dai_id = get_tdm_id_by_name(w->name); 290 + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 291 + 292 + dev_dbg(cmpnt->dev, "name %s, event 0x%x, dai_id %d, mclk %d\n", 293 + w->name, event, dai_id, tdm_priv->mclk_rate); 294 + 295 + switch (event) { 296 + case SND_SOC_DAPM_PRE_PMU: 297 + mt8189_mck_enable(afe, tdm_priv->mclk_id, tdm_priv->mclk_rate); 298 + break; 299 + case SND_SOC_DAPM_POST_PMD: 300 + tdm_priv->mclk_rate = 0; 301 + mt8189_mck_disable(afe, tdm_priv->mclk_id); 302 + break; 303 + default: 304 + break; 305 + } 306 + 307 + return 0; 308 + } 309 + 310 + static const struct snd_soc_dapm_widget mtk_dai_tdm_widgets[] = { 311 + SND_SOC_DAPM_DEMUX("TDM Playback Route", SND_SOC_NOPM, 0, 0, 312 + &tdm_out_demux_control), 313 + 314 + SND_SOC_DAPM_SUPPLY_S("TDM_BCK", SUPPLY_SEQ_TDM_BCK_EN, 315 + SND_SOC_NOPM, 0, 0, 316 + mtk_tdm_bck_en_event, 317 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 318 + 319 + SND_SOC_DAPM_SUPPLY_S("TDM_MCK", SUPPLY_SEQ_TDM_MCK_EN, 320 + SND_SOC_NOPM, 0, 0, 321 + mtk_tdm_mck_en_event, 322 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 323 + 324 + SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_BCK", SUPPLY_SEQ_TDM_DPTX_BCK_EN, 325 + SND_SOC_NOPM, 0, 0, 326 + mtk_tdm_bck_en_event, 327 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 328 + 329 + SND_SOC_DAPM_SUPPLY_S("TDM_DPTX_MCK", SUPPLY_SEQ_TDM_DPTX_MCK_EN, 330 + SND_SOC_NOPM, 0, 0, 331 + mtk_tdm_mck_en_event, 332 + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 333 + 334 + SND_SOC_DAPM_SUPPLY_S("TDM_CG", SUPPLY_SEQ_TDM_CG_EN, 335 + AUDIO_TOP_CON2, PDN_TDM_OUT_SFT, 1, 336 + NULL, 0), 337 + }; 338 + 339 + static int mtk_afe_tdm_apll_connect(struct snd_soc_dapm_widget *source, 340 + struct snd_soc_dapm_widget *sink) 341 + { 342 + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(sink->dapm); 343 + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); 344 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 345 + int dai_id = get_tdm_id_by_name(sink->name); 346 + struct mtk_afe_tdm_priv *tdm_priv = afe_priv->dai_priv[dai_id]; 347 + int cur_apll; 348 + 349 + /* which apll */ 350 + cur_apll = mt8189_get_apll_by_name(afe, source->name); 351 + 352 + return (tdm_priv->mclk_apll == cur_apll) ? 1 : 0; 353 + } 354 + 355 + static const struct snd_soc_dapm_route mtk_dai_tdm_routes[] = { 356 + {"TDM Playback Route", NULL, "HDMI"}, 357 + 358 + {"TDM", "TDMOUT", "TDM Playback Route"}, 359 + {"TDM", NULL, "TDM_BCK"}, 360 + {"TDM", NULL, "TDM_CG"}, 361 + 362 + {"TDM_DPTX", "DPTXOUT", "TDM Playback Route"}, 363 + {"TDM_DPTX", NULL, "TDM_DPTX_BCK"}, 364 + {"TDM_DPTX", NULL, "TDM_CG"}, 365 + 366 + {"TDM_BCK", NULL, "TDM_MCK"}, 367 + {"TDM_DPTX_BCK", NULL, "TDM_DPTX_MCK"}, 368 + {"TDM_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, 369 + {"TDM_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, 370 + {"TDM_DPTX_MCK", NULL, APLL1_W_NAME, mtk_afe_tdm_apll_connect}, 371 + {"TDM_DPTX_MCK", NULL, APLL2_W_NAME, mtk_afe_tdm_apll_connect}, 372 + }; 373 + 374 + /* dai ops */ 375 + static int mtk_dai_tdm_cal_mclk(struct mtk_base_afe *afe, 376 + struct mtk_afe_tdm_priv *tdm_priv, 377 + int freq) 378 + { 379 + int apll; 380 + int apll_rate; 381 + 382 + apll = mt8189_get_apll_by_rate(afe, freq); 383 + apll_rate = mt8189_get_apll_rate(afe, apll); 384 + 385 + if (freq > apll_rate) 386 + return -EINVAL; 387 + 388 + if (apll_rate % freq != 0) 389 + return -EINVAL; 390 + 391 + tdm_priv->mclk_rate = freq; 392 + tdm_priv->mclk_apll = apll; 393 + 394 + return 0; 395 + } 396 + 397 + static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream, 398 + struct snd_pcm_hw_params *params, 399 + struct snd_soc_dai *dai) 400 + { 401 + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 402 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 403 + int tdm_id = dai->id; 404 + struct mtk_afe_tdm_priv *tdm_priv; 405 + unsigned int rate = params_rate(params); 406 + unsigned int channels = params_channels(params); 407 + snd_pcm_format_t format = params_format(params); 408 + unsigned int tdm_con; 409 + 410 + if (tdm_id >= MT8189_DAI_NUM || tdm_id < 0) 411 + return -EINVAL; 412 + 413 + tdm_priv = afe_priv->dai_priv[tdm_id]; 414 + 415 + /* calculate mclk_rate, if not set explicitly */ 416 + if (!tdm_priv->mclk_rate) { 417 + tdm_priv->mclk_rate = rate * tdm_priv->mclk_multiple; 418 + mtk_dai_tdm_cal_mclk(afe, 419 + tdm_priv, 420 + tdm_priv->mclk_rate); 421 + } 422 + 423 + /* calculate bck */ 424 + tdm_priv->bck_rate = rate * 425 + channels * 426 + snd_pcm_format_physical_width(format); 427 + 428 + if (tdm_priv->bck_rate > tdm_priv->mclk_rate) 429 + return -EINVAL; 430 + 431 + if (tdm_priv->mclk_rate % tdm_priv->bck_rate != 0) 432 + return -EINVAL; 433 + 434 + dev_dbg(afe->dev, "id %d, rate %d, ch %d, fmt %d, mclk %d, bck %d\n", 435 + tdm_id, rate, channels, format, 436 + tdm_priv->mclk_rate, tdm_priv->bck_rate); 437 + 438 + /* set tdm */ 439 + tdm_con = 1 << LEFT_ALIGN_SFT; 440 + tdm_con |= get_tdm_wlen(format) << WLEN_SFT; 441 + tdm_con |= get_tdm_ch(channels) << CHANNEL_NUM_SFT; 442 + tdm_con |= get_tdm_channel_bck(format) << CHANNEL_BCK_CYCLES_SFT; 443 + tdm_con |= get_tdm_lrck_width(format) << LRCK_TDM_WIDTH_SFT; 444 + regmap_write(afe->regmap, AFE_TDM_CON1, tdm_con); 445 + 446 + /* set dptx */ 447 + if (tdm_id == MT8189_DAI_TDM_DPTX) { 448 + regmap_update_bits(afe->regmap, AFE_DPTX_CON, 449 + DPTX_CHANNEL_ENABLE_MASK_SFT, 450 + get_dptx_ch_enable_mask(channels) << 451 + DPTX_CHANNEL_ENABLE_SFT); 452 + regmap_update_bits(afe->regmap, AFE_DPTX_CON, 453 + DPTX_CHANNEL_NUMBER_MASK_SFT, 454 + get_dptx_ch(channels) << 455 + DPTX_CHANNEL_NUMBER_SFT); 456 + regmap_update_bits(afe->regmap, AFE_DPTX_CON, 457 + DPTX_16BIT_MASK_SFT, 458 + get_dptx_wlen(format) << DPTX_16BIT_SFT); 459 + } 460 + switch (channels) { 461 + case 1: 462 + case 2: 463 + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; 464 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT1_SFT; 465 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; 466 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; 467 + break; 468 + case 3: 469 + case 4: 470 + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; 471 + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; 472 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT2_SFT; 473 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; 474 + break; 475 + case 5: 476 + case 6: 477 + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; 478 + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; 479 + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; 480 + tdm_con |= TDM_CH_ZERO << ST_CH_PAIR_SOUT3_SFT; 481 + break; 482 + case 7: 483 + case 8: 484 + tdm_con = TDM_CH_START_O30_O31 << ST_CH_PAIR_SOUT0_SFT; 485 + tdm_con |= TDM_CH_START_O32_O33 << ST_CH_PAIR_SOUT1_SFT; 486 + tdm_con |= TDM_CH_START_O34_O35 << ST_CH_PAIR_SOUT2_SFT; 487 + tdm_con |= TDM_CH_START_O36_O37 << ST_CH_PAIR_SOUT3_SFT; 488 + break; 489 + default: 490 + tdm_con = 0; 491 + } 492 + regmap_write(afe->regmap, AFE_TDM_CON2, tdm_con); 493 + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 494 + HDMI_CH_NUM_MASK_SFT, 495 + channels << HDMI_CH_NUM_SFT); 496 + 497 + return 0; 498 + } 499 + 500 + static int mtk_dai_tdm_trigger(struct snd_pcm_substream *substream, 501 + int cmd, 502 + struct snd_soc_dai *dai) 503 + { 504 + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); 505 + int tdm_id = dai->id; 506 + 507 + dev_dbg(afe->dev, "%s(), cmd %d, tdm_id %d\n", __func__, cmd, tdm_id); 508 + 509 + switch (cmd) { 510 + case SNDRV_PCM_TRIGGER_START: 511 + case SNDRV_PCM_TRIGGER_RESUME: 512 + /* enable Out control */ 513 + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 514 + HDMI_OUT_ON_MASK_SFT, 515 + 0x1 << HDMI_OUT_ON_SFT); 516 + 517 + /* enable dptx */ 518 + if (tdm_id == MT8189_DAI_TDM_DPTX) { 519 + regmap_update_bits(afe->regmap, AFE_DPTX_CON, 520 + DPTX_ON_MASK_SFT, 0x1 << 521 + DPTX_ON_SFT); 522 + } 523 + 524 + /* enable tdm */ 525 + regmap_update_bits(afe->regmap, AFE_TDM_CON1, 526 + TDM_EN_MASK_SFT, 0x1 << TDM_EN_SFT); 527 + break; 528 + case SNDRV_PCM_TRIGGER_STOP: 529 + case SNDRV_PCM_TRIGGER_SUSPEND: 530 + /* disable tdm */ 531 + regmap_update_bits(afe->regmap, AFE_TDM_CON1, 532 + TDM_EN_MASK_SFT, 0); 533 + 534 + /* disable dptx */ 535 + if (tdm_id == MT8189_DAI_TDM_DPTX) { 536 + regmap_update_bits(afe->regmap, AFE_DPTX_CON, 537 + DPTX_ON_MASK_SFT, 0); 538 + } 539 + 540 + /* disable Out control */ 541 + regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 542 + HDMI_OUT_ON_MASK_SFT, 0); 543 + break; 544 + default: 545 + return -EINVAL; 546 + } 547 + 548 + return 0; 549 + } 550 + 551 + static int mtk_dai_tdm_set_sysclk(struct snd_soc_dai *dai, 552 + int clk_id, unsigned int freq, int dir) 553 + { 554 + struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); 555 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 556 + struct mtk_afe_tdm_priv *tdm_priv; 557 + 558 + if (dai->id >= MT8189_DAI_NUM || dai->id < 0) 559 + return -EINVAL; 560 + 561 + tdm_priv = afe_priv->dai_priv[dai->id]; 562 + 563 + if (!tdm_priv) 564 + return -EINVAL; 565 + 566 + if (dir != SND_SOC_CLOCK_OUT) 567 + return -EINVAL; 568 + 569 + dev_dbg(afe->dev, "%s(), freq %d\n", __func__, freq); 570 + 571 + return mtk_dai_tdm_cal_mclk(afe, tdm_priv, freq); 572 + } 573 + 574 + static const struct snd_soc_dai_ops mtk_dai_tdm_ops = { 575 + .hw_params = mtk_dai_tdm_hw_params, 576 + .trigger = mtk_dai_tdm_trigger, 577 + .set_sysclk = mtk_dai_tdm_set_sysclk, 578 + }; 579 + 580 + /* dai driver */ 581 + #define MTK_TDM_RATES (SNDRV_PCM_RATE_8000_48000 |\ 582 + SNDRV_PCM_RATE_88200 |\ 583 + SNDRV_PCM_RATE_96000 |\ 584 + SNDRV_PCM_RATE_176400 |\ 585 + SNDRV_PCM_RATE_192000) 586 + 587 + #define MTK_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ 588 + SNDRV_PCM_FMTBIT_S24_LE |\ 589 + SNDRV_PCM_FMTBIT_S32_LE) 590 + 591 + static struct snd_soc_dai_driver mtk_dai_tdm_driver[] = { 592 + { 593 + .name = "TDM", 594 + .id = MT8189_DAI_TDM, 595 + .playback = { 596 + .stream_name = "TDM", 597 + .channels_min = 2, 598 + .channels_max = 8, 599 + .rates = MTK_TDM_RATES, 600 + .formats = MTK_TDM_FORMATS, 601 + }, 602 + .ops = &mtk_dai_tdm_ops, 603 + }, 604 + { 605 + .name = "TDM_DPTX", 606 + .id = MT8189_DAI_TDM_DPTX, 607 + .playback = { 608 + .stream_name = "TDM_DPTX", 609 + .channels_min = 2, 610 + .channels_max = 8, 611 + .rates = MTK_TDM_RATES, 612 + .formats = MTK_TDM_FORMATS, 613 + }, 614 + .ops = &mtk_dai_tdm_ops, 615 + }, 616 + }; 617 + 618 + static struct mtk_afe_tdm_priv *init_tdm_priv_data(struct mtk_base_afe *afe, 619 + int id) 620 + { 621 + struct mtk_afe_tdm_priv *tdm_priv; 622 + 623 + tdm_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_afe_tdm_priv), 624 + GFP_KERNEL); 625 + if (!tdm_priv) 626 + return NULL; 627 + 628 + if (id == MT8189_DAI_TDM_DPTX) 629 + tdm_priv->mclk_multiple = 256; 630 + else 631 + tdm_priv->mclk_multiple = 128; 632 + 633 + tdm_priv->bck_id = MT8189_TDMOUT_BCK; 634 + tdm_priv->mclk_id = MT8189_TDMOUT_MCK; 635 + 636 + return tdm_priv; 637 + } 638 + 639 + int mt8189_dai_tdm_register(struct mtk_base_afe *afe) 640 + { 641 + struct mt8189_afe_private *afe_priv = afe->platform_priv; 642 + struct mtk_afe_tdm_priv *tdm_priv, *tdm_dptx_priv; 643 + struct mtk_base_afe_dai *dai; 644 + 645 + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); 646 + if (!dai) 647 + return -ENOMEM; 648 + 649 + dai->dai_drivers = mtk_dai_tdm_driver; 650 + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_tdm_driver); 651 + dai->controls = mtk_dai_tdm_controls; 652 + dai->num_controls = ARRAY_SIZE(mtk_dai_tdm_controls); 653 + dai->dapm_widgets = mtk_dai_tdm_widgets; 654 + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_tdm_widgets); 655 + dai->dapm_routes = mtk_dai_tdm_routes; 656 + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_tdm_routes); 657 + 658 + tdm_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM); 659 + if (!tdm_priv) 660 + return -ENOMEM; 661 + 662 + tdm_dptx_priv = init_tdm_priv_data(afe, MT8189_DAI_TDM_DPTX); 663 + if (!tdm_dptx_priv) 664 + return -ENOMEM; 665 + 666 + list_add(&dai->list, &afe->sub_dais); 667 + 668 + afe_priv->dai_priv[MT8189_DAI_TDM] = tdm_priv; 669 + afe_priv->dai_priv[MT8189_DAI_TDM_DPTX] = tdm_dptx_priv; 670 + 671 + return 0; 672 + }