From 6b111fa07962823058663efcedd51661bd60ca03 Mon Sep 17 00:00:00 2001
From: Jianhua Lu <lujianhua000@gmail.com>
Date: Mon, 11 Dec 2023 09:23:28 +0800
Subject: [PATCH 08/12] ASoC: qcom: sm8250: add tertiary tdm support

---
 sound/soc/qcom/sm8250.c | 85 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)

diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c
index f193d0ba63d0..e6e0b40e5600 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:
@@ -112,6 +167,21 @@ 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;
+		snd_soc_dai_set_sysclk(cpu_dai,
+			Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT,
+			TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+
+		for_each_rtd_codec_dais(rtd, j, codec_dai) {
+			ret = snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+			snd_soc_dai_set_sysclk(codec_dai, 0, TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+			if (ret < 0) {
+				dev_err(rtd->dev, "TDM fmt err:%d\n", ret);
+				return ret;
+			}
+		}
+		break;
 	default:
 		break;
 	}
@@ -119,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);
@@ -140,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.52.0

