ASoC: amd: acp: Add legacy audio driver support for Rembrandt platform
authorV sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Thu, 7 Jul 2022 16:11:42 +0000 (21:41 +0530)
committerMark Brown <broonie@kernel.org>
Fri, 8 Jul 2022 17:53:15 +0000 (18:53 +0100)
Add i2s and dmic support for Rembrandt platform,
Add machine support for nau8825, max98360 and rt5682s,rt1019 codec
in legacy driver for rembrandt platform.
Here codec is in a slave mode.

Signed-off-by: V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
Link: https://lore.kernel.org/r/20220707161142.491034-4-Vsujithkumar.Reddy@amd.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/amd/acp/Kconfig
sound/soc/amd/acp/Makefile
sound/soc/amd/acp/acp-i2s.c
sound/soc/amd/acp/acp-legacy-mach.c
sound/soc/amd/acp/acp-mach-common.c
sound/soc/amd/acp/acp-mach.h
sound/soc/amd/acp/acp-pci.c
sound/soc/amd/acp/acp-platform.c
sound/soc/amd/acp/acp-rembrandt.c [new file with mode: 0644]
sound/soc/amd/acp/amd.h
sound/soc/amd/acp/chip_offset_byte.h

index 7e56d26..ce00378 100644 (file)
@@ -40,6 +40,17 @@ config SND_AMD_ASOC_RENOIR
        help
          This option enables Renoir I2S support on AMD platform.
 
+config SND_AMD_ASOC_REMBRANDT
+       tristate "AMD ACP ASOC Rembrandt Support"
+       select SND_SOC_AMD_ACP_PCM
+       select SND_SOC_AMD_ACP_I2S
+       select SND_SOC_AMD_ACP_PDM
+       depends on X86 && PCI
+       help
+         This option enables Rembrandt I2S support on AMD platform.
+         Say Y if you want to enable AUDIO on Rembrandt
+         If unsure select "N".
+
 config SND_SOC_AMD_MACH_COMMON
        tristate
        depends on X86 && PCI && I2C
index 657ddfa..d9abb0e 100644 (file)
@@ -12,6 +12,7 @@ snd-acp-pci-objs     := acp-pci.o
 
 #platform specific driver
 snd-acp-renoir-objs     := acp-renoir.o
+snd-acp-rembrandt-objs  := acp-rembrandt.o
 
 #machine specific driver
 snd-acp-mach-objs     := acp-mach-common.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o
 obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o
 
 obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o
+obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o
 
 obj-$(CONFIG_SND_SOC_AMD_MACH_COMMON) += snd-acp-mach.o
 obj-$(CONFIG_SND_SOC_AMD_LEGACY_MACH) += snd-acp-legacy-mach.o
index a736c00..393f729 100644 (file)
@@ -30,11 +30,14 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
 {
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata;
+       struct acp_resource *rsrc;
        u32 val;
        u32 xfer_resolution;
        u32 reg_val;
+       u32 lrclk_div_val, bclk_div_val;
 
        adata = snd_soc_dai_get_drvdata(dai);
+       rsrc = adata->rsrc;
 
        /* These values are as per Hardware Spec */
        switch (params_format(params)) {
@@ -63,6 +66,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                case I2S_SP_INSTANCE:
                        reg_val = ACP_I2STDM_ITER;
                        break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_ITER;
+                       break;
                default:
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
@@ -75,6 +81,9 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
                case I2S_SP_INSTANCE:
                        reg_val = ACP_I2STDM_IRER;
                        break;
+               case I2S_HS_INSTANCE:
+                       reg_val = ACP_HSTDM_IRER;
+                       break;
                default:
                        dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                        return -EINVAL;
@@ -86,6 +95,74 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_
        val = val | (xfer_resolution  << 3);
        writel(val, adata->acp_base + reg_val);
 
+       if (rsrc->soc_mclk) {
+               switch (params_format(params)) {
+               case SNDRV_PCM_FORMAT_S16_LE:
+                       switch (params_rate(params)) {
+                       case 8000:
+                               bclk_div_val = 768;
+                               break;
+                       case 16000:
+                               bclk_div_val = 384;
+                               break;
+                       case 24000:
+                               bclk_div_val = 256;
+                               break;
+                       case 32000:
+                               bclk_div_val = 192;
+                               break;
+                       case 44100:
+                       case 48000:
+                               bclk_div_val = 128;
+                               break;
+                       case 88200:
+                       case 96000:
+                               bclk_div_val = 64;
+                               break;
+                       case 192000:
+                               bclk_div_val = 32;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       lrclk_div_val = 32;
+                       break;
+               case SNDRV_PCM_FORMAT_S32_LE:
+                       switch (params_rate(params)) {
+                       case 8000:
+                               bclk_div_val = 384;
+                               break;
+                       case 16000:
+                               bclk_div_val = 192;
+                               break;
+                       case 24000:
+                               bclk_div_val = 128;
+                               break;
+                       case 32000:
+                               bclk_div_val = 96;
+                               break;
+                       case 44100:
+                       case 48000:
+                               bclk_div_val = 64;
+                               break;
+                       case 88200:
+                       case 96000:
+                               bclk_div_val = 32;
+                               break;
+                       case 192000:
+                               bclk_div_val = 16;
+                               break;
+                       default:
+                               return -EINVAL;
+                       }
+                       lrclk_div_val = 64;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               adata->lrclk_div = lrclk_div_val;
+               adata->bclk_div = bclk_div_val;
+       }
        return 0;
 }
 
@@ -94,6 +171,7 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
        struct acp_stream *stream = substream->runtime->private_data;
        struct device *dev = dai->component->dev;
        struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_resource *rsrc = adata->rsrc;
        u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg;
 
        period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size);
@@ -118,6 +196,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                                ier_val = ACP_I2STDM_IER;
                                buf_reg = ACP_I2S_TX_RINGBUFSIZE;
                                break;
+                       case I2S_HS_INSTANCE:
+                               water_val = ACP_HS_TX_INTR_WATERMARK_SIZE;
+                               reg_val = ACP_HSTDM_ITER;
+                               ier_val = ACP_HSTDM_IER;
+                               buf_reg = ACP_HS_TX_RINGBUFSIZE;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -136,6 +220,12 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                                ier_val = ACP_I2STDM_IER;
                                buf_reg = ACP_I2S_RX_RINGBUFSIZE;
                                break;
+                       case I2S_HS_INSTANCE:
+                               water_val = ACP_HS_RX_INTR_WATERMARK_SIZE;
+                               reg_val = ACP_HSTDM_IRER;
+                               ier_val = ACP_HSTDM_IER;
+                               buf_reg = ACP_HS_RX_RINGBUFSIZE;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -147,6 +237,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                val = val | BIT(0);
                writel(val, adata->acp_base + reg_val);
                writel(1, adata->acp_base + ier_val);
+               if (rsrc->soc_mclk)
+                       acp_set_i2s_clk(adata, dai->driver->id);
                return 0;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
@@ -159,6 +251,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                        case I2S_SP_INSTANCE:
                                reg_val = ACP_I2STDM_ITER;
                                break;
+                       case I2S_HS_INSTANCE:
+                               reg_val = ACP_HSTDM_ITER;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -172,6 +267,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                        case I2S_SP_INSTANCE:
                                reg_val = ACP_I2STDM_IRER;
                                break;
+                       case I2S_HS_INSTANCE:
+                               reg_val = ACP_HSTDM_IRER;
+                               break;
                        default:
                                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                                return -EINVAL;
@@ -187,6 +285,9 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct
                if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) &&
                    !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0)))
                        writel(0, adata->acp_base + ACP_I2STDM_IER);
+               if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) &&
+                   !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0)))
+                       writel(0, adata->acp_base + ACP_HSTDM_IER);
                return 0;
        default:
                return -EINVAL;
@@ -247,6 +348,27 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
                        writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR);
                }
                break;
+       case I2S_HS_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       reg_dma_size = ACP_HS_TX_DMA_SIZE;
+                       acp_fifo_addr = rsrc->sram_pte_offset +
+                               HS_PB_FIFO_ADDR_OFFSET;
+                       reg_fifo_addr = ACP_HS_TX_FIFOADDR;
+                       reg_fifo_size = ACP_HS_TX_FIFOSIZE;
+
+                       phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR);
+               } else {
+                       reg_dma_size = ACP_HS_RX_DMA_SIZE;
+                       acp_fifo_addr = rsrc->sram_pte_offset +
+                                       HS_CAPT_FIFO_ADDR_OFFSET;
+                       reg_fifo_addr = ACP_HS_RX_FIFOADDR;
+                       reg_fifo_size = ACP_HS_RX_FIFOSIZE;
+
+                       phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset;
+                       writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR);
+               }
+               break;
        default:
                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                return -EINVAL;
@@ -260,7 +382,9 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d
        ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) |
                        BIT(BT_RX_THRESHOLD(rsrc->offset)) |
                        BIT(I2S_TX_THRESHOLD(rsrc->offset)) |
-                       BIT(BT_TX_THRESHOLD(rsrc->offset));
+                       BIT(BT_TX_THRESHOLD(rsrc->offset)) |
+                       BIT(HS_RX_THRESHOLD(rsrc->offset)) |
+                       BIT(HS_TX_THRESHOLD(rsrc->offset));
 
        writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
 
@@ -299,6 +423,17 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
                        stream->fifo_offset = BT_CAPT_FIFO_ADDR_OFFSET;
                }
                break;
+       case I2S_HS_INSTANCE:
+               if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+                       irq_bit = BIT(HS_TX_THRESHOLD(rsrc->offset));
+                       stream->pte_offset = ACP_SRAM_HS_PB_PTE_OFFSET;
+                       stream->fifo_offset = HS_PB_FIFO_ADDR_OFFSET;
+               } else {
+                       irq_bit = BIT(HS_RX_THRESHOLD(rsrc->offset));
+                       stream->pte_offset = ACP_SRAM_HS_CP_PTE_OFFSET;
+                       stream->fifo_offset = HS_CAPT_FIFO_ADDR_OFFSET;
+               }
+               break;
        default:
                dev_err(dev, "Invalid dai id %x\n", dai->driver->id);
                return -EINVAL;
index 7f04a04..1f4878f 100644 (file)
@@ -47,6 +47,28 @@ static struct acp_card_drvdata rt5682s_rt1019_data = {
        .dmic_codec_id = DMIC,
 };
 
+static struct acp_card_drvdata max_nau8825_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = NAU8825,
+       .amp_codec_id = MAX98360A,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+       .platform = REMBRANDT,
+};
+
+static struct acp_card_drvdata rt5682s_rt1019_rmb_data = {
+       .hs_cpu_id = I2S_HS,
+       .amp_cpu_id = I2S_HS,
+       .dmic_cpu_id = DMIC,
+       .hs_codec_id = RT5682S,
+       .amp_codec_id = RT1019,
+       .dmic_codec_id = DMIC,
+       .soc_mclk = true,
+       .platform = REMBRANDT,
+};
+
 static const struct snd_kcontrol_new acp_controls[] = {
        SOC_DAPM_PIN_SWITCH("Headphone Jack"),
        SOC_DAPM_PIN_SWITCH("Headset Mic"),
@@ -112,6 +134,14 @@ static const struct platform_device_id board_ids[] = {
                .name = "acp3xalc5682s1019",
                .driver_data = (kernel_ulong_t)&rt5682s_rt1019_data,
        },
+       {
+               .name = "rmb-nau8825-max",
+               .driver_data = (kernel_ulong_t)&max_nau8825_data,
+       },
+       {
+               .name = "rmb-rt5682s-rt1019",
+               .driver_data = (kernel_ulong_t)&rt5682s_rt1019_rmb_data,
+       },
        { }
 };
 static struct platform_driver acp_asoc_audio = {
@@ -130,4 +160,6 @@ MODULE_DESCRIPTION("ACP chrome audio support");
 MODULE_ALIAS("platform:acp3xalc56821019");
 MODULE_ALIAS("platform:acp3xalc5682sm98360");
 MODULE_ALIAS("platform:acp3xalc5682s1019");
+MODULE_ALIAS("platform:rmb-nau8825-max");
+MODULE_ALIAS("platform:rmb-rt5682s-rt1019");
 MODULE_LICENSE("GPL v2");
index 8614539..f0c4912 100644 (file)
@@ -545,6 +545,12 @@ static struct snd_soc_dai_link_component platform_component[] = {
        }
 };
 
+static struct snd_soc_dai_link_component platform_rmb_component[] = {
+       {
+               .name = "acp_asoc_rembrandt.0",
+       }
+};
+
 static struct snd_soc_dai_link_component sof_component[] = {
        {
                 .name = "0000:04:00.5",
@@ -553,6 +559,8 @@ static struct snd_soc_dai_link_component sof_component[] = {
 
 SND_SOC_DAILINK_DEF(i2s_sp,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-sp")));
+SND_SOC_DAILINK_DEF(i2s_hs,
+                   DAILINK_COMP_ARRAY(COMP_CPU("acp-i2s-hs")));
 SND_SOC_DAILINK_DEF(sof_sp,
        DAILINK_COMP_ARRAY(COMP_CPU("acp-sof-sp")));
 SND_SOC_DAILINK_DEF(sof_hs,
@@ -774,6 +782,40 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->hs_cpu_id == I2S_HS) {
+               links[i].name = "acp-headset-codec";
+               links[i].id = HEADSET_BE_ID;
+               links[i].cpus = i2s_hs;
+               links[i].num_cpus = ARRAY_SIZE(i2s_hs);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
+               links[i].dpcm_playback = 1;
+               links[i].dpcm_capture = 1;
+               if (!drv_data->hs_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->hs_codec_id == NAU8825) {
+                       links[i].codecs = nau8825;
+                       links[i].num_codecs = ARRAY_SIZE(nau8825);
+                       links[i].init = acp_card_nau8825_init;
+                       links[i].ops = &acp_card_nau8825_ops;
+               }
+               if (drv_data->hs_codec_id == RT5682S) {
+                       links[i].codecs = rt5682s;
+                       links[i].num_codecs = ARRAY_SIZE(rt5682s);
+                       links[i].init = acp_card_rt5682s_init;
+                       links[i].ops = &acp_card_rt5682s_ops;
+               }
+               i++;
+       }
+
        if (drv_data->amp_cpu_id == I2S_SP) {
                links[i].name = "acp-amp-codec";
                links[i].id = AMP_BE_ID;
@@ -804,6 +846,41 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                i++;
        }
 
+       if (drv_data->amp_cpu_id == I2S_HS) {
+               links[i].name = "acp-amp-codec";
+               links[i].id = AMP_BE_ID;
+               links[i].cpus = i2s_hs;
+               links[i].num_cpus = ARRAY_SIZE(i2s_hs);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
+               links[i].dpcm_playback = 1;
+               if (!drv_data->amp_codec_id) {
+                       /* Use dummy codec if codec id not specified */
+                       links[i].codecs = dummy_codec;
+                       links[i].num_codecs = ARRAY_SIZE(dummy_codec);
+               }
+               if (drv_data->amp_codec_id == MAX98360A) {
+                       links[i].codecs = max98360a;
+                       links[i].num_codecs = ARRAY_SIZE(max98360a);
+                       links[i].ops = &acp_card_maxim_ops;
+                       links[i].init = acp_card_maxim_init;
+               }
+               if (drv_data->amp_codec_id == RT1019) {
+                       links[i].codecs = rt1019;
+                       links[i].num_codecs = ARRAY_SIZE(rt1019);
+                       links[i].ops = &acp_card_rt1019_ops;
+                       links[i].init = acp_card_rt1019_init;
+                       card->codec_conf = rt1019_conf;
+                       card->num_configs = ARRAY_SIZE(rt1019_conf);
+               }
+               i++;
+       }
+
        if (drv_data->dmic_cpu_id == DMIC) {
                links[i].name = "acp-dmic-codec";
                links[i].id = DMIC_BE_ID;
@@ -817,8 +894,13 @@ int acp_legacy_dai_links_create(struct snd_soc_card *card)
                }
                links[i].cpus = pdm_dmic;
                links[i].num_cpus = ARRAY_SIZE(pdm_dmic);
-               links[i].platforms = platform_component;
-               links[i].num_platforms = ARRAY_SIZE(platform_component);
+               if (drv_data->platform == REMBRANDT) {
+                       links[i].platforms = platform_rmb_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_rmb_component);
+               } else {
+                       links[i].platforms = platform_component;
+                       links[i].num_platforms = ARRAY_SIZE(platform_component);
+               }
                links[i].ops = &acp_card_dmic_ops;
                links[i].dpcm_capture = 1;
        }
index c95ee1c..20583ef 100644 (file)
@@ -41,6 +41,11 @@ enum codec_endpoints {
        NAU8825,
 };
 
+enum platform_end_point {
+       RENOIR = 0,
+       REMBRANDT,
+};
+
 struct acp_card_drvdata {
        unsigned int hs_cpu_id;
        unsigned int amp_cpu_id;
@@ -49,6 +54,7 @@ struct acp_card_drvdata {
        unsigned int amp_codec_id;
        unsigned int dmic_codec_id;
        unsigned int dai_fmt;
+       unsigned int platform;
        struct clk *wclk;
        struct clk *bclk;
        bool soc_mclk;
index c893963..c03bcd3 100644 (file)
@@ -82,6 +82,12 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id
                chip->name = "acp_asoc_renoir";
                chip->acp_rev = ACP3X_DEV;
                break;
+       case 0x6f:
+               res_acp = acp3x_res;
+               num_res = ARRAY_SIZE(acp3x_res);
+               chip->name = "acp_asoc_rembrandt";
+               chip->acp_rev = ACP6X_DEV;
+               break;
        default:
                dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision);
                return -EINVAL;
index e93c9e4..327e177 100644 (file)
@@ -94,11 +94,14 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
        struct acp_resource *rsrc = adata->rsrc;
        struct acp_stream *stream;
        u16 i2s_flag = 0;
-       u32 val, i;
+       u32 val, val1, i;
 
        if (!adata)
                return IRQ_NONE;
 
+       if (adata->rsrc->no_of_ctrls == 2)
+               val1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1)));
+
        val = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
 
        for (i = 0; i < ACP_MAX_STREAM; i++) {
@@ -110,8 +113,16 @@ static irqreturn_t i2s_irq_handler(int irq, void *data)
                        i2s_flag = 1;
                        break;
                }
+               if (adata->rsrc->no_of_ctrls == 2) {
+                       if (stream && (val1 & stream->irq_bit)) {
+                               writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata,
+                                      (rsrc->irqp_used - 1)));
+                               snd_pcm_period_elapsed(stream->substream);
+                               i2s_flag = 1;
+                               break;
+                       }
+               }
        }
-
        if (i2s_flag)
                return IRQ_HANDLED;
 
@@ -132,6 +143,7 @@ static void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream
        reg_val = rsrc->sram_pte_offset;
        writel(reg_val | BIT(31), adata->acp_base + pte_reg);
        writel(PAGE_SIZE_4K_ENABLE,  adata->acp_base + pte_size);
+       writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL);
 }
 
 static void config_acp_dma(struct acp_dev_data *adata, int cpu_id, int size)
diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c
new file mode 100644 (file)
index 0000000..2b57c0c
--- /dev/null
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license. When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2022 Advanced Micro Devices, Inc.
+//
+// Authors: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
+//          V sujith kumar Reddy <Vsujithkumar.Reddy@amd.com>
+/*
+ * Hardware interface for Renoir ACP block
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <linux/dma-mapping.h>
+
+#include "amd.h"
+
+#define DRV_NAME "acp_asoc_rembrandt"
+
+#define ACP6X_PGFSM_CONTROL                    0x1024
+#define ACP6X_PGFSM_STATUS                     0x1028
+
+#define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK  0x00010001
+
+#define ACP_PGFSM_CNTL_POWER_ON_MASK           0x01
+#define ACP_PGFSM_CNTL_POWER_OFF_MASK          0x00
+#define ACP_PGFSM_STATUS_MASK                  0x03
+#define ACP_POWERED_ON                         0x00
+#define ACP_POWER_ON_IN_PROGRESS               0x01
+#define ACP_POWERED_OFF                                0x02
+#define ACP_POWER_OFF_IN_PROGRESS              0x03
+
+#define ACP_ERROR_MASK                         0x20000000
+#define ACP_EXT_INTR_STAT_CLEAR_MASK           0xFFFFFFFF
+
+
+static int rmb_acp_init(void __iomem *base);
+static int rmb_acp_deinit(void __iomem *base);
+
+static struct acp_resource rsrc = {
+       .offset = 0,
+       .no_of_ctrls = 2,
+       .irqp_used = 1,
+       .soc_mclk = true,
+       .irq_reg_offset = 0x1a00,
+       .i2s_pin_cfg_offset = 0x1440,
+       .i2s_mode = 0x0a,
+       .scratch_reg_offset = 0x12800,
+       .sram_pte_offset = 0x03802800,
+};
+
+static struct snd_soc_acpi_codecs amp_rt1019 = {
+       .num_codecs = 1,
+       .codecs = {"10EC1019"}
+};
+
+static struct snd_soc_acpi_codecs amp_max = {
+       .num_codecs = 1,
+       .codecs = {"MX98360A"}
+};
+
+static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = {
+       {
+               .id = "10508825",
+               .drv_name = "rmb-nau8825-max",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_max,
+       },
+       {
+               .id = "AMDI0007",
+               .drv_name = "rembrandt-acp",
+       },
+       {
+               .id = "RTL5682",
+               .drv_name = "rmb-rt5682s-rt1019",
+               .machine_quirk = snd_soc_acpi_codec_list,
+               .quirk_data = &amp_rt1019,
+       },
+       {},
+};
+
+static struct snd_soc_dai_driver acp_rmb_dai[] = {
+{
+       .name = "acp-i2s-sp",
+       .id = I2S_SP_INSTANCE,
+       .playback = {
+               .stream_name = "I2S SP Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S SP Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-i2s-bt",
+       .id = I2S_BT_INSTANCE,
+       .playback = {
+               .stream_name = "I2S BT Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S BT Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-i2s-hs",
+       .id = I2S_HS_INSTANCE,
+       .playback = {
+               .stream_name = "I2S HS Playback",
+               .rates = SNDRV_PCM_RATE_8000_96000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 96000,
+       },
+       .capture = {
+               .stream_name = "I2S HS Capture",
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8 |
+                          SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 8,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &asoc_acp_cpu_dai_ops,
+       .probe = &asoc_acp_i2s_probe,
+},
+{
+       .name = "acp-pdm-dmic",
+       .id = DMIC_INSTANCE,
+       .capture = {
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S32_LE,
+               .channels_min = 2,
+               .channels_max = 2,
+               .rate_min = 8000,
+               .rate_max = 48000,
+       },
+       .ops = &acp_dmic_dai_ops,
+},
+};
+
+static int acp6x_power_on(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       val = readl(base + ACP6X_PGFSM_STATUS);
+
+       if (val == ACP_POWERED_ON)
+               return 0;
+
+       if ((val & ACP_PGFSM_STATUS_MASK) !=
+                               ACP_POWER_ON_IN_PROGRESS)
+               writel(ACP_PGFSM_CNTL_POWER_ON_MASK,
+                      base + ACP6X_PGFSM_CONTROL);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP6X_PGFSM_STATUS);
+               if (!val)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int acp6x_power_off(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       writel(ACP_PGFSM_CNTL_POWER_OFF_MASK,
+              base + ACP6X_PGFSM_CONTROL);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP6X_PGFSM_STATUS);
+               if ((val & ACP_PGFSM_STATUS_MASK) == ACP_POWERED_OFF)
+                       return 0;
+               udelay(1);
+       }
+       return -ETIMEDOUT;
+}
+
+static int acp6x_reset(void __iomem *base)
+{
+       u32 val;
+       int timeout;
+
+       writel(1, base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP_SOFT_RESET);
+               if (val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK)
+                       break;
+               cpu_relax();
+       }
+       writel(0, base + ACP_SOFT_RESET);
+       timeout = 0;
+       while (++timeout < 500) {
+               val = readl(base + ACP_SOFT_RESET);
+               if (!val)
+                       return 0;
+               cpu_relax();
+       }
+       return -ETIMEDOUT;
+}
+
+static void acp6x_enable_interrupts(struct acp_dev_data *adata)
+{
+       struct acp_resource *rsrc = adata->rsrc;
+       u32 ext_intr_ctrl;
+
+       writel(0x01, ACP_EXTERNAL_INTR_ENB(adata));
+       ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+       ext_intr_ctrl |= ACP_ERROR_MASK;
+       writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used));
+}
+
+static void acp6x_disable_interrupts(struct acp_dev_data *adata)
+{
+       struct acp_resource *rsrc = adata->rsrc;
+
+       writel(ACP_EXT_INTR_STAT_CLEAR_MASK,
+              ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used));
+       writel(0x00, ACP_EXTERNAL_INTR_ENB(adata));
+}
+
+static int rmb_acp_init(void __iomem *base)
+{
+       int ret;
+
+       /* power on */
+       ret = acp6x_power_on(base);
+       if (ret) {
+               pr_err("ACP power on failed\n");
+               return ret;
+       }
+       writel(0x01, base + ACP_CONTROL);
+
+       /* Reset */
+       ret = acp6x_reset(base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rmb_acp_deinit(void __iomem *base)
+{
+       int ret = 0;
+
+       /* Reset */
+       ret = acp6x_reset(base);
+       if (ret) {
+               pr_err("ACP reset failed\n");
+               return ret;
+       }
+
+       writel(0x00, base + ACP_CONTROL);
+
+       /* power off */
+       ret = acp6x_power_off(base);
+       if (ret) {
+               pr_err("ACP power off failed\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int rembrandt_audio_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acp_chip_info *chip;
+       struct acp_dev_data *adata;
+       struct resource *res;
+
+       chip = dev_get_platdata(&pdev->dev);
+       if (!chip || !chip->base) {
+               dev_err(&pdev->dev, "ACP chip data is NULL\n");
+               return -ENODEV;
+       }
+
+       if (chip->acp_rev != ACP6X_DEV) {
+               dev_err(&pdev->dev, "Un-supported ACP Revision %d\n", chip->acp_rev);
+               return -ENODEV;
+       }
+
+       rmb_acp_init(chip->base);
+
+       adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL);
+       if (!adata)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem");
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
+               return -ENODEV;
+       }
+
+       adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!adata->acp_base)
+               return -ENOMEM;
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq");
+       if (!res) {
+               dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n");
+               return -ENODEV;
+       }
+
+       adata->i2s_irq = res->start;
+       adata->dev = dev;
+       adata->dai_driver = acp_rmb_dai;
+       adata->num_dai = ARRAY_SIZE(acp_rmb_dai);
+       adata->rsrc = &rsrc;
+
+       adata->machines = snd_soc_acpi_amd_rmb_acp_machines;
+       acp_machine_select(adata);
+
+       dev_set_drvdata(dev, adata);
+       acp6x_enable_interrupts(adata);
+       acp_platform_register(dev);
+
+       return 0;
+}
+
+static int rembrandt_audio_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct acp_dev_data *adata = dev_get_drvdata(dev);
+       struct acp_chip_info *chip;
+
+       chip = dev_get_platdata(&pdev->dev);
+       if (!chip || !chip->base) {
+               dev_err(&pdev->dev, "ACP chip data is NULL\n");
+               return -ENODEV;
+       }
+
+       rmb_acp_deinit(chip->base);
+
+       acp6x_disable_interrupts(adata);
+       acp_platform_unregister(dev);
+       return 0;
+}
+
+static struct platform_driver rembrandt_driver = {
+       .probe = rembrandt_audio_probe,
+       .remove = rembrandt_audio_remove,
+       .driver = {
+               .name = "acp_asoc_rembrandt",
+       },
+};
+
+module_platform_driver(rembrandt_driver);
+
+MODULE_DESCRIPTION("AMD ACP Rembrandt Driver");
+MODULE_IMPORT_NS(SND_SOC_ACP_COMMON);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index 186cb8b..af96037 100644 (file)
 #include "chip_offset_byte.h"
 
 #define ACP3X_DEV                      3
+#define ACP6X_DEV                      6
 
 #define I2S_SP_INSTANCE                        0x00
 #define I2S_BT_INSTANCE                        0x01
 #define DMIC_INSTANCE                  0x02
+#define I2S_HS_INSTANCE                        0x03
 
 #define MEM_WINDOW_START               0x4080000
 
 #define I2S_TX_THRESHOLD(base) THRESHOLD(8, base)
 #define BT_TX_THRESHOLD(base)  THRESHOLD(6, base)
 #define BT_RX_THRESHOLD(base)  THRESHOLD(5, base)
+#define HS_TX_THRESHOLD(base)  THRESHOLD(4, base)
+#define HS_RX_THRESHOLD(base)  THRESHOLD(3, base)
 
 #define ACP_SRAM_SP_PB_PTE_OFFSET      0x0
 #define ACP_SRAM_SP_CP_PTE_OFFSET      0x100
 #define ACP_SRAM_BT_PB_PTE_OFFSET      0x200
 #define ACP_SRAM_BT_CP_PTE_OFFSET      0x300
 #define ACP_SRAM_PDM_PTE_OFFSET                0x400
+#define ACP_SRAM_HS_PB_PTE_OFFSET       0x500
+#define ACP_SRAM_HS_CP_PTE_OFFSET       0x600
 #define PAGE_SIZE_4K_ENABLE            0x2
 
 #define I2S_SP_TX_MEM_WINDOW_START     0x4000000
 #define I2S_SP_RX_MEM_WINDOW_START     0x4020000
 #define I2S_BT_TX_MEM_WINDOW_START     0x4040000
 #define I2S_BT_RX_MEM_WINDOW_START     0x4060000
+#define I2S_HS_TX_MEM_WINDOW_START      0x40A0000
+#define I2S_HS_RX_MEM_WINDOW_START      0x40C0000
 
 #define SP_PB_FIFO_ADDR_OFFSET         0x500
 #define SP_CAPT_FIFO_ADDR_OFFSET       0x700
 #define BT_PB_FIFO_ADDR_OFFSET         0x900
 #define BT_CAPT_FIFO_ADDR_OFFSET       0xB00
+#define HS_PB_FIFO_ADDR_OFFSET         0xD00
+#define HS_CAPT_FIFO_ADDR_OFFSET       0xF00
 #define PLAYBACK_MIN_NUM_PERIODS       2
 #define PLAYBACK_MAX_NUM_PERIODS       8
 #define PLAYBACK_MAX_PERIOD_SIZE       8192
@@ -72,7 +82,7 @@
 
 #define ACP3x_ITER_IRER_SAMP_LEN_MASK  0x38
 
-#define ACP_MAX_STREAM                 6
+#define ACP_MAX_STREAM                 8
 
 struct acp_chip_info {
        char *name;             /* Platform name */
@@ -95,6 +105,7 @@ struct acp_resource {
        int offset;
        int no_of_ctrls;
        int irqp_used;
+       bool soc_mclk;
        u32 irq_reg_offset;
        u32 i2s_pin_cfg_offset;
        int i2s_mode;
@@ -117,9 +128,23 @@ struct acp_dev_data {
        struct snd_soc_acpi_mach *machines;
        struct platform_device *mach_dev;
 
+       u32 bclk_div;
+       u32 lrclk_div;
+
        struct acp_resource *rsrc;
 };
 
+union acp_i2stdm_mstrclkgen {
+       struct {
+               u32 i2stdm_master_mode : 1;
+               u32 i2stdm_format_mode : 1;
+               u32 i2stdm_lrclk_div_val : 9;
+               u32 i2stdm_bclk_div_val : 11;
+               u32:10;
+       } bitfields, bits;
+       u32  u32_all;
+};
+
 extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops;
 extern const struct snd_soc_dai_ops acp_dmic_dai_ops;
 
@@ -146,6 +171,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
                        high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW);
                        break;
+               case I2S_HS_INSTANCE:
+                       high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH);
+                       low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW);
+                       break;
                default:
                        dev_err(adata->dev, "Invalid dai id %x\n", dai_id);
                        return -EINVAL;
@@ -160,6 +189,10 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
                        high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW);
                        break;
+               case I2S_HS_INSTANCE:
+                       high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH);
+                       low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW);
+                       break;
                case DMIC_INSTANCE:
                        high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH);
                        low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW);
@@ -175,4 +208,31 @@ static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int
        return byte_count;
 }
 
+static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id)
+{
+       union acp_i2stdm_mstrclkgen mclkgen;
+       u32 master_reg;
+
+       switch (dai_id) {
+       case I2S_SP_INSTANCE:
+               master_reg = ACP_I2STDM0_MSTRCLKGEN;
+               break;
+       case I2S_BT_INSTANCE:
+               master_reg = ACP_I2STDM1_MSTRCLKGEN;
+               break;
+       case I2S_HS_INSTANCE:
+               master_reg = ACP_I2STDM2_MSTRCLKGEN;
+               break;
+       default:
+               master_reg = ACP_I2STDM0_MSTRCLKGEN;
+               break;
+       }
+
+       mclkgen.bits.i2stdm_master_mode = 0x1;
+       mclkgen.bits.i2stdm_format_mode = 0x00;
+
+       mclkgen.bits.i2stdm_bclk_div_val = adata->bclk_div;
+       mclkgen.bits.i2stdm_lrclk_div_val = adata->lrclk_div;
+       writel(mclkgen.u32_all, adata->acp_base + master_reg);
+}
 #endif
index fff7e80..ce3948e 100644 (file)
 #define ACP_BT_TX_LINEARPOSITIONCNTR_HIGH             0x2084
 #define ACP_BT_TX_LINEARPOSITIONCNTR_LOW              0x2088
 #define ACP_BT_TX_INTR_WATERMARK_SIZE                 0x208C
+#define ACP_HS_RX_RINGBUFADDR                        0x3A90
+#define ACP_HS_RX_RINGBUFSIZE                        0x3A94
+#define ACP_HS_RX_LINKPOSITIONCNTR                   0x3A98
+#define ACP_HS_RX_FIFOADDR                           0x3A9C
+#define ACP_HS_RX_FIFOSIZE                           0x3AA0
+#define ACP_HS_RX_DMA_SIZE                           0x3AA4
+#define ACP_HS_RX_LINEARPOSITIONCNTR_HIGH            0x3AA8
+#define ACP_HS_RX_LINEARPOSITIONCNTR_LOW             0x3AAC
+#define ACP_HS_RX_INTR_WATERMARK_SIZE                0x3AB0
+#define ACP_HS_TX_RINGBUFADDR                        0x3AB4
+#define ACP_HS_TX_RINGBUFSIZE                        0x3AB8
+#define ACP_HS_TX_LINKPOSITIONCNTR                   0x3ABC
+#define ACP_HS_TX_FIFOADDR                           0x3AC0
+#define ACP_HS_TX_FIFOSIZE                           0x3AC4
+#define ACP_HS_TX_DMA_SIZE                           0x3AC8
+#define ACP_HS_TX_LINEARPOSITIONCNTR_HIGH            0x3ACC
+#define ACP_HS_TX_LINEARPOSITIONCNTR_LOW             0x3AD0
+#define ACP_HS_TX_INTR_WATERMARK_SIZE                0x3AD4
 
 #define ACP_I2STDM_IER                                0x2400
 #define ACP_I2STDM_IRER                               0x2404
 #define ACP_BTTDM_ITER                                0x280C
 #define ACP_BTTDM_TXFRMT                              0x2810
 
+/* Registers from ACP_HS_TDM block */
+#define ACP_HSTDM_IER                                 0x2814
+#define ACP_HSTDM_IRER                                0x2818
+#define ACP_HSTDM_RXFRMT                              0x281C
+#define ACP_HSTDM_ITER                                0x2820
+#define ACP_HSTDM_TXFRMT                              0x2824
+
 /* Registers from ACP_WOV_PDM block */
 
 #define ACP_WOV_PDM_ENABLE                            0x2C04
 #define ACP_PDM_VAD_DYNAMIC_CLK_GATING_EN             0x2C64
 #define ACP_WOV_ERROR_STATUS_REGISTER                 0x2C68
 
+#define ACP_I2STDM0_MSTRCLKGEN                       0x2414
+#define ACP_I2STDM1_MSTRCLKGEN                       0x2418
+#define ACP_I2STDM2_MSTRCLKGEN                       0x241C
 #endif