[PATCH] CHROMIUM: ASoC: amd: acp: Add tdm support for codecs in machine driver

From: Venkata Prasad Potturu
Date: Fri Oct 28 2022 - 06:31:10 EST


From: Venkata Prasad Potturu <venkataprasad.potturu@xxxxxxx>

Add tdm support for rt5682, rt5682s, rt1019 and nau8825 codec in
machine driver.

Signed-off-by: Venkata Prasad Potturu <venkataprasad.potturu@xxxxxxx>
---
sound/soc/amd/acp/acp-mach-common.c | 255 ++++++++++++++++++++++++++--
1 file changed, 243 insertions(+), 12 deletions(-)

diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c
index a78cf29387a7..bce3d8ed48ec 100644
--- a/sound/soc/amd/acp/acp-mach-common.c
+++ b/sound/soc/amd/acp/acp-mach-common.c
@@ -27,6 +27,21 @@
#include "../../codecs/nau8825.h"
#include "acp-mach.h"

+static int tdm_mode = 0;
+module_param_named(tdm_mode, tdm_mode, int, 0444);
+MODULE_PARM_DESC(tdm_mode, "Set 1 for tdm mode, set 0 for i2s mode");
+
+#define TDM_CHANNELS 8
+#define BIT_WIDTH 16
+#define SLOT0 BIT(0)
+#define SLOT1 BIT(1)
+#define SLOT2 BIT(2)
+#define SLOT3 BIT(3)
+#define SLOT4 BIT(4)
+#define SLOT5 BIT(5)
+#define SLOT6 BIT(6)
+#define SLOT7 BIT(7)
+
#define PCO_PLAT_CLK 48000000
#define RT5682_PLL_FREQ (48000 * 512)
#define DUAL_CHANNEL 2
@@ -80,13 +95,19 @@ static int acp_card_rt5682_init(struct snd_soc_pcm_runtime *rtd)
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
struct snd_soc_component *component = codec_dai->component;
int ret;
+ unsigned int fmt;

dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name);

if (drvdata->hs_codec_id != RT5682)
return -EINVAL;

- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBP_CFP);
if (ret < 0) {
dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
@@ -151,10 +172,15 @@ static int acp_card_hs_startup(struct snd_pcm_substream *substream)
int ret;
unsigned int fmt;

+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;

ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
@@ -191,9 +217,65 @@ static void acp_card_shutdown(struct snd_pcm_substream *substream)
clk_disable_unprepare(drvdata->wclk);
}

+static int acp_card_rt5682x_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ int ret;
+ unsigned int fmt;
+
+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBP_CFP);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 0 and slot 1 for playback and capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, SLOT0 | SLOT1, SLOT0 | SLOT1,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBC_CFC);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 0 and slot 1 for playback and capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, SLOT0 | SLOT1, SLOT0 | SLOT1,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret < 0) {
+ dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static const struct snd_soc_ops acp_card_rt5682_ops = {
.startup = acp_card_hs_startup,
.shutdown = acp_card_shutdown,
+ .hw_params = acp_card_rt5682x_hw_params,
};

/* Define RT5682S CODEC component*/
@@ -220,10 +302,15 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != RT5682S)
return -EINVAL;

+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;

ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
@@ -283,6 +370,7 @@ static int acp_card_rt5682s_init(struct snd_soc_pcm_runtime *rtd)

static const struct snd_soc_ops acp_card_rt5682s_ops = {
.startup = acp_card_hs_startup,
+ .hw_params = acp_card_rt5682x_hw_params,
};

static const unsigned int dmic_channels[] = {
@@ -351,19 +439,48 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_card *card = rtd->card;
struct acp_card_drvdata *drvdata = card->drvdata;
struct snd_soc_dai *codec_dai;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int srate, i, ret = 0;
+ unsigned int fmt;

srate = params_rate(params);

if (drvdata->amp_codec_id != RT1019)
return -EINVAL;

+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBP_CFP);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 2 and slot 3 for playback.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, SLOT2 | SLOT3, 0, TDM_CHANNELS, BIT_WIDTH);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
for_each_rtd_codec_dais(rtd, i, codec_dai) {
if (strcmp(codec_dai->name, "rt1019-aif"))
continue;

- ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
- 64 * srate, 256 * srate);
+ if (tdm_mode)
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
+ 128 * srate, 256 * srate);
+ else
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT1019_PLL_S_BCLK,
+ 64 * srate, 256 * srate);
+
if (ret < 0)
return ret;

@@ -371,8 +488,36 @@ static int acp_card_rt1019_hw_params(struct snd_pcm_substream *substream,
256 * srate, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
- }

+ if (tdm_mode) {
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A
+ | SND_SOC_DAIFMT_NB_NF);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ /**
+ * As codec supports slot 2 for left channel playback.
+ */
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1019:00")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, SLOT2, SLOT2,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret < 0)
+ break;
+ }
+
+ /**
+ * As codec supports slot 3 for right channel playback.
+ */
+ if (!strcmp(codec_dai->component->name, "i2c-10EC1019:01")) {
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, SLOT3, SLOT3,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret < 0)
+ break;
+ }
+ }
+ }
return 0;
}

@@ -426,9 +571,43 @@ static int acp_card_maxim_init(struct snd_soc_pcm_runtime *rtd)
ARRAY_SIZE(max98360a_map));
}

+static int acp_card_maxim_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
+ unsigned int fmt;
+ int ret;
+
+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBP_CFP);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 2 and slot 3 for playback.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, SLOT2 | SLOT3, 0, TDM_CHANNELS, BIT_WIDTH);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
static const struct snd_soc_ops acp_card_maxim_ops = {
.startup = acp_card_amp_startup,
.shutdown = acp_card_shutdown,
+ .hw_params = acp_card_maxim_hw_params,
};

/* Declare nau8825 codec components */
@@ -454,10 +633,15 @@ static int acp_card_nau8825_init(struct snd_soc_pcm_runtime *rtd)
if (drvdata->hs_codec_id != NAU8825)
return -EINVAL;

+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
if (drvdata->soc_mclk)
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC;
else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;
+ fmt = fmt | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP;

ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0) {
@@ -493,8 +677,34 @@ static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
{
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
+ struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
int ret;
+ unsigned int fmt;

+ if (tdm_mode)
+ fmt = SND_SOC_DAIFMT_DSP_A;
+ else
+ fmt = SND_SOC_DAIFMT_I2S;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBP_CFP);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 4 and slot 5 for playback
+ * and slot 6 and slot 7 for capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, SLOT4 | SLOT5, SLOT6 | SLOT7,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret && ret != -ENOTSUPP) {
+ dev_err(rtd->dev, "set TDM slot err: %d\n", ret);
+ return ret;
+ }
+ }
ret = snd_soc_dai_set_sysclk(codec_dai, NAU8825_CLK_FLL_FS,
(48000 * 256), SND_SOC_CLOCK_IN);
if (ret < 0)
@@ -507,6 +717,25 @@ static int acp_nau8825_hw_params(struct snd_pcm_substream *substream,
return ret;
}

+ ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBC_CFC);
+ if (ret < 0) {
+ dev_err(rtd->card->dev, "Failed to set dai fmt: %d\n", ret);
+ return ret;
+ }
+
+ if (tdm_mode) {
+ /**
+ * As codec supports slot 4 and slot 5 for playback and slot 6 for capture.
+ */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, SLOT6, SLOT4 | SLOT5,
+ TDM_CHANNELS, BIT_WIDTH);
+ if (ret < 0) {
+ dev_warn(rtd->dev, "set TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
return ret;
}

@@ -567,6 +796,8 @@ SND_SOC_DAILINK_DEF(sof_sp,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
SND_SOC_DAILINK_DEF(sof_hs,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs")));
+SND_SOC_DAILINK_DEF(sof_hs_virtual,
+ DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-hs-virtual")));
SND_SOC_DAILINK_DEF(sof_dmic,
DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-dmic")));
SND_SOC_DAILINK_DEF(pdm_dmic,
@@ -733,8 +964,8 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)
if (drv_data->amp_cpu_id == I2S_HS) {
links[i].name = "acp-amp-codec";
links[i].id = AMP_BE_ID;
- links[i].cpus = sof_hs;
- links[i].num_cpus = ARRAY_SIZE(sof_hs);
+ links[i].cpus = sof_hs_virtual;
+ links[i].num_cpus = ARRAY_SIZE(sof_hs_virtual);
links[i].platforms = sof_component;
links[i].num_platforms = ARRAY_SIZE(sof_component);
links[i].dpcm_playback = 1;
--
2.25.1