From b369812a69e4518460f72ab82beb3fc3cdf933c6 Mon Sep 17 00:00:00 2001 From: Jianhua Lu Date: Mon, 11 Dec 2023 09:23:28 +0800 Subject: [PATCH] ASoC: qcom: sm8250: Add tdm support Signed-off-by: Jiali Chen --- sound/soc/qcom/sm8250.c | 93 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 05a8b04e5..e1d87a401 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -17,6 +17,9 @@ #include "sdw.h" #define MI2S_BCLK_RATE 1536000 +#define TDM_BCLK_RATE 12288000 + +static unsigned int tdm_slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28}; struct sm8250_snd_data { bool stream_prepared[AFE_PORT_MAX]; @@ -55,6 +58,57 @@ static void sm8250_snd_exit(struct snd_soc_pcm_runtime *rtd) } +static int sm8250_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + int ret = 0; + int channels, slots, slot_width; + + channels = params_channels(params); + slots = 8; + slot_width = 32; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, 0x03, + slots, slot_width); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL, + channels, tdm_slot_offset); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xf, 0, + slots, slot_width); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set tdm slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, channels, + tdm_slot_offset, 0, NULL); + if (ret < 0) { + dev_err(rtd->dev, "%s: failed to set channel map, err:%d\n", + __func__, ret); + goto end; + } + } + +end: + return ret; +} + static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { @@ -78,6 +132,7 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); + int ret,j; switch (cpu_dai->id) { case PRIMARY_MI2S_RX: @@ -104,6 +159,29 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) snd_soc_dai_set_fmt(cpu_dai, fmt); snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); break; + case TERTIARY_TDM_RX_0: + codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_DSP_A; + ret = snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT, + TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + if (ret < 0) { + dev_err(rtd->dev, "TDM cpu sysclk err:%d\n", ret); + return ret; + } + + for_each_rtd_codec_dais(rtd, j, codec_dai) { + ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt); + if (ret < 0) { + dev_err(rtd->dev, "TDM fmt err:%d\n", ret); + return ret; + } + ret = snd_soc_dai_set_sysclk(codec_dai, 0, TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + if (ret < 0) { + dev_err(rtd->dev, "TDM sysclk err:%d\n", ret); + return ret; + } + } + break; default: break; } @@ -111,6 +189,20 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) return qcom_snd_sdw_startup(substream); } +static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + + switch (cpu_dai->id) { + case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + return sm8250_tdm_snd_hw_params(substream, params); + } + + return 0; +} + static int sm8250_snd_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); @@ -132,6 +224,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) static const struct snd_soc_ops sm8250_be_ops = { .startup = sm8250_snd_startup, .shutdown = qcom_snd_sdw_shutdown, + .hw_params = sm8250_snd_hw_params, .hw_free = sm8250_snd_hw_free, .prepare = sm8250_snd_prepare, }; -- 2.53.0