All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
@ 2021-11-22 11:46 ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add support function to get dma control and lpaif handle to avoid
repeated code in platform driver

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-platform.c | 90 ++++++++++++++++++++---------------------
 1 file changed, 43 insertions(+), 47 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a44162c..59c0884 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -177,6 +177,44 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	return 0;
 }
 
+static void __get_lpaif_handle(struct snd_pcm_substream *substream,
+				struct snd_soc_component *component,
+				struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct lpass_pcm_data *pcm_data = rt->private_data;
+	struct lpass_variant *v = drvdata->variant;
+	int dir = substream->stream;
+	unsigned int dai_id = cpu_dai->driver->id;
+	struct lpaif_dmactl *l_dmactl;
+	struct regmap *l_map;
+	int l_id;
+
+	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
+		l_id = pcm_data->dma_ch;
+		if (dai_id == LPASS_DP_RX) {
+			l_dmactl = drvdata->hdmi_rd_dmactl;
+			l_map = drvdata->hdmiif_map;
+		} else {
+			l_dmactl = drvdata->rd_dmactl;
+			l_map = drvdata->lpaif_map;
+		}
+	} else {
+		l_dmactl = drvdata->wr_dmactl;
+		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+		l_map = drvdata->lpaif_map;
+	}
+	if (dmactl)
+		*dmactl = l_dmactl;
+	if (id)
+		*id = l_id;
+	if (map)
+		*map = l_map;
+}
+
 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 					   struct snd_pcm_substream *substream,
 					   struct snd_pcm_hw_params *params)
@@ -191,22 +229,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	struct lpaif_dmactl *dmactl;
-	int id, dir = substream->stream;
+	int id;
 	int bitwidth;
 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX)
-			dmactl = drvdata->hdmi_rd_dmactl;
-		else
-			dmactl = drvdata->rd_dmactl;
-
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-	}
+	__get_lpaif_handle(substream, component, &dmactl, &id, NULL);
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -379,24 +407,9 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 	int ret, id, ch, dir = substream->stream;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
-
-		id = pcm_data->dma_ch;
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
-	}
 
+	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
 	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
 				runtime->dma_addr);
 	if (ret) {
@@ -444,26 +457,12 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	struct lpaif_dmactl *dmactl;
 	struct regmap *map;
 	int ret, ch, id;
-	int dir = substream->stream;
 	unsigned int reg_irqclr = 0, val_irqclr = 0;
 	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
 	unsigned int dai_id = cpu_dai->driver->id;
 
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
-	}
+	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -597,10 +596,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct regmap *map;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dai_id == LPASS_DP_RX)
-		map = drvdata->hdmiif_map;
-	else
-		map = drvdata->lpaif_map;
+	__get_lpaif_handle(substream, component, NULL, NULL, &map);
 
 	ch = pcm_data->dma_ch;
 
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
@ 2021-11-22 11:46 ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Add support function to get dma control and lpaif handle to avoid
repeated code in platform driver

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-platform.c | 90 ++++++++++++++++++++---------------------
 1 file changed, 43 insertions(+), 47 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a44162c..59c0884 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -177,6 +177,44 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	return 0;
 }
 
+static void __get_lpaif_handle(struct snd_pcm_substream *substream,
+				struct snd_soc_component *component,
+				struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_runtime *rt = substream->runtime;
+	struct lpass_pcm_data *pcm_data = rt->private_data;
+	struct lpass_variant *v = drvdata->variant;
+	int dir = substream->stream;
+	unsigned int dai_id = cpu_dai->driver->id;
+	struct lpaif_dmactl *l_dmactl;
+	struct regmap *l_map;
+	int l_id;
+
+	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
+		l_id = pcm_data->dma_ch;
+		if (dai_id == LPASS_DP_RX) {
+			l_dmactl = drvdata->hdmi_rd_dmactl;
+			l_map = drvdata->hdmiif_map;
+		} else {
+			l_dmactl = drvdata->rd_dmactl;
+			l_map = drvdata->lpaif_map;
+		}
+	} else {
+		l_dmactl = drvdata->wr_dmactl;
+		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+		l_map = drvdata->lpaif_map;
+	}
+	if (dmactl)
+		*dmactl = l_dmactl;
+	if (id)
+		*id = l_id;
+	if (map)
+		*map = l_map;
+}
+
 static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 					   struct snd_pcm_substream *substream,
 					   struct snd_pcm_hw_params *params)
@@ -191,22 +229,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	struct lpaif_dmactl *dmactl;
-	int id, dir = substream->stream;
+	int id;
 	int bitwidth;
 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX)
-			dmactl = drvdata->hdmi_rd_dmactl;
-		else
-			dmactl = drvdata->rd_dmactl;
-
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-	}
+	__get_lpaif_handle(substream, component, &dmactl, &id, NULL);
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -379,24 +407,9 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 	int ret, id, ch, dir = substream->stream;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
-
-		id = pcm_data->dma_ch;
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
-	}
 
+	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
 	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
 				runtime->dma_addr);
 	if (ret) {
@@ -444,26 +457,12 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	struct lpaif_dmactl *dmactl;
 	struct regmap *map;
 	int ret, ch, id;
-	int dir = substream->stream;
 	unsigned int reg_irqclr = 0, val_irqclr = 0;
 	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
 	unsigned int dai_id = cpu_dai->driver->id;
 
 	ch = pcm_data->dma_ch;
-	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		id = pcm_data->dma_ch;
-		if (dai_id == LPASS_DP_RX) {
-			dmactl = drvdata->hdmi_rd_dmactl;
-			map = drvdata->hdmiif_map;
-		} else {
-			dmactl = drvdata->rd_dmactl;
-			map = drvdata->lpaif_map;
-		}
-	} else {
-		dmactl = drvdata->wr_dmactl;
-		id = pcm_data->dma_ch - v->wrdma_channel_start;
-		map = drvdata->lpaif_map;
-	}
+	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -597,10 +596,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct regmap *map;
 	unsigned int dai_id = cpu_dai->driver->id;
 
-	if (dai_id == LPASS_DP_RX)
-		map = drvdata->hdmiif_map;
-	else
-		map = drvdata->lpaif_map;
+	__get_lpaif_handle(substream, component, NULL, NULL, &map);
 
 	ch = pcm_data->dma_ch;
 
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 06/10] ASoC: qcom: Add support for codec dma driver
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Upadate lpass cpu and platform driver to support audio over codec dma
in ADSP bypass use case.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/common.c         |  39 ++++
 sound/soc/qcom/common.h         |   1 +
 sound/soc/qcom/lpass-cpu.c      |  60 +++++-
 sound/soc/qcom/lpass-platform.c | 424 ++++++++++++++++++++++++++++++++++++++--
 4 files changed, 508 insertions(+), 16 deletions(-)

diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 09af007..26d3752 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -4,6 +4,7 @@
 
 #include <linux/module.h>
 #include "common.h"
+#include "lpass.h"
 
 int qcom_snd_parse_of(struct snd_soc_card *card)
 {
@@ -169,4 +170,42 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 }
 EXPORT_SYMBOL(qcom_snd_parse_of);
 
+bool is_cdc_dma_port(int dai_id)
+{
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_RX1:
+	case LPASS_CDC_DMA_RX2:
+	case LPASS_CDC_DMA_RX3:
+	case LPASS_CDC_DMA_RX4:
+	case LPASS_CDC_DMA_RX5:
+	case LPASS_CDC_DMA_RX6:
+	case LPASS_CDC_DMA_RX7:
+	case LPASS_CDC_DMA_RX8:
+	case LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0:
+	case LPASS_CDC_DMA_TX1:
+	case LPASS_CDC_DMA_TX2:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_TX4:
+	case LPASS_CDC_DMA_TX5:
+	case LPASS_CDC_DMA_TX6:
+	case LPASS_CDC_DMA_TX7:
+	case LPASS_CDC_DMA_TX8:
+	case LPASS_CDC_DMA_VA_TX0:
+	case LPASS_CDC_DMA_VA_TX1:
+	case LPASS_CDC_DMA_VA_TX2:
+	case LPASS_CDC_DMA_VA_TX3:
+	case LPASS_CDC_DMA_VA_TX4:
+	case LPASS_CDC_DMA_VA_TX5:
+	case LPASS_CDC_DMA_VA_TX6:
+	case LPASS_CDC_DMA_VA_TX7:
+	case LPASS_CDC_DMA_VA_TX8:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(is_cdc_dma_port);
+
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index f05c05b..a8fea4c 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -7,5 +7,6 @@
 #include <sound/soc.h>
 
 int qcom_snd_parse_of(struct snd_soc_card *card);
+bool is_cdc_dma_port(int dai_id);
 
 #endif
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 3bd9eb3..9e6656c 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,6 +17,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 #include "lpass-lpaif-reg.h"
+#include "common.h"
 #include "lpass.h"
 
 #define LPASS_CPU_MAX_MI2S_LINES	4
@@ -857,7 +858,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
 		}
 		if (id == LPASS_DP_RX) {
 			data->hdmi_port_enable = 1;
-		} else {
+		} else if (is_cdc_dma_port(id))
+			data->codec_dma_enable = 1;
+		else {
 			data->mi2s_playback_sd_mode[id] =
 				of_lpass_cpu_parse_sd_lines(dev, node,
 							    "qcom,playback-sd-lines");
@@ -872,6 +875,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
+	struct resource *res;
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
@@ -897,6 +901,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	of_lpass_cpu_parse_dai_data(dev, drvdata);
 
+	drvdata->num_clks =  variant->num_clks;
+	if (drvdata->codec_dma_enable) {
+		drvdata->rxtx_lpaif =
+				devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
+		if (IS_ERR(drvdata->rxtx_lpaif))
+			return PTR_ERR(drvdata->rxtx_lpaif);
+
+		drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
+		if (IS_ERR(drvdata->va_lpaif))
+			return PTR_ERR(drvdata->va_lpaif);
+
+		lpass_rxtx_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
+					variant->rxtx_wrdma_channels +
+					variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
+
+		drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
+					&lpass_rxtx_regmap_config);
+		if (IS_ERR(drvdata->rxtx_lpaif_map)) {
+			dev_err(dev, "error initializing rxtx regmap: %ld\n",
+				PTR_ERR(drvdata->rxtx_lpaif_map));
+			return PTR_ERR(drvdata->rxtx_lpaif_map);
+		}
+		lpass_va_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
+					variant->va_wrdma_channels +
+					variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
+
+		drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
+					&lpass_va_regmap_config);
+		if (IS_ERR(drvdata->va_lpaif_map)) {
+			dev_err(dev, "error initializing va regmap: %ld\n",
+				PTR_ERR(drvdata->va_lpaif_map));
+			return PTR_ERR(drvdata->va_lpaif_map);
+		}
+		drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
+					sizeof(*drvdata->cdc_clks), GFP_KERNEL);
+		drvdata->cdc_num_clks =  variant->cdc_dma_num_clks;
+
+		for (i = 0; i < drvdata->cdc_num_clks; i++)
+			drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
+
+		ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
+		if (ret) {
+			dev_err(dev, "Failed to get clocks %d\n", ret);
+			return ret;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+		drvdata->va_cdc_dma_lpm_buf = res->start;
+	}
 	drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
 	if (IS_ERR(drvdata->lpaif))
 		return PTR_ERR(drvdata->lpaif);
@@ -939,7 +995,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	for (i = 0; i < variant->num_dai; i++) {
 		dai_id = variant->dai_driver[i].id;
-		if (dai_id == LPASS_DP_RX)
+		if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
 			continue;
 
 		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 59c0884..4b79908 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -14,12 +14,15 @@
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "lpass-lpaif-reg.h"
+#include "common.h"
 #include "lpass.h"
 
 #define DRV_NAME "lpass-platform"
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
+#define LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE (24 * 1024)
+#define LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
 
 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.info			=	SNDRV_PCM_INFO_MMAP |
@@ -45,6 +48,103 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.fifo_size		=	0,
 };
 
+static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static const struct snd_pcm_hardware lpass_platform_va_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
+	int rval;
+
+	drvdata->rxtx_rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->rxtx_rd_dmactl == NULL)
+		return -ENOMEM;
+
+	drvdata->rxtx_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->rxtx_wr_dmactl == NULL)
+		return -ENOMEM;
+
+	rd_dmactl = drvdata->rxtx_rd_dmactl;
+	wr_dmactl = drvdata->rxtx_wr_dmactl;
+
+	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
+					    &v->rxtx_rdma_intf, 15);
+	if (rval)
+		return rval;
+
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->rxtx_wrdma_intf, 15);
+}
+
+static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *wr_dmactl;
+
+	drvdata->va_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->va_wr_dmactl == NULL)
+		return -ENOMEM;
+
+	wr_dmactl = drvdata->va_wr_dmactl;
+
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->va_wrdma_intf, 15);
+}
+
+
 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
 					 struct regmap *map)
 {
@@ -126,22 +226,43 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 	if (cpu_dai->driver->id == LPASS_DP_RX) {
 		map = drvdata->hdmiif_map;
 		drvdata->hdmi_substream[dma_ch] = substream;
+	} else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) {
+		map = drvdata->rxtx_lpaif_map;
+		drvdata->rxtx_substream[dma_ch] = substream;
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		map = drvdata->va_lpaif_map;
+		drvdata->va_substream[dma_ch] = substream;
 	} else {
 		map = drvdata->lpaif_map;
 		drvdata->substream[dma_ch] = substream;
 	}
 	data->dma_ch = dma_ch;
-	ret = regmap_write(map,
-			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev,
-			"error writing to rdmactl reg: %d\n", ret);
-		return ret;
+	if (!(dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0)) {
+		ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
+		if (ret) {
+			dev_err(soc_runtime->dev,
+				"error writing to rdmactl reg: %d\n", ret);
+			return ret;
+		}
 	}
-	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
-
-	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
 
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
+		runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		break;
+	case LPASS_CDC_DMA_VA_TX0:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
+		runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		break;
+	default:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
+		runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
+		break;
+	}
 	ret = snd_pcm_hw_constraint_integer(runtime,
 			SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0) {
@@ -168,6 +289,10 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	data = runtime->private_data;
 	if (dai_id == LPASS_DP_RX)
 		drvdata->hdmi_substream[data->dma_ch] = NULL;
+	else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3)
+		drvdata->rxtx_substream[data->dma_ch] = NULL;
+	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
+		drvdata->va_substream[data->dma_ch] = NULL;
 	else
 		drvdata->substream[data->dma_ch] = NULL;
 	if (v->free_dma_channel)
@@ -198,14 +323,27 @@ static void __get_lpaif_handle(struct snd_pcm_substream *substream,
 		if (dai_id == LPASS_DP_RX) {
 			l_dmactl = drvdata->hdmi_rd_dmactl;
 			l_map = drvdata->hdmiif_map;
+		} else if (dai_id == LPASS_CDC_DMA_RX0) {
+			l_map = drvdata->rxtx_lpaif_map;
+			l_dmactl = drvdata->rxtx_rd_dmactl;
 		} else {
 			l_dmactl = drvdata->rd_dmactl;
 			l_map = drvdata->lpaif_map;
 		}
 	} else {
-		l_dmactl = drvdata->wr_dmactl;
-		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
-		l_map = drvdata->lpaif_map;
+		if (dai_id == LPASS_CDC_DMA_TX3) {
+			l_dmactl = drvdata->rxtx_wr_dmactl;
+			l_map = drvdata->rxtx_lpaif_map;
+			l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+		} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+			l_dmactl = drvdata->va_wr_dmactl;
+			l_map = drvdata->va_lpaif_map;
+			l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+		} else {
+			l_dmactl = drvdata->wr_dmactl;
+			l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+			l_map = drvdata->lpaif_map;
+		}
 	}
 	if (dmactl)
 		*dmactl = l_dmactl;
@@ -256,6 +394,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	}
 
 	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_VA_TX0:
+		break;
 	case LPASS_DP_RX:
 		ret = regmap_fields_write(dmactl->burst8, id,
 							LPAIF_DMACTL_BURSTEN_INCR4);
@@ -380,6 +522,10 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 
 	if (dai_id == LPASS_DP_RX)
 		map = drvdata->hdmiif_map;
+	else if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0)
+		return 0;
 	else
 		map = drvdata->lpaif_map;
 
@@ -434,6 +580,16 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 		return ret;
 	}
 
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0) {
+		ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
+				ret, id);
+			return ret;
+		}
+	}
 	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
@@ -476,6 +632,22 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			return ret;
 		}
 		switch (dai_id) {
+		case LPASS_CDC_DMA_RX0:
+		case LPASS_CDC_DMA_TX3:
+		case LPASS_CDC_DMA_VA_TX0:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
 		case LPASS_DP_RX:
 			ret = regmap_fields_write(dmactl->dyncclk, id,
 					 LPAIF_DMACTL_DYNCLK_ON);
@@ -540,6 +712,24 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			return ret;
 		}
 		switch (dai_id) {
+		case LPASS_CDC_DMA_RX0:
+		case LPASS_CDC_DMA_TX3:
+		case LPASS_CDC_DMA_VA_TX0:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+
+		break;
 		case LPASS_DP_RX:
 			ret = regmap_fields_write(dmactl->dyncclk, id,
 					 LPAIF_DMACTL_DYNCLK_OFF);
@@ -619,6 +809,38 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
 }
 
+static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long size, offset;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	size = vma->vm_end - vma->vm_start;
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+	return io_remap_pfn_range(vma, vma->vm_start,
+			(runtime->dma_addr + offset) >> PAGE_SHIFT,
+			size, vma->vm_page_prot);
+
+}
+
+static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
+				      struct snd_pcm_substream *substream,
+				      struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0) {
+		return lpass_platform_cdc_dma_mmap(component, substream, vma);
+	}
+	return 0;
+}
+
 static irqreturn_t lpass_dma_interrupt_handler(
 			struct snd_pcm_substream *substream,
 			struct lpass_data *drvdata,
@@ -635,6 +857,14 @@ static irqreturn_t lpass_dma_interrupt_handler(
 
 	mask = LPAIF_IRQ_ALL(chan);
 	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_VA_TX0:
+		map = (dai_id == LPASS_CDC_DMA_VA_TX0) ?
+				drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
+		reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+		val = 0;
+		break;
 	case LPASS_DP_RX:
 		map = drvdata->hdmiif_map;
 		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
@@ -758,18 +988,112 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
 				return rv;
 		}
 	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_RX0), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->rxtx_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
 
+	rv = regmap_read(drvdata->va_lpaif_map,
+			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST,
+			LPASS_CDC_DMA_VA_TX0), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->va_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
 	return IRQ_HANDLED;
 }
 
+static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
+			struct snd_pcm *pcm, int dai_id)
+{
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	else
+		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+
+	ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	buf = &substream->dma_buffer;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	/* Assign Codec DMA buffer pointers */
+	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+	if (dai_id == LPASS_CDC_DMA_RX0) {
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
+	} else if (dai_id == LPASS_CDC_DMA_TX3) {
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		buf->addr = drvdata->va_cdc_dma_lpm_buf;
+	}
+
+	buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
+
+	return 0;
+}
+
 static int lpass_platform_pcm_new(struct snd_soc_component *component,
 				  struct snd_soc_pcm_runtime *soc_runtime)
 {
 	struct snd_pcm *pcm = soc_runtime->pcm;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+
 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
-	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
-					    component->dev, size);
+	if (is_cdc_dma_port(dai_id))
+		return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
+	else
+		return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+						component->dev, size);
 }
 
 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
@@ -804,6 +1128,22 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
 	return regcache_sync(map);
 }
 
+int lpass_platform_copy(struct snd_soc_component *component,
+			 struct snd_pcm_substream *substream, int channel,
+			 unsigned long pos, void __user *buf, unsigned long bytes)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+
+	unsigned char *dma_buf = rt->dma_area + pos +
+				channel * (rt->dma_bytes / rt->channels);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return copy_from_user_toio(dma_buf, buf, bytes);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return copy_to_user_fromio(buf, dma_buf, bytes);
+
+	return 0;
+}
 
 static const struct snd_soc_component_driver lpass_component_driver = {
 	.name		= DRV_NAME,
@@ -814,9 +1154,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
 	.prepare	= lpass_platform_pcmops_prepare,
 	.trigger	= lpass_platform_pcmops_trigger,
 	.pointer	= lpass_platform_pcmops_pointer,
+	.mmap		= lpass_platform_pcmops_mmap,
 	.pcm_construct	= lpass_platform_pcm_new,
 	.suspend		= lpass_platform_pcmops_suspend,
 	.resume			= lpass_platform_pcmops_resume,
+	.copy_user		= lpass_platform_copy,
 
 };
 
@@ -854,6 +1196,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (drvdata->codec_dma_enable) {
+		ret = regmap_write(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_TX3), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		ret = regmap_write(drvdata->va_lpaif_map,
+			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_VA_TX0), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
+		if (drvdata->rxtxif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
+				lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-rxtxif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
+						 drvdata->rxtx_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing rxtx dmactl fields: %d\n", ret);
+			return ret;
+		}
+
+		drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
+		if (drvdata->vaif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
+				lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-vaif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
+						 drvdata->va_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing va dmactl fields: %d\n", ret);
+			return ret;
+		}
+	}
+
 	if (drvdata->hdmi_port_enable) {
 		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
 		if (drvdata->hdmiif_irq < 0)
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 06/10] ASoC: qcom: Add support for codec dma driver
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Upadate lpass cpu and platform driver to support audio over codec dma
in ADSP bypass use case.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/common.c         |  39 ++++
 sound/soc/qcom/common.h         |   1 +
 sound/soc/qcom/lpass-cpu.c      |  60 +++++-
 sound/soc/qcom/lpass-platform.c | 424 ++++++++++++++++++++++++++++++++++++++--
 4 files changed, 508 insertions(+), 16 deletions(-)

diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 09af007..26d3752 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -4,6 +4,7 @@
 
 #include <linux/module.h>
 #include "common.h"
+#include "lpass.h"
 
 int qcom_snd_parse_of(struct snd_soc_card *card)
 {
@@ -169,4 +170,42 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
 }
 EXPORT_SYMBOL(qcom_snd_parse_of);
 
+bool is_cdc_dma_port(int dai_id)
+{
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_RX1:
+	case LPASS_CDC_DMA_RX2:
+	case LPASS_CDC_DMA_RX3:
+	case LPASS_CDC_DMA_RX4:
+	case LPASS_CDC_DMA_RX5:
+	case LPASS_CDC_DMA_RX6:
+	case LPASS_CDC_DMA_RX7:
+	case LPASS_CDC_DMA_RX8:
+	case LPASS_CDC_DMA_RX9:
+	case LPASS_CDC_DMA_TX0:
+	case LPASS_CDC_DMA_TX1:
+	case LPASS_CDC_DMA_TX2:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_TX4:
+	case LPASS_CDC_DMA_TX5:
+	case LPASS_CDC_DMA_TX6:
+	case LPASS_CDC_DMA_TX7:
+	case LPASS_CDC_DMA_TX8:
+	case LPASS_CDC_DMA_VA_TX0:
+	case LPASS_CDC_DMA_VA_TX1:
+	case LPASS_CDC_DMA_VA_TX2:
+	case LPASS_CDC_DMA_VA_TX3:
+	case LPASS_CDC_DMA_VA_TX4:
+	case LPASS_CDC_DMA_VA_TX5:
+	case LPASS_CDC_DMA_VA_TX6:
+	case LPASS_CDC_DMA_VA_TX7:
+	case LPASS_CDC_DMA_VA_TX8:
+		return true;
+	default:
+		return false;
+	}
+}
+EXPORT_SYMBOL(is_cdc_dma_port);
+
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
index f05c05b..a8fea4c 100644
--- a/sound/soc/qcom/common.h
+++ b/sound/soc/qcom/common.h
@@ -7,5 +7,6 @@
 #include <sound/soc.h>
 
 int qcom_snd_parse_of(struct snd_soc_card *card);
+bool is_cdc_dma_port(int dai_id);
 
 #endif
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 3bd9eb3..9e6656c 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,6 +17,7 @@
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
 #include "lpass-lpaif-reg.h"
+#include "common.h"
 #include "lpass.h"
 
 #define LPASS_CPU_MAX_MI2S_LINES	4
@@ -857,7 +858,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
 		}
 		if (id == LPASS_DP_RX) {
 			data->hdmi_port_enable = 1;
-		} else {
+		} else if (is_cdc_dma_port(id))
+			data->codec_dma_enable = 1;
+		else {
 			data->mi2s_playback_sd_mode[id] =
 				of_lpass_cpu_parse_sd_lines(dev, node,
 							    "qcom,playback-sd-lines");
@@ -872,6 +875,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
+	struct resource *res;
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
@@ -897,6 +901,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	of_lpass_cpu_parse_dai_data(dev, drvdata);
 
+	drvdata->num_clks =  variant->num_clks;
+	if (drvdata->codec_dma_enable) {
+		drvdata->rxtx_lpaif =
+				devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
+		if (IS_ERR(drvdata->rxtx_lpaif))
+			return PTR_ERR(drvdata->rxtx_lpaif);
+
+		drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
+		if (IS_ERR(drvdata->va_lpaif))
+			return PTR_ERR(drvdata->va_lpaif);
+
+		lpass_rxtx_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
+					variant->rxtx_wrdma_channels +
+					variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
+
+		drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
+					&lpass_rxtx_regmap_config);
+		if (IS_ERR(drvdata->rxtx_lpaif_map)) {
+			dev_err(dev, "error initializing rxtx regmap: %ld\n",
+				PTR_ERR(drvdata->rxtx_lpaif_map));
+			return PTR_ERR(drvdata->rxtx_lpaif_map);
+		}
+		lpass_va_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
+					variant->va_wrdma_channels +
+					variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
+
+		drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
+					&lpass_va_regmap_config);
+		if (IS_ERR(drvdata->va_lpaif_map)) {
+			dev_err(dev, "error initializing va regmap: %ld\n",
+				PTR_ERR(drvdata->va_lpaif_map));
+			return PTR_ERR(drvdata->va_lpaif_map);
+		}
+		drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
+					sizeof(*drvdata->cdc_clks), GFP_KERNEL);
+		drvdata->cdc_num_clks =  variant->cdc_dma_num_clks;
+
+		for (i = 0; i < drvdata->cdc_num_clks; i++)
+			drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
+
+		ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
+		if (ret) {
+			dev_err(dev, "Failed to get clocks %d\n", ret);
+			return ret;
+		}
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
+		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
+
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
+		drvdata->va_cdc_dma_lpm_buf = res->start;
+	}
 	drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
 	if (IS_ERR(drvdata->lpaif))
 		return PTR_ERR(drvdata->lpaif);
@@ -939,7 +995,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	for (i = 0; i < variant->num_dai; i++) {
 		dai_id = variant->dai_driver[i].id;
-		if (dai_id == LPASS_DP_RX)
+		if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
 			continue;
 
 		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 59c0884..4b79908 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -14,12 +14,15 @@
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "lpass-lpaif-reg.h"
+#include "common.h"
 #include "lpass.h"
 
 #define DRV_NAME "lpass-platform"
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
+#define LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE (24 * 1024)
+#define LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
 
 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.info			=	SNDRV_PCM_INFO_MMAP |
@@ -45,6 +48,103 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.fifo_size		=	0,
 };
 
+static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static const struct snd_pcm_hardware lpass_platform_va_hardware = {
+	.info			=	SNDRV_PCM_INFO_MMAP |
+					SNDRV_PCM_INFO_MMAP_VALID |
+					SNDRV_PCM_INFO_INTERLEAVED |
+					SNDRV_PCM_INFO_PAUSE |
+					SNDRV_PCM_INFO_RESUME,
+	.formats		=	SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+	.rates			=	SNDRV_PCM_RATE_8000_192000,
+	.rate_min		=	8000,
+	.rate_max		=	192000,
+	.channels_min		=	1,
+	.channels_max		=	8,
+	.buffer_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE,
+	.period_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.period_bytes_min	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
+						LPASS_PLATFORM_PERIODS,
+	.periods_min		=	LPASS_PLATFORM_PERIODS,
+	.periods_max		=	LPASS_PLATFORM_PERIODS,
+	.fifo_size		=	0,
+};
+
+static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
+	int rval;
+
+	drvdata->rxtx_rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->rxtx_rd_dmactl == NULL)
+		return -ENOMEM;
+
+	drvdata->rxtx_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->rxtx_wr_dmactl == NULL)
+		return -ENOMEM;
+
+	rd_dmactl = drvdata->rxtx_rd_dmactl;
+	wr_dmactl = drvdata->rxtx_wr_dmactl;
+
+	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
+					    &v->rxtx_rdma_intf, 15);
+	if (rval)
+		return rval;
+
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->rxtx_wrdma_intf, 15);
+}
+
+static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *wr_dmactl;
+
+	drvdata->va_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->va_wr_dmactl == NULL)
+		return -ENOMEM;
+
+	wr_dmactl = drvdata->va_wr_dmactl;
+
+	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
+					    &v->va_wrdma_intf, 15);
+}
+
+
 static int lpass_platform_alloc_dmactl_fields(struct device *dev,
 					 struct regmap *map)
 {
@@ -126,22 +226,43 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 	if (cpu_dai->driver->id == LPASS_DP_RX) {
 		map = drvdata->hdmiif_map;
 		drvdata->hdmi_substream[dma_ch] = substream;
+	} else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) {
+		map = drvdata->rxtx_lpaif_map;
+		drvdata->rxtx_substream[dma_ch] = substream;
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		map = drvdata->va_lpaif_map;
+		drvdata->va_substream[dma_ch] = substream;
 	} else {
 		map = drvdata->lpaif_map;
 		drvdata->substream[dma_ch] = substream;
 	}
 	data->dma_ch = dma_ch;
-	ret = regmap_write(map,
-			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev,
-			"error writing to rdmactl reg: %d\n", ret);
-		return ret;
+	if (!(dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0)) {
+		ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
+		if (ret) {
+			dev_err(soc_runtime->dev,
+				"error writing to rdmactl reg: %d\n", ret);
+			return ret;
+		}
 	}
-	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
-
-	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
 
+	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
+		runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		break;
+	case LPASS_CDC_DMA_VA_TX0:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
+		runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		break;
+	default:
+		snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
+		runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
+		break;
+	}
 	ret = snd_pcm_hw_constraint_integer(runtime,
 			SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0) {
@@ -168,6 +289,10 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	data = runtime->private_data;
 	if (dai_id == LPASS_DP_RX)
 		drvdata->hdmi_substream[data->dma_ch] = NULL;
+	else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3)
+		drvdata->rxtx_substream[data->dma_ch] = NULL;
+	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
+		drvdata->va_substream[data->dma_ch] = NULL;
 	else
 		drvdata->substream[data->dma_ch] = NULL;
 	if (v->free_dma_channel)
@@ -198,14 +323,27 @@ static void __get_lpaif_handle(struct snd_pcm_substream *substream,
 		if (dai_id == LPASS_DP_RX) {
 			l_dmactl = drvdata->hdmi_rd_dmactl;
 			l_map = drvdata->hdmiif_map;
+		} else if (dai_id == LPASS_CDC_DMA_RX0) {
+			l_map = drvdata->rxtx_lpaif_map;
+			l_dmactl = drvdata->rxtx_rd_dmactl;
 		} else {
 			l_dmactl = drvdata->rd_dmactl;
 			l_map = drvdata->lpaif_map;
 		}
 	} else {
-		l_dmactl = drvdata->wr_dmactl;
-		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
-		l_map = drvdata->lpaif_map;
+		if (dai_id == LPASS_CDC_DMA_TX3) {
+			l_dmactl = drvdata->rxtx_wr_dmactl;
+			l_map = drvdata->rxtx_lpaif_map;
+			l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
+		} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+			l_dmactl = drvdata->va_wr_dmactl;
+			l_map = drvdata->va_lpaif_map;
+			l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
+		} else {
+			l_dmactl = drvdata->wr_dmactl;
+			l_id = pcm_data->dma_ch - v->wrdma_channel_start;
+			l_map = drvdata->lpaif_map;
+		}
 	}
 	if (dmactl)
 		*dmactl = l_dmactl;
@@ -256,6 +394,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	}
 
 	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_VA_TX0:
+		break;
 	case LPASS_DP_RX:
 		ret = regmap_fields_write(dmactl->burst8, id,
 							LPAIF_DMACTL_BURSTEN_INCR4);
@@ -380,6 +522,10 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 
 	if (dai_id == LPASS_DP_RX)
 		map = drvdata->hdmiif_map;
+	else if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0)
+		return 0;
 	else
 		map = drvdata->lpaif_map;
 
@@ -434,6 +580,16 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 		return ret;
 	}
 
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0) {
+		ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
+				ret, id);
+			return ret;
+		}
+	}
 	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
@@ -476,6 +632,22 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			return ret;
 		}
 		switch (dai_id) {
+		case LPASS_CDC_DMA_RX0:
+		case LPASS_CDC_DMA_TX3:
+		case LPASS_CDC_DMA_VA_TX0:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
 		case LPASS_DP_RX:
 			ret = regmap_fields_write(dmactl->dyncclk, id,
 					 LPAIF_DMACTL_DYNCLK_ON);
@@ -540,6 +712,24 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			return ret;
 		}
 		switch (dai_id) {
+		case LPASS_CDC_DMA_RX0:
+		case LPASS_CDC_DMA_TX3:
+		case LPASS_CDC_DMA_VA_TX0:
+			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg field: %d\n", ret);
+				return ret;
+			}
+
+			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+
+		break;
 		case LPASS_DP_RX:
 			ret = regmap_fields_write(dmactl->dyncclk, id,
 					 LPAIF_DMACTL_DYNCLK_OFF);
@@ -619,6 +809,38 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
 }
 
+static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,
+			struct snd_pcm_substream *substream,
+			struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long size, offset;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	size = vma->vm_end - vma->vm_start;
+	offset = vma->vm_pgoff << PAGE_SHIFT;
+	return io_remap_pfn_range(vma, vma->vm_start,
+			(runtime->dma_addr + offset) >> PAGE_SHIFT,
+			size, vma->vm_page_prot);
+
+}
+
+static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
+				      struct snd_pcm_substream *substream,
+				      struct vm_area_struct *vma)
+{
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3 ||
+		dai_id == LPASS_CDC_DMA_VA_TX0) {
+		return lpass_platform_cdc_dma_mmap(component, substream, vma);
+	}
+	return 0;
+}
+
 static irqreturn_t lpass_dma_interrupt_handler(
 			struct snd_pcm_substream *substream,
 			struct lpass_data *drvdata,
@@ -635,6 +857,14 @@ static irqreturn_t lpass_dma_interrupt_handler(
 
 	mask = LPAIF_IRQ_ALL(chan);
 	switch (dai_id) {
+	case LPASS_CDC_DMA_RX0:
+	case LPASS_CDC_DMA_TX3:
+	case LPASS_CDC_DMA_VA_TX0:
+		map = (dai_id == LPASS_CDC_DMA_VA_TX0) ?
+				drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
+		reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
+		val = 0;
+		break;
 	case LPASS_DP_RX:
 		map = drvdata->hdmiif_map;
 		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
@@ -758,18 +988,112 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
 				return rv;
 		}
 	}
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_RX0), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->rxtx_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
 
+	rv = regmap_read(drvdata->va_lpaif_map,
+			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST,
+			LPASS_CDC_DMA_VA_TX0), &irqs);
+	if (rv)
+		return IRQ_NONE;
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->va_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
 	return IRQ_HANDLED;
 }
 
+static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
+			struct snd_pcm *pcm, int dai_id)
+{
+	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int ret;
+
+	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	else
+		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
+
+	ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	buf = &substream->dma_buffer;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+
+	/* Assign Codec DMA buffer pointers */
+	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+	if (dai_id == LPASS_CDC_DMA_RX0) {
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
+	} else if (dai_id == LPASS_CDC_DMA_TX3) {
+		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
+		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
+		buf->addr = drvdata->va_cdc_dma_lpm_buf;
+	}
+
+	buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
+
+	return 0;
+}
+
 static int lpass_platform_pcm_new(struct snd_soc_component *component,
 				  struct snd_soc_pcm_runtime *soc_runtime)
 {
 	struct snd_pcm *pcm = soc_runtime->pcm;
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
+	unsigned int dai_id = cpu_dai->driver->id;
+
 	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
 
-	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
-					    component->dev, size);
+	if (is_cdc_dma_port(dai_id))
+		return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
+	else
+		return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
+						component->dev, size);
 }
 
 static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
@@ -804,6 +1128,22 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
 	return regcache_sync(map);
 }
 
+int lpass_platform_copy(struct snd_soc_component *component,
+			 struct snd_pcm_substream *substream, int channel,
+			 unsigned long pos, void __user *buf, unsigned long bytes)
+{
+	struct snd_pcm_runtime *rt = substream->runtime;
+
+	unsigned char *dma_buf = rt->dma_area + pos +
+				channel * (rt->dma_bytes / rt->channels);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return copy_from_user_toio(dma_buf, buf, bytes);
+	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+		return copy_to_user_fromio(buf, dma_buf, bytes);
+
+	return 0;
+}
 
 static const struct snd_soc_component_driver lpass_component_driver = {
 	.name		= DRV_NAME,
@@ -814,9 +1154,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
 	.prepare	= lpass_platform_pcmops_prepare,
 	.trigger	= lpass_platform_pcmops_trigger,
 	.pointer	= lpass_platform_pcmops_pointer,
+	.mmap		= lpass_platform_pcmops_mmap,
 	.pcm_construct	= lpass_platform_pcm_new,
 	.suspend		= lpass_platform_pcmops_suspend,
 	.resume			= lpass_platform_pcmops_resume,
+	.copy_user		= lpass_platform_copy,
 
 };
 
@@ -854,6 +1196,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return ret;
 	}
 
+	if (drvdata->codec_dma_enable) {
+		ret = regmap_write(drvdata->rxtx_lpaif_map,
+			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_TX3), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		ret = regmap_write(drvdata->va_lpaif_map,
+			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_VA_TX0), 0x0);
+		if (ret) {
+			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
+			return ret;
+		}
+		drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
+		if (drvdata->rxtxif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
+				lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-rxtxif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
+						 drvdata->rxtx_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing rxtx dmactl fields: %d\n", ret);
+			return ret;
+		}
+
+		drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
+		if (drvdata->vaif_irq < 0)
+			return -ENODEV;
+
+		ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
+				lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
+				"lpass-irq-vaif", drvdata);
+		if (ret) {
+			dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
+			return ret;
+		}
+
+		ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
+						 drvdata->va_lpaif_map);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"error initializing va dmactl fields: %d\n", ret);
+			return ret;
+		}
+	}
+
 	if (drvdata->hdmi_port_enable) {
 		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
 		if (drvdata->hdmiif_irq < 0)
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 07/10] ASoC: qcom: Add regmap config support for codec dma driver
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Update regmap configuration for supporting headset playback and
capture and DMIC capture using codec dma interface

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-cpu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 9e6656c..ea1542d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -29,6 +29,8 @@
 #define LPASS_CPU_I2S_SD2_3_MASK	GENMASK(3, 2)
 #define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
 #define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
+#define LPASS_REG_READ 1
+#define LPASS_REG_WRITE 0
 
 /*
  * Channel maps for Quad channel playbacks on MI2S Secondary
@@ -799,6 +801,189 @@ static struct regmap_config lpass_hdmi_regmap_config = {
 	.cache_type = REGCACHE_FLAT,
 };
 
+static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQEN_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i) {
+		if (reg == LPAIF_CDC_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i)
+		if (reg == LPAIF_CDC_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i)
+		if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+
+	return false;
+}
+
+static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQEN_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	return false;
+}
+
+static struct regmap_config lpass_rxtx_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_rxtx_regmap_writeable,
+	.readable_reg = lpass_rxtx_regmap_readable,
+	.volatile_reg = lpass_rxtx_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static struct regmap_config lpass_va_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_va_regmap_writeable,
+	.readable_reg = lpass_va_regmap_readable,
+	.volatile_reg = lpass_va_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
 static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
 						struct device_node *node,
 						const char *name)
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 07/10] ASoC: qcom: Add regmap config support for codec dma driver
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Update regmap configuration for supporting headset playback and
capture and DMIC capture using codec dma interface

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-cpu.c | 185 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 185 insertions(+)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 9e6656c..ea1542d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -29,6 +29,8 @@
 #define LPASS_CPU_I2S_SD2_3_MASK	GENMASK(3, 2)
 #define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
 #define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
+#define LPASS_REG_READ 1
+#define LPASS_REG_WRITE 0
 
 /*
  * Channel maps for Quad channel playbacks on MI2S Secondary
@@ -799,6 +801,189 @@ static struct regmap_config lpass_hdmi_regmap_config = {
 	.cache_type = REGCACHE_FLAT,
 };
 
+static bool __lpass_rxtx_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQEN_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i) {
+		if (reg == LPAIF_CDC_RDMACTL_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMABASE_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMABUFF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_RDMAPER_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_CDC_RDMA_INTF_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACTL_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABASE_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABUFF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_WRDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_WRDMAPER_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+		if (reg == LPAIF_CDC_WRDMA_INTF_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_rxtx_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_rxtx_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_rxtx_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_rxtx_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->rxtx_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+	}
+
+	for (i = 0; i < v->rxtx_rdma_channels; ++i)
+		if (reg == LPAIF_CDC_RDMACURR_REG(v, i, LPASS_CDC_DMA_RX0))
+			return true;
+
+	for (i = 0; i < v->rxtx_wrdma_channels; ++i)
+		if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->rxtx_wrdma_channel_start,
+							LPASS_CDC_DMA_TX3))
+			return true;
+
+	return false;
+}
+
+static bool __lpass_va_regmap_accessible(struct device *dev, unsigned int reg, bool rw)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQEN_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACTL_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABASE_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMABUFF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (rw == LPASS_REG_READ) {
+			if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+				return true;
+		}
+		if (reg == LPAIF_CDC_WRDMAPER_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_CDC_WRDMA_INTF_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+	return false;
+}
+
+static bool lpass_va_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_WRITE);
+}
+
+static bool lpass_va_regmap_readable(struct device *dev, unsigned int reg)
+{
+	return __lpass_va_regmap_accessible(dev, reg, LPASS_REG_READ);
+}
+
+static bool lpass_va_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	for (i = 0; i < v->va_irq_ports; ++i) {
+		if (reg == LPAIF_RXTX_IRQCLEAR_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+		if (reg == LPAIF_RXTX_IRQSTAT_REG(v, i, LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	for (i = 0; i < v->va_wrdma_channels; ++i) {
+		if (reg == LPAIF_CDC_WRDMACURR_REG(v, i + v->va_wrdma_channel_start,
+							LPASS_CDC_DMA_VA_TX0))
+			return true;
+	}
+
+	return false;
+}
+
+static struct regmap_config lpass_rxtx_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_rxtx_regmap_writeable,
+	.readable_reg = lpass_rxtx_regmap_readable,
+	.volatile_reg = lpass_rxtx_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
+static struct regmap_config lpass_va_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_va_regmap_writeable,
+	.readable_reg = lpass_va_regmap_readable,
+	.volatile_reg = lpass_va_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+
 static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
 						struct device_node *node,
 						const char *name)
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add bindings for lpass sc7280 based soundcards which supports
audio over i2s based speaker, soundwire based headset, msm dmics
and HDMI Port.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 69 +++++++++++++++++++---
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
index 1e23c0e..0f5a57c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
@@ -22,35 +22,36 @@ properties:
       - qcom,lpass-cpu
       - qcom,apq8016-lpass-cpu
       - qcom,sc7180-lpass-cpu
+      - qcom,sc7280-lpass-cpu
 
   reg:
-    maxItems: 2
+    maxItems: 5
     description: LPAIF core registers
 
   reg-names:
-    maxItems: 2
+    maxItems: 5
 
   clocks:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   clock-names:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   interrupts:
-    maxItems: 2
+    maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    maxItems: 2
+    maxItems: 4
 
   qcom,adsp:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: Phandle for the audio DSP node
 
   iommus:
-    maxItems: 2
+    maxItems: 3
     description: Phandle to apps_smmu node with sid mask
 
   power-domains:
@@ -69,7 +70,7 @@ patternProperties:
   "^dai-link@[0-9a-f]$":
     type: object
     description: |
-      LPASS CPU dai node for each I2S device. Bindings of each node
+      LPASS CPU dai node for each I2S device or Soundwire device. Bindings of each node
       depends on the specific driver providing the functionality and
       properties.
     properties:
@@ -174,6 +175,58 @@ allOf:
         - iommus
         - power-domains
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: qcom,sc7280-lpass-cpu
+
+    then:
+      properties:
+        clock-names:
+          oneOf:
+            - items:   #for I2S
+                - const: lpass_aon_cc_audio_hm_h_clk
+                - const: lpass_core_cc_sysnoc_mport_core_clk
+                - const: lpass_core_cc_ext_if1_ibit_clk
+            - items:   #for Soundwire
+                - const: lpass_aon_cc_audio_hm_h_clk
+                - const: lpass_audio_cc_codec_mem0_clk
+                - const: lpass_audio_cc_codec_mem1_clk
+                - const: lpass_audio_cc_codec_mem2_clk
+            - items:   #for HDMI
+                - const: lpass_aon_cc_audio_hm_h_clk
+
+        reg-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-cdc-lpm
+                - const: lpass-rxtx-lpaif
+                - const: lpass-va-lpaif
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+        interrupt-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-irq-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-hdmi
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-vaif
+                - const: lpass-irq-rxtxif
+                - const: lpass-irq-hdmi
+
+      required:
+        - iommus
+        - power-domains
+
 examples:
   - |
     #include <dt-bindings/sound/sc7180-lpass.h>
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Add bindings for lpass sc7280 based soundcards which supports
audio over i2s based speaker, soundwire based headset, msm dmics
and HDMI Port.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 69 +++++++++++++++++++---
 1 file changed, 61 insertions(+), 8 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
index 1e23c0e..0f5a57c 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
@@ -22,35 +22,36 @@ properties:
       - qcom,lpass-cpu
       - qcom,apq8016-lpass-cpu
       - qcom,sc7180-lpass-cpu
+      - qcom,sc7280-lpass-cpu
 
   reg:
-    maxItems: 2
+    maxItems: 5
     description: LPAIF core registers
 
   reg-names:
-    maxItems: 2
+    maxItems: 5
 
   clocks:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   clock-names:
     minItems: 3
-    maxItems: 6
+    maxItems: 7
 
   interrupts:
-    maxItems: 2
+    maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    maxItems: 2
+    maxItems: 4
 
   qcom,adsp:
     $ref: /schemas/types.yaml#/definitions/phandle
     description: Phandle for the audio DSP node
 
   iommus:
-    maxItems: 2
+    maxItems: 3
     description: Phandle to apps_smmu node with sid mask
 
   power-domains:
@@ -69,7 +70,7 @@ patternProperties:
   "^dai-link@[0-9a-f]$":
     type: object
     description: |
-      LPASS CPU dai node for each I2S device. Bindings of each node
+      LPASS CPU dai node for each I2S device or Soundwire device. Bindings of each node
       depends on the specific driver providing the functionality and
       properties.
     properties:
@@ -174,6 +175,58 @@ allOf:
         - iommus
         - power-domains
 
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: qcom,sc7280-lpass-cpu
+
+    then:
+      properties:
+        clock-names:
+          oneOf:
+            - items:   #for I2S
+                - const: lpass_aon_cc_audio_hm_h_clk
+                - const: lpass_core_cc_sysnoc_mport_core_clk
+                - const: lpass_core_cc_ext_if1_ibit_clk
+            - items:   #for Soundwire
+                - const: lpass_aon_cc_audio_hm_h_clk
+                - const: lpass_audio_cc_codec_mem0_clk
+                - const: lpass_audio_cc_codec_mem1_clk
+                - const: lpass_audio_cc_codec_mem2_clk
+            - items:   #for HDMI
+                - const: lpass_aon_cc_audio_hm_h_clk
+
+        reg-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-cdc-lpm
+                - const: lpass-rxtx-lpaif
+                - const: lpass-va-lpaif
+                - const: lpass-hdmiif
+                - const: lpass-lpaif
+        interrupt-names:
+          anyOf:
+            - items:   #for I2S
+                - const: lpass-irq-lpaif
+            - items:   #for I2S and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-hdmi
+            - items:   #for I2S, soundwire and HDMI
+                - const: lpass-irq-lpaif
+                - const: lpass-irq-vaif
+                - const: lpass-irq-rxtxif
+                - const: lpass-irq-hdmi
+
+      required:
+        - iommus
+        - power-domains
+
 examples:
   - |
     #include <dt-bindings/sound/sc7180-lpass.h>
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 09/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add platform driver for configuring sc7280 lpass core I2S and
DMA configuration to support playback & capture to external codecs
connected over secondary MI2S interface and soundwire interface.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-sc7280.c | 416 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 416 insertions(+)
 create mode 100644 sound/soc/qcom/lpass-sc7280.c

diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
new file mode 100644
index 0000000..20ad3ee
--- /dev/null
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ *
+ * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS
+ */
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/sound/sc7180-lpass.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
+	{
+		.id = LPASS_CDC_DMA_RX0,
+		.name = "CDC DMA RX",
+		.playback = {
+			.stream_name = "WCD Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+	{
+		.id = LPASS_CDC_DMA_TX3,
+		.name = "CDC DMA TX",
+		.capture = {
+			.stream_name = "WCD Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 1,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+
+	{
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name = "Secondary MI2S Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops	= &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	{
+		.id = LPASS_DP_RX,
+		.name = "Hdmi",
+		.playback = {
+			.stream_name = "DP Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S24,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_hdmi_dai_ops,
+	},
+	{
+		.id = LPASS_CDC_DMA_VA_TX0,
+		.name = "CDC DMA VA",
+		.capture = {
+			.stream_name = "DMIC Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 4,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+};
+
+static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata,
+				int direction, unsigned int dai_id)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = 0;
+
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+	dai_id == LPASS_CDC_DMA_TX3) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+									v->rxtx_rdma_channels);
+
+			if (chan >= v->rxtx_rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+							v->rxtx_wrdma_channel_start +
+							v->rxtx_wrdma_channels,
+							v->rxtx_wrdma_channel_start);
+
+			if (chan >=	 v->rxtx_wrdma_channel_start + v->rxtx_wrdma_channels)
+				return -EBUSY;
+		}
+
+		set_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->va_dma_ch_bit_map,
+									v->va_rdma_channels);
+
+			if (chan >= v->va_rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->va_dma_ch_bit_map,
+							v->va_wrdma_channel_start +
+							v->va_wrdma_channels,
+							v->va_wrdma_channel_start);
+
+			if (chan >=	 v->va_wrdma_channel_start + v->va_wrdma_channels)
+				return -EBUSY;
+		}
+
+		set_bit(chan, &drvdata->va_dma_ch_bit_map);
+	} else if (dai_id == LPASS_DP_RX) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->hdmi_dma_ch_bit_map,
+									v->hdmi_rdma_channels);
+
+			if (chan >= v->hdmi_rdma_channels)
+				return -EBUSY;
+		}
+		set_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+	} else {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
+									v->rdma_channels);
+
+			if (chan >= v->rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
+							v->wrdma_channel_start +
+							v->wrdma_channels,
+							v->wrdma_channel_start);
+
+			if (chan >=	 v->wrdma_channel_start + v->wrdma_channels)
+				return -EBUSY;
+		}
+		set_bit(chan, &drvdata->dma_ch_bit_map);
+	}
+	return chan;
+}
+
+static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
+{
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3)
+		clear_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
+		clear_bit(chan, &drvdata->va_dma_ch_bit_map);
+	else if (dai_id == LPASS_DP_RX)
+		clear_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+	else
+		clear_bit(chan, &drvdata->dma_ch_bit_map);
+
+	return 0;
+}
+
+static int sc7280_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *variant = drvdata->variant;
+	struct device *dev = &pdev->dev;
+
+	drvdata->clks = devm_kcalloc(dev, variant->num_clks,
+					sizeof(*drvdata->clks), GFP_KERNEL);
+	drvdata->num_clks = variant->num_clks;
+
+	drvdata->aon_cc_audio_hm_h = devm_clk_get(dev, "lpass_aon_cc_audio_hm_h_clk");
+	if (IS_ERR(drvdata->aon_cc_audio_hm_h))
+		return PTR_ERR(drvdata->aon_cc_audio_hm_h);
+	drvdata->core_cc_sysnoc_mport_core = devm_clk_get(dev,
+					"lpass_core_cc_sysnoc_mport_core_clk");
+	if (IS_ERR(drvdata->core_cc_sysnoc_mport_core))
+		return PTR_ERR(drvdata->core_cc_sysnoc_mport_core);
+
+	clk_prepare_enable(drvdata->aon_cc_audio_hm_h);
+	clk_prepare_enable(drvdata->core_cc_sysnoc_mport_core);
+	return 0;
+}
+
+static int sc7280_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(drvdata->core_cc_sysnoc_mport_core);
+	clk_disable_unprepare(drvdata->aon_cc_audio_hm_h);
+
+	return 0;
+}
+
+static struct lpass_variant sc7280_data = {
+	.i2sctrl_reg_base		= 0x1000,
+	.i2sctrl_reg_stride		= 0x1000,
+	.i2s_ports			= 3,
+	.irq_reg_base			= 0x9000,
+	.irq_reg_stride			= 0x1000,
+	.irq_ports			= 3,
+	.rdma_reg_base			= 0xC000,
+	.rdma_reg_stride		= 0x1000,
+	.rdma_channels			= 5,
+	.rxtx_rdma_reg_base		= 0xC000,
+	.rxtx_rdma_reg_stride		= 0x1000,
+	.rxtx_rdma_channels		= 8,
+	.hdmi_rdma_reg_base		= 0x64000,
+	.hdmi_rdma_reg_stride		= 0x1000,
+	.hdmi_rdma_channels		= 4,
+	.dmactl_audif_start		= 1,
+	.wrdma_reg_base			= 0x18000,
+	.wrdma_reg_stride		= 0x1000,
+	.wrdma_channel_start		= 5,
+	.wrdma_channels			= 4,
+	.rxtx_irq_reg_base		= 0x9000,
+	.rxtx_irq_reg_stride		= 0x1000,
+	.rxtx_irq_ports			= 3,
+	.rxtx_wrdma_reg_base		= 0x18000,
+	.rxtx_wrdma_reg_stride		= 0x1000,
+	.rxtx_wrdma_channel_start	= 5,
+	.rxtx_wrdma_channels		= 6,
+	.va_wrdma_reg_base		= 0x18000,
+	.va_wrdma_reg_stride		= 0x1000,
+	.va_wrdma_channel_start		= 5,
+	.va_wrdma_channels		= 3,
+	.va_irq_reg_base		= 0x9000,
+	.va_irq_reg_stride		= 0x1000,
+	.va_irq_ports			= 3,
+
+	.loopback			= REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000),
+	.spken				= REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000),
+	.spkmode			= REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000),
+	.spkmono			= REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000),
+	.micen				= REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000),
+	.micmode			= REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000),
+	.micmono			= REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000),
+	.wssrc				= REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000),
+	.bitwidth			= REG_FIELD_ID(0x1000, 0, 1, 3, 0x1000),
+
+	.rdma_dyncclk			= REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000),
+	.rdma_bursten			= REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000),
+	.rdma_wpscnt			= REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000),
+	.rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000),
+	.rdma_fifowm			= REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000),
+	.rdma_enable			= REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000),
+
+	.rxtx_rdma_enable		= REG_FIELD_ID(0xC000, 0, 0, 7, 0x1000),
+	.rxtx_rdma_fifowm		= REG_FIELD_ID(0xC000, 1, 11, 7, 0x1000),
+	.rxtx_rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 7, 0x1000),
+	.rxtx_rdma_wpscnt		= REG_FIELD_ID(0xC000, 16, 19, 7, 0x1000),
+	.rxtx_rdma_bursten		= REG_FIELD_ID(0xC000, 20, 20, 7, 0x1000),
+	.rxtx_rdma_dyncclk		= REG_FIELD_ID(0xC000, 21, 21, 7, 0x1000),
+
+	.rxtx_rdma_codec_ch		= REG_FIELD_ID(0xC050, 0, 7, 7, 0x1000),
+	.rxtx_rdma_codec_intf		= REG_FIELD_ID(0xC050, 16, 19, 7, 0x1000),
+	.rxtx_rdma_codec_fs_delay	= REG_FIELD_ID(0xC050, 21, 24, 7, 0x1000),
+	.rxtx_rdma_codec_fs_sel		= REG_FIELD_ID(0xC050, 25, 27, 7, 0x1000),
+	.rxtx_rdma_codec_pack		= REG_FIELD_ID(0xC050, 29, 29, 5, 0x1000),
+	.rxtx_rdma_codec_enable		= REG_FIELD_ID(0xC050, 30, 30, 7, 0x1000),
+
+	.rxtx_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.rxtx_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.rxtx_wrdma_intf		= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.rxtx_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.rxtx_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.rxtx_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.rxtx_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.rxtx_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_sel	= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.rxtx_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.rxtx_wrdma_codec_enable	= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.va_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.va_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.va_wrdma_intf			= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.va_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.va_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.va_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.va_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.va_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.va_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.va_wrdma_codec_fs_sel		= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.va_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.va_wrdma_codec_enable		= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.hdmi_tx_ctl_addr		= 0x1000,
+	.hdmi_legacy_addr		= 0x1008,
+	.hdmi_vbit_addr			= 0x610c0,
+	.hdmi_ch_lsb_addr		= 0x61048,
+	.hdmi_ch_msb_addr		= 0x6104c,
+	.ch_stride			= 0x8,
+	.hdmi_parity_addr		= 0x61034,
+	.hdmi_dmactl_addr		= 0x61038,
+	.hdmi_dma_stride		= 0x4,
+	.hdmi_DP_addr			= 0x610c8,
+	.hdmi_sstream_addr		= 0x6101c,
+	.hdmi_irq_reg_base		= 0x63000,
+	.hdmi_irq_ports			= 1,
+
+	.hdmi_rdma_dyncclk		= REG_FIELD_ID(0x64000, 14, 14, 4, 0x1000),
+	.hdmi_rdma_bursten		= REG_FIELD_ID(0x64000, 13, 13, 4, 0x1000),
+	.hdmi_rdma_burst8		= REG_FIELD_ID(0x64000, 15, 15, 4, 0x1000),
+	.hdmi_rdma_burst16		= REG_FIELD_ID(0x64000, 16, 16, 4, 0x1000),
+	.hdmi_rdma_dynburst		= REG_FIELD_ID(0x64000, 18, 18, 4, 0x1000),
+	.hdmi_rdma_wpscnt		= REG_FIELD_ID(0x64000, 10, 12, 4, 0x1000),
+	.hdmi_rdma_fifowm		= REG_FIELD_ID(0x64000, 1, 5, 4, 0x1000),
+	.hdmi_rdma_enable		= REG_FIELD_ID(0x64000, 0, 0, 4, 0x1000),
+
+	.sstream_en			= REG_FIELD(0x6101c, 0, 0),
+	.dma_sel			= REG_FIELD(0x6101c, 1, 2),
+	.auto_bbit_en			= REG_FIELD(0x6101c, 3, 3),
+	.layout				= REG_FIELD(0x6101c, 4, 4),
+	.layout_sp			= REG_FIELD(0x6101c, 5, 8),
+	.set_sp_on_en			= REG_FIELD(0x6101c, 10, 10),
+	.dp_audio			= REG_FIELD(0x6101c, 11, 11),
+	.dp_staffing_en			= REG_FIELD(0x6101c, 12, 12),
+	.dp_sp_b_hw_en			= REG_FIELD(0x6101c, 13, 13),
+
+	.mute				= REG_FIELD(0x610c8, 0, 0),
+	.as_sdp_cc			= REG_FIELD(0x610c8, 1, 3),
+	.as_sdp_ct			= REG_FIELD(0x610c8, 4, 7),
+	.aif_db4			= REG_FIELD(0x610c8, 8, 15),
+	.frequency			= REG_FIELD(0x610c8, 16, 21),
+	.mst_index			= REG_FIELD(0x610c8, 28, 29),
+	.dptx_index			= REG_FIELD(0x610c8, 30, 31),
+
+	.soft_reset			= REG_FIELD(0x1000, 31, 31),
+	.force_reset			= REG_FIELD(0x1000, 30, 30),
+
+	.use_hw_chs			= REG_FIELD(0x61038, 0, 0),
+	.use_hw_usr			= REG_FIELD(0x61038, 1, 1),
+	.hw_chs_sel			= REG_FIELD(0x61038, 2, 4),
+	.hw_usr_sel			= REG_FIELD(0x61038, 5, 6),
+
+	.replace_vbit			= REG_FIELD(0x610c0, 0, 0),
+	.vbit_stream			= REG_FIELD(0x610c0, 1, 1),
+
+	.legacy_en			=  REG_FIELD(0x1008, 0, 0),
+	.calc_en			=  REG_FIELD(0x61034, 0, 0),
+	.lsb_bits			=  REG_FIELD(0x61048, 0, 31),
+	.msb_bits			=  REG_FIELD(0x6104c, 0, 31),
+
+
+	.clk_name			= (const char*[]) {
+							"lpass_aon_cc_audio_hm_h_clk",
+							"lpass_core_cc_sysnoc_mport_core_clk"
+						},
+	.num_clks				= 2,
+	.cdc_dma_clk_names		= (const char*[]) {
+								"lpass_audio_cc_codec_mem0_clk",
+								"lpass_audio_cc_codec_mem1_clk",
+								"lpass_audio_cc_codec_mem2_clk",
+								"lpass_aon_cc_va_mem0_clk"
+							},
+	.cdc_dma_num_clks				= 4,
+	.dai_driver				= sc7280_lpass_cpu_dai_driver,
+	.num_dai				= ARRAY_SIZE(sc7280_lpass_cpu_dai_driver),
+	.dai_osr_clk_names		= (const char *[]) {
+							   "null",
+							   "null"
+							},
+	.dai_bit_clk_names		= (const char *[]) {
+								"null",
+								"lpass_core_cc_ext_if0_ibit_clk",
+								"lpass_core_cc_ext_if1_ibit_clk"
+							},
+	.init					= sc7280_lpass_init,
+	.exit					= sc7280_lpass_exit,
+	.alloc_dma_channel		= sc7280_lpass_alloc_dma_channel,
+	.free_dma_channel		= sc7280_lpass_free_dma_channel,
+};
+
+static const struct of_device_id sc7280_lpass_cpu_device_id[] = {
+	{.compatible = "qcom,sc7280-lpass-cpu", .data = &sc7280_data},
+	{}
+};
+MODULE_DEVICE_TABLE(of, sc7280_lpass_cpu_device_id);
+
+static struct platform_driver sc7280_lpass_cpu_platform_driver = {
+	.driver = {
+		.name = "sc7280-lpass-cpu",
+		.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
+	},
+	.probe = asoc_qcom_lpass_cpu_platform_probe,
+	.remove = asoc_qcom_lpass_cpu_platform_remove,
+	.shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
+};
+
+module_platform_driver(sc7280_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("SC7280 LPASS CPU DRIVER");
+MODULE_LICENSE("GPL v2");
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 09/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Add platform driver for configuring sc7280 lpass core I2S and
DMA configuration to support playback & capture to external codecs
connected over secondary MI2S interface and soundwire interface.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/lpass-sc7280.c | 416 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 416 insertions(+)
 create mode 100644 sound/soc/qcom/lpass-sc7280.c

diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
new file mode 100644
index 0000000..20ad3ee
--- /dev/null
+++ b/sound/soc/qcom/lpass-sc7280.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
+ *
+ * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS
+ */
+
+#include <linux/module.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+
+#include <dt-bindings/sound/sc7180-lpass.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
+	{
+		.id = LPASS_CDC_DMA_RX0,
+		.name = "CDC DMA RX",
+		.playback = {
+			.stream_name = "WCD Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+	{
+		.id = LPASS_CDC_DMA_TX3,
+		.name = "CDC DMA TX",
+		.capture = {
+			.stream_name = "WCD Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 1,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+
+	{
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name = "Secondary MI2S Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops	= &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	{
+		.id = LPASS_DP_RX,
+		.name = "Hdmi",
+		.playback = {
+			.stream_name = "DP Playback",
+			.formats		= SNDRV_PCM_FMTBIT_S24,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min		= 48000,
+			.rate_max		= 48000,
+			.channels_min	= 2,
+			.channels_max	= 2,
+		},
+		.ops	= &asoc_qcom_lpass_hdmi_dai_ops,
+	},
+	{
+		.id = LPASS_CDC_DMA_VA_TX0,
+		.name = "CDC DMA VA",
+		.capture = {
+			.stream_name = "DMIC Capture",
+			.formats = SNDRV_PCM_FMTBIT_S16,
+			.rates = SNDRV_PCM_RATE_48000,
+			.rate_min	= 48000,
+			.rate_max	= 48000,
+			.channels_min	= 2,
+			.channels_max	= 4,
+		},
+		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
+	},
+};
+
+static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata,
+				int direction, unsigned int dai_id)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = 0;
+
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+	dai_id == LPASS_CDC_DMA_TX3) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+									v->rxtx_rdma_channels);
+
+			if (chan >= v->rxtx_rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
+							v->rxtx_wrdma_channel_start +
+							v->rxtx_wrdma_channels,
+							v->rxtx_wrdma_channel_start);
+
+			if (chan >=	 v->rxtx_wrdma_channel_start + v->rxtx_wrdma_channels)
+				return -EBUSY;
+		}
+
+		set_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->va_dma_ch_bit_map,
+									v->va_rdma_channels);
+
+			if (chan >= v->va_rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->va_dma_ch_bit_map,
+							v->va_wrdma_channel_start +
+							v->va_wrdma_channels,
+							v->va_wrdma_channel_start);
+
+			if (chan >=	 v->va_wrdma_channel_start + v->va_wrdma_channels)
+				return -EBUSY;
+		}
+
+		set_bit(chan, &drvdata->va_dma_ch_bit_map);
+	} else if (dai_id == LPASS_DP_RX) {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->hdmi_dma_ch_bit_map,
+									v->hdmi_rdma_channels);
+
+			if (chan >= v->hdmi_rdma_channels)
+				return -EBUSY;
+		}
+		set_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+	} else {
+		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+			chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
+									v->rdma_channels);
+
+			if (chan >= v->rdma_channels)
+				return -EBUSY;
+		} else {
+			chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
+							v->wrdma_channel_start +
+							v->wrdma_channels,
+							v->wrdma_channel_start);
+
+			if (chan >=	 v->wrdma_channel_start + v->wrdma_channels)
+				return -EBUSY;
+		}
+		set_bit(chan, &drvdata->dma_ch_bit_map);
+	}
+	return chan;
+}
+
+static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
+{
+	if (dai_id == LPASS_CDC_DMA_RX0 ||
+		dai_id == LPASS_CDC_DMA_TX3)
+		clear_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
+	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
+		clear_bit(chan, &drvdata->va_dma_ch_bit_map);
+	else if (dai_id == LPASS_DP_RX)
+		clear_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
+	else
+		clear_bit(chan, &drvdata->dma_ch_bit_map);
+
+	return 0;
+}
+
+static int sc7280_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *variant = drvdata->variant;
+	struct device *dev = &pdev->dev;
+
+	drvdata->clks = devm_kcalloc(dev, variant->num_clks,
+					sizeof(*drvdata->clks), GFP_KERNEL);
+	drvdata->num_clks = variant->num_clks;
+
+	drvdata->aon_cc_audio_hm_h = devm_clk_get(dev, "lpass_aon_cc_audio_hm_h_clk");
+	if (IS_ERR(drvdata->aon_cc_audio_hm_h))
+		return PTR_ERR(drvdata->aon_cc_audio_hm_h);
+	drvdata->core_cc_sysnoc_mport_core = devm_clk_get(dev,
+					"lpass_core_cc_sysnoc_mport_core_clk");
+	if (IS_ERR(drvdata->core_cc_sysnoc_mport_core))
+		return PTR_ERR(drvdata->core_cc_sysnoc_mport_core);
+
+	clk_prepare_enable(drvdata->aon_cc_audio_hm_h);
+	clk_prepare_enable(drvdata->core_cc_sysnoc_mport_core);
+	return 0;
+}
+
+static int sc7280_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(drvdata->core_cc_sysnoc_mport_core);
+	clk_disable_unprepare(drvdata->aon_cc_audio_hm_h);
+
+	return 0;
+}
+
+static struct lpass_variant sc7280_data = {
+	.i2sctrl_reg_base		= 0x1000,
+	.i2sctrl_reg_stride		= 0x1000,
+	.i2s_ports			= 3,
+	.irq_reg_base			= 0x9000,
+	.irq_reg_stride			= 0x1000,
+	.irq_ports			= 3,
+	.rdma_reg_base			= 0xC000,
+	.rdma_reg_stride		= 0x1000,
+	.rdma_channels			= 5,
+	.rxtx_rdma_reg_base		= 0xC000,
+	.rxtx_rdma_reg_stride		= 0x1000,
+	.rxtx_rdma_channels		= 8,
+	.hdmi_rdma_reg_base		= 0x64000,
+	.hdmi_rdma_reg_stride		= 0x1000,
+	.hdmi_rdma_channels		= 4,
+	.dmactl_audif_start		= 1,
+	.wrdma_reg_base			= 0x18000,
+	.wrdma_reg_stride		= 0x1000,
+	.wrdma_channel_start		= 5,
+	.wrdma_channels			= 4,
+	.rxtx_irq_reg_base		= 0x9000,
+	.rxtx_irq_reg_stride		= 0x1000,
+	.rxtx_irq_ports			= 3,
+	.rxtx_wrdma_reg_base		= 0x18000,
+	.rxtx_wrdma_reg_stride		= 0x1000,
+	.rxtx_wrdma_channel_start	= 5,
+	.rxtx_wrdma_channels		= 6,
+	.va_wrdma_reg_base		= 0x18000,
+	.va_wrdma_reg_stride		= 0x1000,
+	.va_wrdma_channel_start		= 5,
+	.va_wrdma_channels		= 3,
+	.va_irq_reg_base		= 0x9000,
+	.va_irq_reg_stride		= 0x1000,
+	.va_irq_ports			= 3,
+
+	.loopback			= REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000),
+	.spken				= REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000),
+	.spkmode			= REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000),
+	.spkmono			= REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000),
+	.micen				= REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000),
+	.micmode			= REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000),
+	.micmono			= REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000),
+	.wssrc				= REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000),
+	.bitwidth			= REG_FIELD_ID(0x1000, 0, 1, 3, 0x1000),
+
+	.rdma_dyncclk			= REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000),
+	.rdma_bursten			= REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000),
+	.rdma_wpscnt			= REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000),
+	.rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000),
+	.rdma_fifowm			= REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000),
+	.rdma_enable			= REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000),
+
+	.rxtx_rdma_enable		= REG_FIELD_ID(0xC000, 0, 0, 7, 0x1000),
+	.rxtx_rdma_fifowm		= REG_FIELD_ID(0xC000, 1, 11, 7, 0x1000),
+	.rxtx_rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 7, 0x1000),
+	.rxtx_rdma_wpscnt		= REG_FIELD_ID(0xC000, 16, 19, 7, 0x1000),
+	.rxtx_rdma_bursten		= REG_FIELD_ID(0xC000, 20, 20, 7, 0x1000),
+	.rxtx_rdma_dyncclk		= REG_FIELD_ID(0xC000, 21, 21, 7, 0x1000),
+
+	.rxtx_rdma_codec_ch		= REG_FIELD_ID(0xC050, 0, 7, 7, 0x1000),
+	.rxtx_rdma_codec_intf		= REG_FIELD_ID(0xC050, 16, 19, 7, 0x1000),
+	.rxtx_rdma_codec_fs_delay	= REG_FIELD_ID(0xC050, 21, 24, 7, 0x1000),
+	.rxtx_rdma_codec_fs_sel		= REG_FIELD_ID(0xC050, 25, 27, 7, 0x1000),
+	.rxtx_rdma_codec_pack		= REG_FIELD_ID(0xC050, 29, 29, 5, 0x1000),
+	.rxtx_rdma_codec_enable		= REG_FIELD_ID(0xC050, 30, 30, 7, 0x1000),
+
+	.rxtx_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.rxtx_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.rxtx_wrdma_intf		= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.rxtx_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.rxtx_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.rxtx_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.rxtx_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.rxtx_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.rxtx_wrdma_codec_fs_sel	= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.rxtx_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.rxtx_wrdma_codec_enable	= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.va_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
+	.va_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
+	.va_wrdma_intf			= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
+	.va_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
+	.va_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
+	.va_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
+
+	.va_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
+	.va_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
+	.va_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
+	.va_wrdma_codec_fs_sel		= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
+	.va_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
+	.va_wrdma_codec_enable		= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
+
+	.hdmi_tx_ctl_addr		= 0x1000,
+	.hdmi_legacy_addr		= 0x1008,
+	.hdmi_vbit_addr			= 0x610c0,
+	.hdmi_ch_lsb_addr		= 0x61048,
+	.hdmi_ch_msb_addr		= 0x6104c,
+	.ch_stride			= 0x8,
+	.hdmi_parity_addr		= 0x61034,
+	.hdmi_dmactl_addr		= 0x61038,
+	.hdmi_dma_stride		= 0x4,
+	.hdmi_DP_addr			= 0x610c8,
+	.hdmi_sstream_addr		= 0x6101c,
+	.hdmi_irq_reg_base		= 0x63000,
+	.hdmi_irq_ports			= 1,
+
+	.hdmi_rdma_dyncclk		= REG_FIELD_ID(0x64000, 14, 14, 4, 0x1000),
+	.hdmi_rdma_bursten		= REG_FIELD_ID(0x64000, 13, 13, 4, 0x1000),
+	.hdmi_rdma_burst8		= REG_FIELD_ID(0x64000, 15, 15, 4, 0x1000),
+	.hdmi_rdma_burst16		= REG_FIELD_ID(0x64000, 16, 16, 4, 0x1000),
+	.hdmi_rdma_dynburst		= REG_FIELD_ID(0x64000, 18, 18, 4, 0x1000),
+	.hdmi_rdma_wpscnt		= REG_FIELD_ID(0x64000, 10, 12, 4, 0x1000),
+	.hdmi_rdma_fifowm		= REG_FIELD_ID(0x64000, 1, 5, 4, 0x1000),
+	.hdmi_rdma_enable		= REG_FIELD_ID(0x64000, 0, 0, 4, 0x1000),
+
+	.sstream_en			= REG_FIELD(0x6101c, 0, 0),
+	.dma_sel			= REG_FIELD(0x6101c, 1, 2),
+	.auto_bbit_en			= REG_FIELD(0x6101c, 3, 3),
+	.layout				= REG_FIELD(0x6101c, 4, 4),
+	.layout_sp			= REG_FIELD(0x6101c, 5, 8),
+	.set_sp_on_en			= REG_FIELD(0x6101c, 10, 10),
+	.dp_audio			= REG_FIELD(0x6101c, 11, 11),
+	.dp_staffing_en			= REG_FIELD(0x6101c, 12, 12),
+	.dp_sp_b_hw_en			= REG_FIELD(0x6101c, 13, 13),
+
+	.mute				= REG_FIELD(0x610c8, 0, 0),
+	.as_sdp_cc			= REG_FIELD(0x610c8, 1, 3),
+	.as_sdp_ct			= REG_FIELD(0x610c8, 4, 7),
+	.aif_db4			= REG_FIELD(0x610c8, 8, 15),
+	.frequency			= REG_FIELD(0x610c8, 16, 21),
+	.mst_index			= REG_FIELD(0x610c8, 28, 29),
+	.dptx_index			= REG_FIELD(0x610c8, 30, 31),
+
+	.soft_reset			= REG_FIELD(0x1000, 31, 31),
+	.force_reset			= REG_FIELD(0x1000, 30, 30),
+
+	.use_hw_chs			= REG_FIELD(0x61038, 0, 0),
+	.use_hw_usr			= REG_FIELD(0x61038, 1, 1),
+	.hw_chs_sel			= REG_FIELD(0x61038, 2, 4),
+	.hw_usr_sel			= REG_FIELD(0x61038, 5, 6),
+
+	.replace_vbit			= REG_FIELD(0x610c0, 0, 0),
+	.vbit_stream			= REG_FIELD(0x610c0, 1, 1),
+
+	.legacy_en			=  REG_FIELD(0x1008, 0, 0),
+	.calc_en			=  REG_FIELD(0x61034, 0, 0),
+	.lsb_bits			=  REG_FIELD(0x61048, 0, 31),
+	.msb_bits			=  REG_FIELD(0x6104c, 0, 31),
+
+
+	.clk_name			= (const char*[]) {
+							"lpass_aon_cc_audio_hm_h_clk",
+							"lpass_core_cc_sysnoc_mport_core_clk"
+						},
+	.num_clks				= 2,
+	.cdc_dma_clk_names		= (const char*[]) {
+								"lpass_audio_cc_codec_mem0_clk",
+								"lpass_audio_cc_codec_mem1_clk",
+								"lpass_audio_cc_codec_mem2_clk",
+								"lpass_aon_cc_va_mem0_clk"
+							},
+	.cdc_dma_num_clks				= 4,
+	.dai_driver				= sc7280_lpass_cpu_dai_driver,
+	.num_dai				= ARRAY_SIZE(sc7280_lpass_cpu_dai_driver),
+	.dai_osr_clk_names		= (const char *[]) {
+							   "null",
+							   "null"
+							},
+	.dai_bit_clk_names		= (const char *[]) {
+								"null",
+								"lpass_core_cc_ext_if0_ibit_clk",
+								"lpass_core_cc_ext_if1_ibit_clk"
+							},
+	.init					= sc7280_lpass_init,
+	.exit					= sc7280_lpass_exit,
+	.alloc_dma_channel		= sc7280_lpass_alloc_dma_channel,
+	.free_dma_channel		= sc7280_lpass_free_dma_channel,
+};
+
+static const struct of_device_id sc7280_lpass_cpu_device_id[] = {
+	{.compatible = "qcom,sc7280-lpass-cpu", .data = &sc7280_data},
+	{}
+};
+MODULE_DEVICE_TABLE(of, sc7280_lpass_cpu_device_id);
+
+static struct platform_driver sc7280_lpass_cpu_platform_driver = {
+	.driver = {
+		.name = "sc7280-lpass-cpu",
+		.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
+	},
+	.probe = asoc_qcom_lpass_cpu_platform_probe,
+	.remove = asoc_qcom_lpass_cpu_platform_remove,
+	.shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
+};
+
+module_platform_driver(sc7280_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("SC7280 LPASS CPU DRIVER");
+MODULE_LICENSE("GPL v2");
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 10/10] ASoC: qcom: SC7280: Update config for building codec dma drivers
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Srinivasa Rao Mandadapu, Venkata Prasad Potturu

Add configuration for building SC7280 audio codec dma drivers.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/Kconfig  | 13 +++++++++++++
 sound/soc/qcom/Makefile |  4 ++++
 2 files changed, 17 insertions(+)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 530d01f..b46a2e7 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,10 @@ config SND_SOC_LPASS_PLATFORM
 	tristate
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_CDC_DMA
+	tristate
+	select REGMAP_MMIO
+
 config SND_SOC_LPASS_IPQ806X
 	tristate
 	select SND_SOC_LPASS_CPU
@@ -36,6 +40,13 @@ config SND_SOC_LPASS_SC7180
 	select SND_SOC_LPASS_PLATFORM
 	select SND_SOC_LPASS_HDMI
 
+config SND_SOC_LPASS_SC7280
+	tristate
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_HDMI
+	select SND_SOC_LPASS_CDC_DMA
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	select SND_SOC_LPASS_IPQ806X
@@ -156,7 +167,9 @@ config SND_SOC_SC7280
 	tristate "SoC Machine driver for SC7280 boards"
 	depends on I2C && SOUNDWIRE || COMPILE_TEST
 	select SND_SOC_QCOM_COMMON
+	select SND_SOC_LPASS_SC7280
 	select SND_SOC_MAX98357A
+	select SND_SOC_WCD938X
 	select SND_SOC_LPASS_RX_MACRO
 	select SND_SOC_LPASS_TX_MACRO
 	help
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 625aec6..8b7b876 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,18 +1,22 @@
 # SPDX-License-Identifier: GPL-2.0
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
+snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o
 snd-soc-lpass-hdmi-objs := lpass-hdmi.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 snd-soc-lpass-sc7180-objs := lpass-sc7180.o
+snd-soc-lpass-sc7280-objs := lpass-sc7280.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
+obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o
 obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
+obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o
 
 # Machine
 snd-soc-storm-objs := storm.o
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v5 10/10] ASoC: qcom: SC7280: Update config for building codec dma drivers
@ 2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-22 11:46 UTC (permalink / raw)
  To: agross, bjorn.andersson, lgirdwood, broonie, robh+dt, plai,
	bgoswami, perex, tiwai, srinivas.kandagatla, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu, Srinivasa Rao Mandadapu

Add configuration for building SC7280 audio codec dma drivers.

Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
---
 sound/soc/qcom/Kconfig  | 13 +++++++++++++
 sound/soc/qcom/Makefile |  4 ++++
 2 files changed, 17 insertions(+)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 530d01f..b46a2e7 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,10 @@ config SND_SOC_LPASS_PLATFORM
 	tristate
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_CDC_DMA
+	tristate
+	select REGMAP_MMIO
+
 config SND_SOC_LPASS_IPQ806X
 	tristate
 	select SND_SOC_LPASS_CPU
@@ -36,6 +40,13 @@ config SND_SOC_LPASS_SC7180
 	select SND_SOC_LPASS_PLATFORM
 	select SND_SOC_LPASS_HDMI
 
+config SND_SOC_LPASS_SC7280
+	tristate
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_HDMI
+	select SND_SOC_LPASS_CDC_DMA
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	select SND_SOC_LPASS_IPQ806X
@@ -156,7 +167,9 @@ config SND_SOC_SC7280
 	tristate "SoC Machine driver for SC7280 boards"
 	depends on I2C && SOUNDWIRE || COMPILE_TEST
 	select SND_SOC_QCOM_COMMON
+	select SND_SOC_LPASS_SC7280
 	select SND_SOC_MAX98357A
+	select SND_SOC_WCD938X
 	select SND_SOC_LPASS_RX_MACRO
 	select SND_SOC_LPASS_TX_MACRO
 	help
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 625aec6..8b7b876 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,18 +1,22 @@
 # SPDX-License-Identifier: GPL-2.0
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
+snd-soc-lpass-cdc-dma-objs := lpass-cdc-dma.o
 snd-soc-lpass-hdmi-objs := lpass-hdmi.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 snd-soc-lpass-sc7180-objs := lpass-sc7180.o
+snd-soc-lpass-sc7280-objs := lpass-sc7280.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
+obj-$(CONFIG_SND_SOC_LPASS_CDC_DMA) += snd-soc-lpass-cdc-dma.o
 obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 obj-$(CONFIG_SND_SOC_LPASS_SC7180) += snd-soc-lpass-sc7180.o
+obj-$(CONFIG_SND_SOC_LPASS_SC7280) += snd-soc-lpass-sc7280.o
 
 # Machine
 snd-soc-storm-objs := storm.o
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle
  2021-11-22 11:46 ` Srinivasa Rao Mandadapu
                   ` (5 preceding siblings ...)
  (?)
@ 2021-11-23 12:28 ` Srinivas Kandagatla
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivas Kandagatla @ 2021-11-23 12:28 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, bjorn.andersson, lgirdwood,
	broonie, robh+dt, plai, bgoswami, perex, tiwai, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu



On 22/11/2021 11:46, Srinivasa Rao Mandadapu wrote:
> Add support function to get dma control and lpaif handle to avoid
> repeated code in platform driver
> 
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>

Few minor Nits, but overall it looks good to me.

Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>

> ---
>   sound/soc/qcom/lpass-platform.c | 90 ++++++++++++++++++++---------------------
>   1 file changed, 43 insertions(+), 47 deletions(-)
> 
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index a44162c..59c0884 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -177,6 +177,44 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>   	return 0;
>   }
>   
> +static void __get_lpaif_handle(struct snd_pcm_substream *substream,
> +				struct snd_soc_component *component,
> +				struct lpaif_dmactl **dmactl, int *id, struct regmap **map)
Same indentation is off here.

> +{
> +	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
> +	struct snd_pcm_runtime *rt = substream->runtime;
> +	struct lpass_pcm_data *pcm_data = rt->private_data;
> +	struct lpass_variant *v = drvdata->variant;
> +	int dir = substream->stream;
> +	unsigned int dai_id = cpu_dai->driver->id;
> +	struct lpaif_dmactl *l_dmactl;
> +	struct regmap *l_map;
> +	int l_id;
> +
> +	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> +		l_id = pcm_data->dma_ch;
> +		if (dai_id == LPASS_DP_RX) {
> +			l_dmactl = drvdata->hdmi_rd_dmactl;
> +			l_map = drvdata->hdmiif_map;
> +		} else {
> +			l_dmactl = drvdata->rd_dmactl;
> +			l_map = drvdata->lpaif_map;
> +		}
> +	} else {
> +		l_dmactl = drvdata->wr_dmactl;
> +		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
> +		l_map = drvdata->lpaif_map;
> +	}
> +	if (dmactl)
> +		*dmactl = l_dmactl;
> +	if (id)
> +		*id = l_id;
> +	if (map)
> +		*map = l_map;
> +}
> +
>   static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>   					   struct snd_pcm_substream *substream,
>   					   struct snd_pcm_hw_params *params)
> @@ -191,22 +229,12 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>   	unsigned int channels = params_channels(params);
>   	unsigned int regval;
>   	struct lpaif_dmactl *dmactl;
> -	int id, dir = substream->stream;
> +	int id;
>   	int bitwidth;
>   	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
>   	unsigned int dai_id = cpu_dai->driver->id;
>   
> -	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -		id = pcm_data->dma_ch;
> -		if (dai_id == LPASS_DP_RX)
> -			dmactl = drvdata->hdmi_rd_dmactl;
> -		else
> -			dmactl = drvdata->rd_dmactl;
> -
> -	} else {
> -		dmactl = drvdata->wr_dmactl;
> -		id = pcm_data->dma_ch - v->wrdma_channel_start;
> -	}
> +	__get_lpaif_handle(substream, component, &dmactl, &id, NULL);
error handling is missing.

>   
>   	bitwidth = snd_pcm_format_width(format);
>   	if (bitwidth < 0) {
> @@ -379,24 +407,9 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>   	int ret, id, ch, dir = substream->stream;
>   	unsigned int dai_id = cpu_dai->driver->id;
>   
> -
>   	ch = pcm_data->dma_ch;
> -	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -		if (dai_id == LPASS_DP_RX) {
> -			dmactl = drvdata->hdmi_rd_dmactl;
> -			map = drvdata->hdmiif_map;
> -		} else {
> -			dmactl = drvdata->rd_dmactl;
> -			map = drvdata->lpaif_map;
> -		}
> -
> -		id = pcm_data->dma_ch;
> -	} else {
> -		dmactl = drvdata->wr_dmactl;
> -		id = pcm_data->dma_ch - v->wrdma_channel_start;
> -		map = drvdata->lpaif_map;
> -	}
>   
> +	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
>   	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
>   				runtime->dma_addr);
>   	if (ret) {
> @@ -444,26 +457,12 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>   	struct lpaif_dmactl *dmactl;
>   	struct regmap *map;
>   	int ret, ch, id;
> -	int dir = substream->stream;
>   	unsigned int reg_irqclr = 0, val_irqclr = 0;
>   	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
>   	unsigned int dai_id = cpu_dai->driver->id;
>   
>   	ch = pcm_data->dma_ch;
> -	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
> -		id = pcm_data->dma_ch;
> -		if (dai_id == LPASS_DP_RX) {
> -			dmactl = drvdata->hdmi_rd_dmactl;
> -			map = drvdata->hdmiif_map;
> -		} else {
> -			dmactl = drvdata->rd_dmactl;
> -			map = drvdata->lpaif_map;
> -		}
> -	} else {
> -		dmactl = drvdata->wr_dmactl;
> -		id = pcm_data->dma_ch - v->wrdma_channel_start;
> -		map = drvdata->lpaif_map;
> -	}
> +	__get_lpaif_handle(substream, component, &dmactl, &id, &map);
>   
>   	switch (cmd) {
>   	case SNDRV_PCM_TRIGGER_START:
> @@ -597,10 +596,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>   	struct regmap *map;
>   	unsigned int dai_id = cpu_dai->driver->id;
>   
> -	if (dai_id == LPASS_DP_RX)
> -		map = drvdata->hdmiif_map;
> -	else
> -		map = drvdata->lpaif_map;
> +	__get_lpaif_handle(substream, component, NULL, NULL, &map);
>   
>   	ch = pcm_data->dma_ch;
>   
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 06/10] ASoC: qcom: Add support for codec dma driver
  2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  (?)
@ 2021-11-23 12:28   ` Srinivas Kandagatla
  2021-11-26 11:20     ` Srinivasa Rao Mandadapu
  -1 siblings, 1 reply; 19+ messages in thread
From: Srinivas Kandagatla @ 2021-11-23 12:28 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, bjorn.andersson, lgirdwood,
	broonie, robh+dt, plai, bgoswami, perex, tiwai, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu



On 22/11/2021 11:46, Srinivasa Rao Mandadapu wrote:
> Upadate lpass cpu and platform driver to support audio over codec dma
> in ADSP bypass use case.
> 
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> ---
>   sound/soc/qcom/common.c         |  39 ++++
>   sound/soc/qcom/common.h         |   1 +

common.c is mostly intended to be used by machine drivers, so I would 
suggest that you move it to lpass.h and make is_cdc_dma_port a static 
inlnie function.

>   sound/soc/qcom/lpass-cpu.c      |  60 +++++-
>   sound/soc/qcom/lpass-platform.c | 424 ++++++++++++++++++++++++++++++++++++++--
>   4 files changed, 508 insertions(+), 16 deletions(-)
> 
> diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
> index 09af007..26d3752 100644
> --- a/sound/soc/qcom/common.c
> +++ b/sound/soc/qcom/common.c
> @@ -4,6 +4,7 @@
>   
>   #include <linux/module.h>
>   #include "common.h"
> +#include "lpass.h"
>   
>   int qcom_snd_parse_of(struct snd_soc_card *card)
>   {
> @@ -169,4 +170,42 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
>   }
>   EXPORT_SYMBOL(qcom_snd_parse_of);
>   
> +bool is_cdc_dma_port(int dai_id)
> +{
> +	switch (dai_id) {
> +	case LPASS_CDC_DMA_RX0:
> +	case LPASS_CDC_DMA_RX1:
> +	case LPASS_CDC_DMA_RX2:
> +	case LPASS_CDC_DMA_RX3:
> +	case LPASS_CDC_DMA_RX4:
> +	case LPASS_CDC_DMA_RX5:
> +	case LPASS_CDC_DMA_RX6:
> +	case LPASS_CDC_DMA_RX7:
> +	case LPASS_CDC_DMA_RX8:
> +	case LPASS_CDC_DMA_RX9:
> +	case LPASS_CDC_DMA_TX0:
> +	case LPASS_CDC_DMA_TX1:
> +	case LPASS_CDC_DMA_TX2:
> +	case LPASS_CDC_DMA_TX3:
> +	case LPASS_CDC_DMA_TX4:
> +	case LPASS_CDC_DMA_TX5:
> +	case LPASS_CDC_DMA_TX6:
> +	case LPASS_CDC_DMA_TX7:
> +	case LPASS_CDC_DMA_TX8:
> +	case LPASS_CDC_DMA_VA_TX0:
> +	case LPASS_CDC_DMA_VA_TX1:
> +	case LPASS_CDC_DMA_VA_TX2:
> +	case LPASS_CDC_DMA_VA_TX3:
> +	case LPASS_CDC_DMA_VA_TX4:
> +	case LPASS_CDC_DMA_VA_TX5:
> +	case LPASS_CDC_DMA_VA_TX6:
> +	case LPASS_CDC_DMA_VA_TX7:
> +	case LPASS_CDC_DMA_VA_TX8:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +EXPORT_SYMBOL(is_cdc_dma_port);
> +
>   MODULE_LICENSE("GPL v2");
> diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
> index f05c05b..a8fea4c 100644
> --- a/sound/soc/qcom/common.h
> +++ b/sound/soc/qcom/common.h
> @@ -7,5 +7,6 @@
>   #include <sound/soc.h>
>   
>   int qcom_snd_parse_of(struct snd_soc_card *card);
> +bool is_cdc_dma_port(int dai_id);
>   
>   #endif
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 3bd9eb3..9e6656c 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -17,6 +17,7 @@
>   #include <sound/soc.h>
>   #include <sound/soc-dai.h>
>   #include "lpass-lpaif-reg.h"
> +#include "common.h"
>   #include "lpass.h"
>   
>   #define LPASS_CPU_MAX_MI2S_LINES	4
> @@ -857,7 +858,9 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
>   		}
>   		if (id == LPASS_DP_RX) {
>   			data->hdmi_port_enable = 1;
> -		} else {
> +		} else if (is_cdc_dma_port(id))
> +			data->codec_dma_enable = 1;
> +		else {
>   			data->mi2s_playback_sd_mode[id] =
>   				of_lpass_cpu_parse_sd_lines(dev, node,
>   							    "qcom,playback-sd-lines");
> @@ -872,6 +875,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   {
>   	struct lpass_data *drvdata;
>   	struct device_node *dsp_of_node;
> +	struct resource *res;
>   	struct lpass_variant *variant;
>   	struct device *dev = &pdev->dev;
>   	const struct of_device_id *match;
> @@ -897,6 +901,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   
>   	of_lpass_cpu_parse_dai_data(dev, drvdata);
>   
> +	drvdata->num_clks =  variant->num_clks;
> +	if (drvdata->codec_dma_enable) {
> +		drvdata->rxtx_lpaif =
> +				devm_platform_ioremap_resource_byname(pdev, "lpass-rxtx-lpaif");
> +		if (IS_ERR(drvdata->rxtx_lpaif))
> +			return PTR_ERR(drvdata->rxtx_lpaif);
> +
> +		drvdata->va_lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
> +		if (IS_ERR(drvdata->va_lpaif))
> +			return PTR_ERR(drvdata->va_lpaif);
> +
> +		lpass_rxtx_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
> +					variant->rxtx_wrdma_channels +
> +					variant->rxtx_wrdma_channel_start, LPASS_CDC_DMA_TX3);
> +
> +		drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, drvdata->rxtx_lpaif,
> +					&lpass_rxtx_regmap_config);
> +		if (IS_ERR(drvdata->rxtx_lpaif_map)) {
> +			dev_err(dev, "error initializing rxtx regmap: %ld\n",
> +				PTR_ERR(drvdata->rxtx_lpaif_map));
> +			return PTR_ERR(drvdata->rxtx_lpaif_map);
> +		}
> +		lpass_va_regmap_config.max_register = LPAIF_CDC_WRDMAPER_REG(variant,
> +					variant->va_wrdma_channels +
> +					variant->va_wrdma_channel_start, LPASS_CDC_DMA_VA_TX0);
> +
> +		drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, drvdata->va_lpaif,
> +					&lpass_va_regmap_config);
> +		if (IS_ERR(drvdata->va_lpaif_map)) {
> +			dev_err(dev, "error initializing va regmap: %ld\n",
> +				PTR_ERR(drvdata->va_lpaif_map));
there is a 100 chars limit now, so you can wrap this to a single line.

> +			return PTR_ERR(drvdata->va_lpaif_map);
> +		}
> +		drvdata->cdc_clks = devm_kcalloc(dev, variant->cdc_dma_num_clks,
> +					sizeof(*drvdata->cdc_clks), GFP_KERNEL);
> +		drvdata->cdc_num_clks =  variant->cdc_dma_num_clks;
double space after =

> +
> +		for (i = 0; i < drvdata->cdc_num_clks; i++)
> +			drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
> +
> +		ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, drvdata->cdc_clks);
> +		if (ret) {
> +			dev_err(dev, "Failed to get clocks %d\n", ret);
> +			return ret;
> +		}
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-rxtx-cdc-dma-lpm");
> +		drvdata->rxtx_cdc_dma_lpm_buf = res->start;
> +
> +		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-va-cdc-dma-lpm");
> +		drvdata->va_cdc_dma_lpm_buf = res->start;
> +	}
>   	drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, "lpass-lpaif");
>   	if (IS_ERR(drvdata->lpaif))
>   		return PTR_ERR(drvdata->lpaif);
> @@ -939,7 +995,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   
>   	for (i = 0; i < variant->num_dai; i++) {
>   		dai_id = variant->dai_driver[i].id;
> -		if (dai_id == LPASS_DP_RX)
> +		if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
>   			continue;
>   
>   		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index 59c0884..4b79908 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -14,12 +14,15 @@
>   #include <linux/regmap.h>
>   #include <sound/soc.h>
>   #include "lpass-lpaif-reg.h"
> +#include "common.h"
>   #include "lpass.h"
>   
>   #define DRV_NAME "lpass-platform"
>   
>   #define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
>   #define LPASS_PLATFORM_PERIODS		2
> +#define LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE (24 * 1024)
> +#define LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
>   
>   static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>   	.info			=	SNDRV_PCM_INFO_MMAP |
> @@ -45,6 +48,103 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>   	.fifo_size		=	0,
>   };
>   
> +static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
> +	.info			=	SNDRV_PCM_INFO_MMAP |
> +					SNDRV_PCM_INFO_MMAP_VALID |
> +					SNDRV_PCM_INFO_INTERLEAVED |
> +					SNDRV_PCM_INFO_PAUSE |
> +					SNDRV_PCM_INFO_RESUME,
> +	.formats		=	SNDRV_PCM_FMTBIT_S16 |
> +					SNDRV_PCM_FMTBIT_S24 |
> +					SNDRV_PCM_FMTBIT_S32,
> +	.rates			=	SNDRV_PCM_RATE_8000_192000,
> +	.rate_min		=	8000,
> +	.rate_max		=	192000,
> +	.channels_min		=	1,
> +	.channels_max		=	8,
> +	.buffer_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
> +	.period_bytes_max	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
> +						LPASS_PLATFORM_PERIODS,
> +	.period_bytes_min	=	LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
> +						LPASS_PLATFORM_PERIODS,
> +	.periods_min		=	LPASS_PLATFORM_PERIODS,
> +	.periods_max		=	LPASS_PLATFORM_PERIODS,
> +	.fifo_size		=	0,
> +};
> +
> +static const struct snd_pcm_hardware lpass_platform_va_hardware = {
> +	.info			=	SNDRV_PCM_INFO_MMAP |
> +					SNDRV_PCM_INFO_MMAP_VALID |
> +					SNDRV_PCM_INFO_INTERLEAVED |
> +					SNDRV_PCM_INFO_PAUSE |
> +					SNDRV_PCM_INFO_RESUME,
> +	.formats		=	SNDRV_PCM_FMTBIT_S16 |
> +					SNDRV_PCM_FMTBIT_S24 |
> +					SNDRV_PCM_FMTBIT_S32,
> +	.rates			=	SNDRV_PCM_RATE_8000_192000,
> +	.rate_min		=	8000,
> +	.rate_max		=	192000,
> +	.channels_min		=	1,
> +	.channels_max		=	8,
> +	.buffer_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE,
> +	.period_bytes_max	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
> +						LPASS_PLATFORM_PERIODS,
> +	.period_bytes_min	=	LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
> +						LPASS_PLATFORM_PERIODS,
> +	.periods_min		=	LPASS_PLATFORM_PERIODS,
> +	.periods_max		=	LPASS_PLATFORM_PERIODS,
> +	.fifo_size		=	0,
> +};
> +
> +static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
> +					 struct regmap *map)
> +{
> +	struct lpass_data *drvdata = dev_get_drvdata(dev);
> +	struct lpass_variant *v = drvdata->variant;
> +	struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
> +	int rval;
> +
> +	drvdata->rxtx_rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
> +					  GFP_KERNEL);
> +	if (drvdata->rxtx_rd_dmactl == NULL)
> +		return -ENOMEM;
> +
> +	drvdata->rxtx_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
> +					  GFP_KERNEL);
> +	if (drvdata->rxtx_wr_dmactl == NULL)
> +		return -ENOMEM;
> +
> +	rd_dmactl = drvdata->rxtx_rd_dmactl;
> +	wr_dmactl = drvdata->rxtx_wr_dmactl;

may be rewrite this to:

	rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
	if (rd_dmactl == NULL)
		return -ENOMEM;

	wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
	if (wr_dmactl == NULL)
		return -ENOMEM;

	drvdata->rxtx_rd_dmactl = rd_dmactl;
	drvdata->rxtx_wr_dmactl = wr_dmactl;


> +
> +	rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
> +					    &v->rxtx_rdma_intf, 15);

can we define this magic number 15 properly?
> +	if (rval)
> +		return rval;
> +
> +	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
> +					    &v->rxtx_wrdma_intf, 15);
> +}
> +
> +static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
> +					 struct regmap *map)
> +{
> +	struct lpass_data *drvdata = dev_get_drvdata(dev);
> +	struct lpass_variant *v = drvdata->variant;
> +	struct lpaif_dmactl *wr_dmactl;
> +
> +	drvdata->va_wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
> +					  GFP_KERNEL);
> +	if (drvdata->va_wr_dmactl == NULL)
> +		return -ENOMEM;
> +
> +	wr_dmactl = drvdata->va_wr_dmactl;
simillar comment.

> +
> +	return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
> +					    &v->va_wrdma_intf, 15);
> +}
> +
> +
>   static int lpass_platform_alloc_dmactl_fields(struct device *dev,
>   					 struct regmap *map)
>   {
> @@ -126,22 +226,43 @@ static int lpass_platform_pcmops_open(struct snd_soc_component *component,
>   	if (cpu_dai->driver->id == LPASS_DP_RX) {
>   		map = drvdata->hdmiif_map;
>   		drvdata->hdmi_substream[dma_ch] = substream;
> +	} else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3) {
> +		map = drvdata->rxtx_lpaif_map;
> +		drvdata->rxtx_substream[dma_ch] = substream;
> +	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
> +		map = drvdata->va_lpaif_map;
> +		drvdata->va_substream[dma_ch] = substream;
>   	} else {
>   		map = drvdata->lpaif_map;
>   		drvdata->substream[dma_ch] = substream;
>   	}
>   	data->dma_ch = dma_ch;
> -	ret = regmap_write(map,
> -			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
> -	if (ret) {
> -		dev_err(soc_runtime->dev,
> -			"error writing to rdmactl reg: %d\n", ret);
> -		return ret;
> +	if (!(dai_id == LPASS_CDC_DMA_RX0 ||
> +		dai_id == LPASS_CDC_DMA_TX3 ||
> +		dai_id == LPASS_CDC_DMA_VA_TX0)) {
> +		ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
> +		if (ret) {
> +			dev_err(soc_runtime->dev,
> +				"error writing to rdmactl reg: %d\n", ret);
> +			return ret;
> +		}
>   	}
> -	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
> -
> -	runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
>   
> +	switch (dai_id) {
> +	case LPASS_CDC_DMA_RX0:
> +	case LPASS_CDC_DMA_TX3:
> +		snd_soc_set_runtime_hwparams(substream, &lpass_platform_rxtx_hardware);
> +		runtime->dma_bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +		break;
> +	case LPASS_CDC_DMA_VA_TX0:
> +		snd_soc_set_runtime_hwparams(substream, &lpass_platform_va_hardware);
> +		runtime->dma_bytes = lpass_platform_va_hardware.buffer_bytes_max;
> +		break;
> +	default:
> +		snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
> +		runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
> +		break;
> +	}
>   	ret = snd_pcm_hw_constraint_integer(runtime,
>   			SNDRV_PCM_HW_PARAM_PERIODS);
>   	if (ret < 0) {
> @@ -168,6 +289,10 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>   	data = runtime->private_data;
>   	if (dai_id == LPASS_DP_RX)
>   		drvdata->hdmi_substream[data->dma_ch] = NULL;
> +	else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == LPASS_CDC_DMA_TX3)
> +		drvdata->rxtx_substream[data->dma_ch] = NULL;
> +	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
> +		drvdata->va_substream[data->dma_ch] = NULL;
>   	else
>   		drvdata->substream[data->dma_ch] = NULL;
>   	if (v->free_dma_channel)
> @@ -198,14 +323,27 @@ static void __get_lpaif_handle(struct snd_pcm_substream *substream,
>   		if (dai_id == LPASS_DP_RX) {
>   			l_dmactl = drvdata->hdmi_rd_dmactl;
>   			l_map = drvdata->hdmiif_map;
> +		} else if (dai_id == LPASS_CDC_DMA_RX0) {
> +			l_map = drvdata->rxtx_lpaif_map;
> +			l_dmactl = drvdata->rxtx_rd_dmactl;
>   		} else {
>   			l_dmactl = drvdata->rd_dmactl;
>   			l_map = drvdata->lpaif_map;
>   		}
>   	} else {
> -		l_dmactl = drvdata->wr_dmactl;
> -		l_id = pcm_data->dma_ch - v->wrdma_channel_start;
> -		l_map = drvdata->lpaif_map;
> +		if (dai_id == LPASS_CDC_DMA_TX3) {
> +			l_dmactl = drvdata->rxtx_wr_dmactl;
> +			l_map = drvdata->rxtx_lpaif_map;
> +			l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
> +		} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
> +			l_dmactl = drvdata->va_wr_dmactl;
> +			l_map = drvdata->va_lpaif_map;
> +			l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
> +		} else {
> +			l_dmactl = drvdata->wr_dmactl;
> +			l_id = pcm_data->dma_ch - v->wrdma_channel_start;
> +			l_map = drvdata->lpaif_map;
> +		}
>   	}
>   	if (dmactl)
>   		*dmactl = l_dmactl;
> @@ -256,6 +394,10 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>   	}
>   
>   	switch (dai_id) {
> +	case LPASS_CDC_DMA_RX0:
> +	case LPASS_CDC_DMA_TX3:
> +	case LPASS_CDC_DMA_VA_TX0:

Is there a reason why we can not add support to other CDC_DMA dais as 
part of this patchset?

> +		break;
>   	case LPASS_DP_RX:
>   		ret = regmap_fields_write(dmactl->burst8, id,
>   							LPAIF_DMACTL_BURSTEN_INCR4);
> @@ -380,6 +522,10 @@ static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
>   
>   	if (dai_id == LPASS_DP_RX)
>   		map = drvdata->hdmiif_map;
> +	else if (dai_id == LPASS_CDC_DMA_RX0 ||
> +		dai_id == LPASS_CDC_DMA_TX3 ||
> +		dai_id == LPASS_CDC_DMA_VA_TX0)
> +		return 0;
>   	else
>   		map = drvdata->lpaif_map;
>   
> @@ -434,6 +580,16 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>   		return ret;
>   	}
>   
> +	if (dai_id == LPASS_CDC_DMA_RX0 ||
> +		dai_id == LPASS_CDC_DMA_TX3 ||
> +		dai_id == LPASS_CDC_DMA_VA_TX0) {
> +		ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
> +		if (ret) {
> +			dev_err(soc_runtime->dev, "error writing fifowm field to dmactl reg: %d, id: %d\n",
> +				ret, id);
> +			return ret;
> +		}
> +	}
>   	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
>   	if (ret) {
>   		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
> @@ -476,6 +632,22 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>   			return ret;
>   		}
>   		switch (dai_id) {
> +		case LPASS_CDC_DMA_RX0:
> +		case LPASS_CDC_DMA_TX3:
> +		case LPASS_CDC_DMA_VA_TX0:
> +			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_ON);
> +			if (ret) {
> +				dev_err(soc_runtime->dev,
> +					"error writing to rdmactl reg field: %d\n", ret);
> +				return ret;
> +			}
> +			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
> +			val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
> +			val_mask = LPAIF_IRQ_ALL(ch);
> +			val_irqen = LPAIF_IRQ_ALL(ch);
> +			break;
>   		case LPASS_DP_RX:
>   			ret = regmap_fields_write(dmactl->dyncclk, id,
>   					 LPAIF_DMACTL_DYNCLK_ON);
> @@ -540,6 +712,24 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
>   			return ret;
>   		}
>   		switch (dai_id) {
> +		case LPASS_CDC_DMA_RX0:
> +		case LPASS_CDC_DMA_TX3:
> +		case LPASS_CDC_DMA_VA_TX0:
> +			ret = regmap_fields_write(dmactl->dyncclk, id, LPAIF_DMACTL_DYNCLK_OFF);
> +			if (ret) {
> +				dev_err(soc_runtime->dev,
> +					"error writing to rdmactl reg field: %d\n", ret);
> +				return ret;
> +			}
> +
> +			reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
> +			val_irqclr = LPAIF_IRQ_ALL(ch);
> +
> +			reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
> +			val_mask = LPAIF_IRQ_ALL(ch);
> +			val_irqen = LPAIF_IRQ_ALL(ch);
> +
> +		break;
>   		case LPASS_DP_RX:
>   			ret = regmap_fields_write(dmactl->dyncclk, id,
>   					 LPAIF_DMACTL_DYNCLK_OFF);
> @@ -619,6 +809,38 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
>   	return bytes_to_frames(substream->runtime, curr_addr - base_addr);
>   }
>   
> +static int lpass_platform_cdc_dma_mmap(struct snd_soc_component *component,
> +			struct snd_pcm_substream *substream,
> +			struct vm_area_struct *vma)
> +{
> +	struct snd_pcm_runtime *runtime = substream->runtime;
> +	unsigned long size, offset;
> +
> +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> +	size = vma->vm_end - vma->vm_start;
> +	offset = vma->vm_pgoff << PAGE_SHIFT;
> +	return io_remap_pfn_range(vma, vma->vm_start,
> +			(runtime->dma_addr + offset) >> PAGE_SHIFT,
> +			size, vma->vm_page_prot);
> +
> +}
> +
> +static int lpass_platform_pcmops_mmap(struct snd_soc_component *component,
> +				      struct snd_pcm_substream *substream,
> +				      struct vm_area_struct *vma)
> +{
> +	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
> +	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +	unsigned int dai_id = cpu_dai->driver->id;
> +
> +	if (dai_id == LPASS_CDC_DMA_RX0 ||
> +		dai_id == LPASS_CDC_DMA_TX3 ||
> +		dai_id == LPASS_CDC_DMA_VA_TX0) {
> +		return lpass_platform_cdc_dma_mmap(component, substream, vma);
> +	}
> +	return 0;
> +}
> +
>   static irqreturn_t lpass_dma_interrupt_handler(
>   			struct snd_pcm_substream *substream,
>   			struct lpass_data *drvdata,
> @@ -635,6 +857,14 @@ static irqreturn_t lpass_dma_interrupt_handler(
>   
>   	mask = LPAIF_IRQ_ALL(chan);
>   	switch (dai_id) {
> +	case LPASS_CDC_DMA_RX0:
> +	case LPASS_CDC_DMA_TX3:
> +	case LPASS_CDC_DMA_VA_TX0:
> +		map = (dai_id == LPASS_CDC_DMA_VA_TX0) ?
> +				drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
> +		reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
> +		val = 0;
> +		break;
>   	case LPASS_DP_RX:
>   		map = drvdata->hdmiif_map;
>   		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
> @@ -758,18 +988,112 @@ static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
>   				return rv;
>   		}
>   	}
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
> +{
> +	struct lpass_data *drvdata = data;
> +	struct lpass_variant *v = drvdata->variant;
> +	unsigned int irqs;
> +	int rv, chan;
> +
> +	rv = regmap_read(drvdata->rxtx_lpaif_map,
> +			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_RX0), &irqs);
> +	if (rv)
> +		return IRQ_NONE;
> +	/* Handle per channel interrupts */
> +	for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
> +		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->rxtx_substream[chan]) {
> +			rv = lpass_dma_interrupt_handler(
> +						drvdata->rxtx_substream[chan],
> +						drvdata, chan, irqs);
> +			if (rv != IRQ_HANDLED)
> +				return rv;
> +		}
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
> +{
> +	struct lpass_data *drvdata = data;
> +	struct lpass_variant *v = drvdata->variant;
> +	unsigned int irqs;
> +	int rv, chan;
>   
> +	rv = regmap_read(drvdata->va_lpaif_map,
> +			LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST,
> +			LPASS_CDC_DMA_VA_TX0), &irqs);
> +	if (rv)
> +		return IRQ_NONE;
> +	/* Handle per channel interrupts */
> +	for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
> +		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->va_substream[chan]) {
> +			rv = lpass_dma_interrupt_handler(
> +						drvdata->va_substream[chan],
> +						drvdata, chan, irqs);
> +			if (rv != IRQ_HANDLED)
> +				return rv;
> +		}
> +	}
>   	return IRQ_HANDLED;
>   }
>   
> +static int lpass_platform_prealloc_cdc_dma_buffer(struct snd_soc_component *component,
> +			struct snd_pcm *pcm, int dai_id)
> +{
> +	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
> +	struct snd_pcm_substream *substream;
> +	struct snd_dma_buffer *buf;
> +	int ret;
> +
> +	if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
> +		substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
> +	else
> +		substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
> +
> +	ret = dma_coerce_mask_and_coherent(pcm->card->dev, DMA_BIT_MASK(64));
> +	if (ret)
> +		return ret;
> +
> +	buf = &substream->dma_buffer;
> +	buf->dev.dev = pcm->card->dev;
> +	buf->private_data = NULL;
> +
> +	/* Assign Codec DMA buffer pointers */
> +	buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
> +	if (dai_id == LPASS_CDC_DMA_RX0) {
> +		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
> +	} else if (dai_id == LPASS_CDC_DMA_TX3) {
> +		buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
> +		buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
> +	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
> +		buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
> +		buf->addr = drvdata->va_cdc_dma_lpm_buf;
> +	}
> +
> +	buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes);
> +
> +	return 0;
> +}
> +
>   static int lpass_platform_pcm_new(struct snd_soc_component *component,
>   				  struct snd_soc_pcm_runtime *soc_runtime)
>   {
>   	struct snd_pcm *pcm = soc_runtime->pcm;
> +	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
> +	unsigned int dai_id = cpu_dai->driver->id;
> +
>   	size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
>   
> -	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
> -					    component->dev, size);
> +	if (is_cdc_dma_port(dai_id))
> +		return lpass_platform_prealloc_cdc_dma_buffer(component, pcm, dai_id);
May be a comment here would be nice for reader to understand why we 
allocate this buffer.

> +	else
> +		return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
> +						component->dev, size);
>   }
>   
>   static int lpass_platform_pcmops_suspend(struct snd_soc_component *component)
> @@ -804,6 +1128,22 @@ static int lpass_platform_pcmops_resume(struct snd_soc_component *component)
>   	return regcache_sync(map);
>   }
>   
> +int lpass_platform_copy(struct snd_soc_component *component,
> +			 struct snd_pcm_substream *substream, int channel,
> +			 unsigned long pos, void __user *buf, unsigned long bytes)
> +{
> +	struct snd_pcm_runtime *rt = substream->runtime;
> +
> +	unsigned char *dma_buf = rt->dma_area + pos +
> +				channel * (rt->dma_bytes / rt->channels);
> +
> +	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> +		return copy_from_user_toio(dma_buf, buf, bytes);
> +	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
> +		return copy_to_user_fromio(buf, dma_buf, bytes);
> +
> +	return 0;
> +}
>   
>   static const struct snd_soc_component_driver lpass_component_driver = {
>   	.name		= DRV_NAME,
> @@ -814,9 +1154,11 @@ static const struct snd_soc_component_driver lpass_component_driver = {
>   	.prepare	= lpass_platform_pcmops_prepare,
>   	.trigger	= lpass_platform_pcmops_trigger,
>   	.pointer	= lpass_platform_pcmops_pointer,
> +	.mmap		= lpass_platform_pcmops_mmap,

isn't this just snd_pcm_lib_mmap_iomem for cdc dma.

>   	.pcm_construct	= lpass_platform_pcm_new,
>   	.suspend		= lpass_platform_pcmops_suspend,
>   	.resume			= lpass_platform_pcmops_resume,
> +	.copy_user		= lpass_platform_copy,

Why do we need this for other non cdc dma dais?


Am thinking that we shoudl have a seperate instance of this for dais 
that can only do dma with hardware buffers.

>   
>   };
>   
> @@ -854,6 +1196,60 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>   		return ret;
>   	}
>   
> +	if (drvdata->codec_dma_enable) {
> +		ret = regmap_write(drvdata->rxtx_lpaif_map,
> +			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_TX3), 0x0);
> +		if (ret) {
> +			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> +			return ret;
> +		}
> +		ret = regmap_write(drvdata->va_lpaif_map,
> +			LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, LPASS_CDC_DMA_VA_TX0), 0x0);
> +		if (ret) {
> +			dev_err(&pdev->dev, "error writing to rxtx irqen reg: %d\n", ret);
> +			return ret;
> +		}
> +		drvdata->rxtxif_irq = platform_get_irq_byname(pdev, "lpass-irq-rxtxif");
> +		if (drvdata->rxtxif_irq < 0)
> +			return -ENODEV;
> +
> +		ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
> +				lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
> +				"lpass-irq-rxtxif", drvdata);
> +		if (ret) {
> +			dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
> +			return ret;
> +		}
> +
> +		ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
> +						 drvdata->rxtx_lpaif_map);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"error initializing rxtx dmactl fields: %d\n", ret);
> +			return ret;
> +		}
> +
> +		drvdata->vaif_irq = platform_get_irq_byname(pdev, "lpass-irq-vaif");
> +		if (drvdata->vaif_irq < 0)
> +			return -ENODEV;
> +
> +		ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
> +				lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
> +				"lpass-irq-vaif", drvdata);
> +		if (ret) {
> +			dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
> +			return ret;
> +		}
> +
> +		ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
> +						 drvdata->va_lpaif_map);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"error initializing va dmactl fields: %d\n", ret);
> +			return ret;
> +		}
> +	}
> +
>   	if (drvdata->hdmi_port_enable) {
>   		drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
>   		if (drvdata->hdmiif_irq < 0)
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings
  2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  (?)
@ 2021-11-23 12:28   ` Srinivas Kandagatla
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivas Kandagatla @ 2021-11-23 12:28 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, bjorn.andersson, lgirdwood,
	broonie, robh+dt, plai, bgoswami, perex, tiwai, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu



On 22/11/2021 11:46, Srinivasa Rao Mandadapu wrote:
> Add bindings for lpass sc7280 based soundcards which supports
> audio over i2s based speaker, soundwire based headset, msm dmics
> and HDMI Port.
> 


Subject line is totally missleading,

This is not a soundcard bindings but its lpass cpu bindings.

--srini
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> ---
>   .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 69 +++++++++++++++++++---
>   1 file changed, 61 insertions(+), 8 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
> index 1e23c0e..0f5a57c 100644
> --- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
> +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
> @@ -22,35 +22,36 @@ properties:
>         - qcom,lpass-cpu
>         - qcom,apq8016-lpass-cpu
>         - qcom,sc7180-lpass-cpu
> +      - qcom,sc7280-lpass-cpu
>   
>     reg:
> -    maxItems: 2
> +    maxItems: 5
>       description: LPAIF core registers
>   
>     reg-names:
> -    maxItems: 2
> +    maxItems: 5
>   
>     clocks:
>       minItems: 3
> -    maxItems: 6
> +    maxItems: 7
>   
>     clock-names:
>       minItems: 3
> -    maxItems: 6
> +    maxItems: 7
>   
>     interrupts:
> -    maxItems: 2
> +    maxItems: 4
>       description: LPAIF DMA buffer interrupt
>   
>     interrupt-names:
> -    maxItems: 2
> +    maxItems: 4
>   
>     qcom,adsp:
>       $ref: /schemas/types.yaml#/definitions/phandle
>       description: Phandle for the audio DSP node
>   
>     iommus:
> -    maxItems: 2
> +    maxItems: 3
>       description: Phandle to apps_smmu node with sid mask
>   
>     power-domains:
> @@ -69,7 +70,7 @@ patternProperties:
>     "^dai-link@[0-9a-f]$":
>       type: object
>       description: |
> -      LPASS CPU dai node for each I2S device. Bindings of each node
> +      LPASS CPU dai node for each I2S device or Soundwire device. Bindings of each node
>         depends on the specific driver providing the functionality and
>         properties.
>       properties:
> @@ -174,6 +175,58 @@ allOf:
>           - iommus
>           - power-domains
>   
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            const: qcom,sc7280-lpass-cpu
> +
> +    then:
> +      properties:
> +        clock-names:
> +          oneOf:
> +            - items:   #for I2S
> +                - const: lpass_aon_cc_audio_hm_h_clk
> +                - const: lpass_core_cc_sysnoc_mport_core_clk
> +                - const: lpass_core_cc_ext_if1_ibit_clk
> +            - items:   #for Soundwire
> +                - const: lpass_aon_cc_audio_hm_h_clk
> +                - const: lpass_audio_cc_codec_mem0_clk
> +                - const: lpass_audio_cc_codec_mem1_clk
> +                - const: lpass_audio_cc_codec_mem2_clk
> +            - items:   #for HDMI
> +                - const: lpass_aon_cc_audio_hm_h_clk
> +
> +        reg-names:
> +          anyOf:
> +            - items:   #for I2S
> +                - const: lpass-lpaif
> +            - items:   #for I2S and HDMI
> +                - const: lpass-hdmiif
> +                - const: lpass-lpaif
> +            - items:   #for I2S, soundwire and HDMI
> +                - const: lpass-cdc-lpm
> +                - const: lpass-rxtx-lpaif
> +                - const: lpass-va-lpaif
> +                - const: lpass-hdmiif
> +                - const: lpass-lpaif
> +        interrupt-names:
> +          anyOf:
> +            - items:   #for I2S
> +                - const: lpass-irq-lpaif
> +            - items:   #for I2S and HDMI
> +                - const: lpass-irq-lpaif
> +                - const: lpass-irq-hdmi
> +            - items:   #for I2S, soundwire and HDMI
> +                - const: lpass-irq-lpaif
> +                - const: lpass-irq-vaif
> +                - const: lpass-irq-rxtxif
> +                - const: lpass-irq-hdmi
> +
> +      required:
> +        - iommus
> +        - power-domains
> +
>   examples:
>     - |
>       #include <dt-bindings/sound/sc7180-lpass.h>
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 09/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio
  2021-11-22 11:46   ` Srinivasa Rao Mandadapu
  (?)
@ 2021-11-23 12:28   ` Srinivas Kandagatla
  -1 siblings, 0 replies; 19+ messages in thread
From: Srinivas Kandagatla @ 2021-11-23 12:28 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu, agross, bjorn.andersson, lgirdwood,
	broonie, robh+dt, plai, bgoswami, perex, tiwai, rohitkr,
	linux-arm-msm, alsa-devel, devicetree, linux-kernel, swboyd,
	judyhsiao
  Cc: Venkata Prasad Potturu



On 22/11/2021 11:46, Srinivasa Rao Mandadapu wrote:
> Add platform driver for configuring sc7280 lpass core I2S and
> DMA configuration to support playback & capture to external codecs
> connected over secondary MI2S interface and soundwire interface.
> 
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> ---
>   sound/soc/qcom/lpass-sc7280.c | 416 ++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 416 insertions(+)
>   create mode 100644 sound/soc/qcom/lpass-sc7280.c
> 
> diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c
> new file mode 100644
> index 0000000..20ad3ee
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-sc7280.c
> @@ -0,0 +1,416 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
> + *
> + * lpass-sc7180.c -- ALSA SoC platform-machine driver for QTi LPASS
> + */
> +
> +#include <linux/module.h>
> +#include <sound/pcm.h>
> +#include <sound/soc.h>
> +#include <linux/pm_domain.h>

?? do you really use this

> +#include <linux/pm_runtime.h>
> +
> +#include <dt-bindings/sound/sc7180-lpass.h>
> +
> +#include "lpass-lpaif-reg.h"
> +#include "lpass.h"
> +
> +static struct snd_soc_dai_driver sc7280_lpass_cpu_dai_driver[] = {
> +	{
> +		.id = LPASS_CDC_DMA_RX0,
> +		.name = "CDC DMA RX",
> +		.playback = {
> +			.stream_name = "WCD Playback",
> +			.formats		= SNDRV_PCM_FMTBIT_S16,

indentation is changing for every field, can we be consistent.

> +			.rates = SNDRV_PCM_RATE_48000,
> +			.rate_min		= 48000,
> +			.rate_max		= 48000,
> +			.channels_min	= 2,
> +			.channels_max	= 2,
> +		},
> +		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
> +	},
> +	{
> +		.id = LPASS_CDC_DMA_TX3,
> +		.name = "CDC DMA TX",
> +		.capture = {
> +			.stream_name = "WCD Capture",
> +			.formats = SNDRV_PCM_FMTBIT_S16,
> +			.rates = SNDRV_PCM_RATE_48000,
> +			.rate_min		= 48000,
> +			.rate_max		= 48000,
> +			.channels_min	= 1,
> +			.channels_max	= 2,
> +		},
> +		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
> +	},
> +
> +	{
> +		.id = MI2S_SECONDARY,
> +		.name = "Secondary MI2S",
> +		.playback = {
> +			.stream_name = "Secondary MI2S Playback",
> +			.formats		= SNDRV_PCM_FMTBIT_S16,
> +			.rates = SNDRV_PCM_RATE_48000,
> +			.rate_min		= 48000,
> +			.rate_max		= 48000,
> +			.channels_min	= 2,
> +			.channels_max	= 2,
> +		},
> +		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
> +		.ops	= &asoc_qcom_lpass_cpu_dai_ops,
> +	},
> +	{
> +		.id = LPASS_DP_RX,
> +		.name = "Hdmi",
> +		.playback = {
> +			.stream_name = "DP Playback",
> +			.formats		= SNDRV_PCM_FMTBIT_S24,
> +			.rates = SNDRV_PCM_RATE_48000,
> +			.rate_min		= 48000,
> +			.rate_max		= 48000,
> +			.channels_min	= 2,
> +			.channels_max	= 2,
> +		},
> +		.ops	= &asoc_qcom_lpass_hdmi_dai_ops,
> +	},
> +	{
> +		.id = LPASS_CDC_DMA_VA_TX0,
> +		.name = "CDC DMA VA",
> +		.capture = {
> +			.stream_name = "DMIC Capture",
> +			.formats = SNDRV_PCM_FMTBIT_S16,
> +			.rates = SNDRV_PCM_RATE_48000,
> +			.rate_min	= 48000,
> +			.rate_max	= 48000,
> +			.channels_min	= 2,
> +			.channels_max	= 4,
> +		},
> +		.ops	= &asoc_qcom_lpass_wcd_dai_ops,
> +	},
> +};
> +
> +static int sc7280_lpass_alloc_dma_channel(struct lpass_data *drvdata,
> +				int direction, unsigned int dai_id)

Same indentation issue.
> +{
> +	struct lpass_variant *v = drvdata->variant;
> +	int chan = 0;
> +
> +	if (dai_id == LPASS_CDC_DMA_RX0 ||
> +	dai_id == LPASS_CDC_DMA_TX3) {

this looks very badly indented..

> +		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
> +			chan = find_first_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
> +									v->rxtx_rdma_channels);
> +
> +			if (chan >= v->rxtx_rdma_channels)
> +				return -EBUSY;
> +		} else {
> +			chan = find_next_zero_bit(&drvdata->rxtx_dma_ch_bit_map,
> +							v->rxtx_wrdma_channel_start +
> +							v->rxtx_wrdma_channels,
> +							v->rxtx_wrdma_channel_start);
> +
> +			if (chan >=	 v->rxtx_wrdma_channel_start + v->rxtx_wrdma_channels)
multiple spaces after >=

> +				return -EBUSY;
> +		}
> +
> +		set_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
> +	} else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
> +		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
> +			chan = find_first_zero_bit(&drvdata->va_dma_ch_bit_map,
> +									v->va_rdma_channels);
> +
> +			if (chan >= v->va_rdma_channels)
> +				return -EBUSY;
> +		} else {
> +			chan = find_next_zero_bit(&drvdata->va_dma_ch_bit_map,
> +							v->va_wrdma_channel_start +
> +							v->va_wrdma_channels,
> +							v->va_wrdma_channel_start);
> +
> +			if (chan >=	 v->va_wrdma_channel_start + v->va_wrdma_channels)
> +				return -EBUSY;
> +		}
> +
> +		set_bit(chan, &drvdata->va_dma_ch_bit_map);
> +	} else if (dai_id == LPASS_DP_RX) {
> +		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
> +			chan = find_first_zero_bit(&drvdata->hdmi_dma_ch_bit_map,
> +									v->hdmi_rdma_channels);
> +
> +			if (chan >= v->hdmi_rdma_channels)
> +				return -EBUSY;
> +		}
> +		set_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
> +	} else {
> +		if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
> +			chan = find_first_zero_bit(&drvdata->dma_ch_bit_map,
> +									v->rdma_channels);
> +
> +			if (chan >= v->rdma_channels)
> +				return -EBUSY;
> +		} else {
> +			chan = find_next_zero_bit(&drvdata->dma_ch_bit_map,
> +							v->wrdma_channel_start +
> +							v->wrdma_channels,
> +							v->wrdma_channel_start);
> +
> +			if (chan >=	 v->wrdma_channel_start + v->wrdma_channels)
> +				return -EBUSY;
> +		}
> +		set_bit(chan, &drvdata->dma_ch_bit_map);
> +	}
> +	return chan;
> +}
> +
> +static int sc7280_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
> +{
> +	if (dai_id == LPASS_CDC_DMA_RX0 ||
> +		dai_id == LPASS_CDC_DMA_TX3)
> +		clear_bit(chan, &drvdata->rxtx_dma_ch_bit_map);
> +	else if (dai_id == LPASS_CDC_DMA_VA_TX0)
> +		clear_bit(chan, &drvdata->va_dma_ch_bit_map);
> +	else if (dai_id == LPASS_DP_RX)
> +		clear_bit(chan, &drvdata->hdmi_dma_ch_bit_map);
> +	else
> +		clear_bit(chan, &drvdata->dma_ch_bit_map);

better move this to a switch case.

> +
> +	return 0;
> +}
> +
> +static int sc7280_lpass_init(struct platform_device *pdev)
> +{
> +	struct lpass_data *drvdata = platform_get_drvdata(pdev);
> +	struct lpass_variant *variant = drvdata->variant;
> +	struct device *dev = &pdev->dev;
> +
> +	drvdata->clks = devm_kcalloc(dev, variant->num_clks,
> +					sizeof(*drvdata->clks), GFP_KERNEL);

No check on return value ?

> +	drvdata->num_clks = variant->num_clks;
> +
> +	drvdata->aon_cc_audio_hm_h = devm_clk_get(dev, "lpass_aon_cc_audio_hm_h_clk");
> +	if (IS_ERR(drvdata->aon_cc_audio_hm_h))
> +		return PTR_ERR(drvdata->aon_cc_audio_hm_h);
> +	drvdata->core_cc_sysnoc_mport_core = devm_clk_get(dev,
> +					"lpass_core_cc_sysnoc_mport_core_clk");
> +	if (IS_ERR(drvdata->core_cc_sysnoc_mport_core))
> +		return PTR_ERR(drvdata->core_cc_sysnoc_mport_core);
> +
> +	clk_prepare_enable(drvdata->aon_cc_audio_hm_h);
> +	clk_prepare_enable(drvdata->core_cc_sysnoc_mport_core);
> +	return 0;
> +}
> +
> +static int sc7280_lpass_exit(struct platform_device *pdev)
> +{
> +	struct lpass_data *drvdata = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(drvdata->core_cc_sysnoc_mport_core);
> +	clk_disable_unprepare(drvdata->aon_cc_audio_hm_h);
> +
> +	return 0;
> +}
> +
> +static struct lpass_variant sc7280_data = {
> +	.i2sctrl_reg_base		= 0x1000,
> +	.i2sctrl_reg_stride		= 0x1000,
> +	.i2s_ports			= 3,
> +	.irq_reg_base			= 0x9000,
> +	.irq_reg_stride			= 0x1000,
> +	.irq_ports			= 3,
> +	.rdma_reg_base			= 0xC000,
> +	.rdma_reg_stride		= 0x1000,
> +	.rdma_channels			= 5,
> +	.rxtx_rdma_reg_base		= 0xC000,
> +	.rxtx_rdma_reg_stride		= 0x1000,
> +	.rxtx_rdma_channels		= 8,
> +	.hdmi_rdma_reg_base		= 0x64000,
> +	.hdmi_rdma_reg_stride		= 0x1000,
> +	.hdmi_rdma_channels		= 4,
> +	.dmactl_audif_start		= 1,
> +	.wrdma_reg_base			= 0x18000,
> +	.wrdma_reg_stride		= 0x1000,
> +	.wrdma_channel_start		= 5,
> +	.wrdma_channels			= 4,
> +	.rxtx_irq_reg_base		= 0x9000,
> +	.rxtx_irq_reg_stride		= 0x1000,
> +	.rxtx_irq_ports			= 3,
> +	.rxtx_wrdma_reg_base		= 0x18000,
> +	.rxtx_wrdma_reg_stride		= 0x1000,
> +	.rxtx_wrdma_channel_start	= 5,
> +	.rxtx_wrdma_channels		= 6,
> +	.va_wrdma_reg_base		= 0x18000,
> +	.va_wrdma_reg_stride		= 0x1000,
> +	.va_wrdma_channel_start		= 5,
> +	.va_wrdma_channels		= 3,
> +	.va_irq_reg_base		= 0x9000,
> +	.va_irq_reg_stride		= 0x1000,
> +	.va_irq_ports			= 3,
> +
> +	.loopback			= REG_FIELD_ID(0x1000, 17, 17, 3, 0x1000),
> +	.spken				= REG_FIELD_ID(0x1000, 16, 16, 3, 0x1000),
> +	.spkmode			= REG_FIELD_ID(0x1000, 11, 15, 3, 0x1000),
> +	.spkmono			= REG_FIELD_ID(0x1000, 10, 10, 3, 0x1000),
> +	.micen				= REG_FIELD_ID(0x1000, 9, 9, 3, 0x1000),
> +	.micmode			= REG_FIELD_ID(0x1000, 4, 8, 3, 0x1000),
> +	.micmono			= REG_FIELD_ID(0x1000, 3, 3, 3, 0x1000),
> +	.wssrc				= REG_FIELD_ID(0x1000, 2, 2, 3, 0x1000),
> +	.bitwidth			= REG_FIELD_ID(0x1000, 0, 1, 3, 0x1000),
> +
> +	.rdma_dyncclk			= REG_FIELD_ID(0xC000, 21, 21, 5, 0x1000),
> +	.rdma_bursten			= REG_FIELD_ID(0xC000, 20, 20, 5, 0x1000),
> +	.rdma_wpscnt			= REG_FIELD_ID(0xC000, 16, 19, 5, 0x1000),
> +	.rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 5, 0x1000),
> +	.rdma_fifowm			= REG_FIELD_ID(0xC000, 1, 5, 5, 0x1000),
> +	.rdma_enable			= REG_FIELD_ID(0xC000, 0, 0, 5, 0x1000),
> +
> +	.rxtx_rdma_enable		= REG_FIELD_ID(0xC000, 0, 0, 7, 0x1000),
> +	.rxtx_rdma_fifowm		= REG_FIELD_ID(0xC000, 1, 11, 7, 0x1000),
> +	.rxtx_rdma_intf			= REG_FIELD_ID(0xC000, 12, 15, 7, 0x1000),
> +	.rxtx_rdma_wpscnt		= REG_FIELD_ID(0xC000, 16, 19, 7, 0x1000),
> +	.rxtx_rdma_bursten		= REG_FIELD_ID(0xC000, 20, 20, 7, 0x1000),
> +	.rxtx_rdma_dyncclk		= REG_FIELD_ID(0xC000, 21, 21, 7, 0x1000),
> +
> +	.rxtx_rdma_codec_ch		= REG_FIELD_ID(0xC050, 0, 7, 7, 0x1000),
> +	.rxtx_rdma_codec_intf		= REG_FIELD_ID(0xC050, 16, 19, 7, 0x1000),
> +	.rxtx_rdma_codec_fs_delay	= REG_FIELD_ID(0xC050, 21, 24, 7, 0x1000),
> +	.rxtx_rdma_codec_fs_sel		= REG_FIELD_ID(0xC050, 25, 27, 7, 0x1000),
> +	.rxtx_rdma_codec_pack		= REG_FIELD_ID(0xC050, 29, 29, 5, 0x1000),
> +	.rxtx_rdma_codec_enable		= REG_FIELD_ID(0xC050, 30, 30, 7, 0x1000),
> +
> +	.rxtx_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
> +	.rxtx_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
> +	.rxtx_wrdma_intf		= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
> +	.rxtx_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
> +	.rxtx_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
> +	.rxtx_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
> +
> +	.rxtx_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
> +	.rxtx_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
> +	.rxtx_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
> +	.rxtx_wrdma_codec_fs_sel	= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
> +	.rxtx_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
> +	.rxtx_wrdma_codec_enable	= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
> +
> +	.va_wrdma_enable		= REG_FIELD_ID(0x18000, 0, 0, 5, 0x1000),
> +	.va_wrdma_fifowm		= REG_FIELD_ID(0x18000, 1, 11, 5, 0x1000),
> +	.va_wrdma_intf			= REG_FIELD_ID(0x18000, 12, 16, 5, 0x1000),
> +	.va_wrdma_wpscnt		= REG_FIELD_ID(0x18000, 17, 20, 5, 0x1000),
> +	.va_wrdma_bursten		= REG_FIELD_ID(0x18000, 21, 21, 5, 0x1000),
> +	.va_wrdma_dyncclk		= REG_FIELD_ID(0x18000, 22, 22, 5, 0x1000),
> +
> +	.va_wrdma_codec_ch		= REG_FIELD_ID(0x18050, 0, 7, 5, 0x1000),
> +	.va_wrdma_codec_intf		= REG_FIELD_ID(0x18050, 16, 19, 5, 0x1000),
> +	.va_wrdma_codec_fs_delay	= REG_FIELD_ID(0x18050, 21, 24, 5, 0x1000),
> +	.va_wrdma_codec_fs_sel		= REG_FIELD_ID(0x18050, 25, 27, 5, 0x1000),
> +	.va_wrdma_codec_pack		= REG_FIELD_ID(0x18050, 29, 29, 5, 0x1000),
> +	.va_wrdma_codec_enable		= REG_FIELD_ID(0x18050, 30, 30, 5, 0x1000),
> +
> +	.hdmi_tx_ctl_addr		= 0x1000,
> +	.hdmi_legacy_addr		= 0x1008,
> +	.hdmi_vbit_addr			= 0x610c0,
> +	.hdmi_ch_lsb_addr		= 0x61048,
> +	.hdmi_ch_msb_addr		= 0x6104c,
> +	.ch_stride			= 0x8,
> +	.hdmi_parity_addr		= 0x61034,
> +	.hdmi_dmactl_addr		= 0x61038,
> +	.hdmi_dma_stride		= 0x4,
> +	.hdmi_DP_addr			= 0x610c8,
> +	.hdmi_sstream_addr		= 0x6101c,
> +	.hdmi_irq_reg_base		= 0x63000,
> +	.hdmi_irq_ports			= 1,
> +
> +	.hdmi_rdma_dyncclk		= REG_FIELD_ID(0x64000, 14, 14, 4, 0x1000),
> +	.hdmi_rdma_bursten		= REG_FIELD_ID(0x64000, 13, 13, 4, 0x1000),
> +	.hdmi_rdma_burst8		= REG_FIELD_ID(0x64000, 15, 15, 4, 0x1000),
> +	.hdmi_rdma_burst16		= REG_FIELD_ID(0x64000, 16, 16, 4, 0x1000),
> +	.hdmi_rdma_dynburst		= REG_FIELD_ID(0x64000, 18, 18, 4, 0x1000),
> +	.hdmi_rdma_wpscnt		= REG_FIELD_ID(0x64000, 10, 12, 4, 0x1000),
> +	.hdmi_rdma_fifowm		= REG_FIELD_ID(0x64000, 1, 5, 4, 0x1000),
> +	.hdmi_rdma_enable		= REG_FIELD_ID(0x64000, 0, 0, 4, 0x1000),
> +
> +	.sstream_en			= REG_FIELD(0x6101c, 0, 0),
> +	.dma_sel			= REG_FIELD(0x6101c, 1, 2),
> +	.auto_bbit_en			= REG_FIELD(0x6101c, 3, 3),
> +	.layout				= REG_FIELD(0x6101c, 4, 4),
> +	.layout_sp			= REG_FIELD(0x6101c, 5, 8),
> +	.set_sp_on_en			= REG_FIELD(0x6101c, 10, 10),
> +	.dp_audio			= REG_FIELD(0x6101c, 11, 11),
> +	.dp_staffing_en			= REG_FIELD(0x6101c, 12, 12),
> +	.dp_sp_b_hw_en			= REG_FIELD(0x6101c, 13, 13),
> +
> +	.mute				= REG_FIELD(0x610c8, 0, 0),
> +	.as_sdp_cc			= REG_FIELD(0x610c8, 1, 3),
> +	.as_sdp_ct			= REG_FIELD(0x610c8, 4, 7),
> +	.aif_db4			= REG_FIELD(0x610c8, 8, 15),
> +	.frequency			= REG_FIELD(0x610c8, 16, 21),
> +	.mst_index			= REG_FIELD(0x610c8, 28, 29),
> +	.dptx_index			= REG_FIELD(0x610c8, 30, 31),
> +
> +	.soft_reset			= REG_FIELD(0x1000, 31, 31),
> +	.force_reset			= REG_FIELD(0x1000, 30, 30),
> +
> +	.use_hw_chs			= REG_FIELD(0x61038, 0, 0),
> +	.use_hw_usr			= REG_FIELD(0x61038, 1, 1),
> +	.hw_chs_sel			= REG_FIELD(0x61038, 2, 4),
> +	.hw_usr_sel			= REG_FIELD(0x61038, 5, 6),
> +
> +	.replace_vbit			= REG_FIELD(0x610c0, 0, 0),
> +	.vbit_stream			= REG_FIELD(0x610c0, 1, 1),
> +
> +	.legacy_en			=  REG_FIELD(0x1008, 0, 0),
> +	.calc_en			=  REG_FIELD(0x61034, 0, 0),
> +	.lsb_bits			=  REG_FIELD(0x61048, 0, 31),
> +	.msb_bits			=  REG_FIELD(0x6104c, 0, 31),
> +
> +
> +	.clk_name			= (const char*[]) {
> +							"lpass_aon_cc_audio_hm_h_clk",
> +							"lpass_core_cc_sysnoc_mport_core_clk"
> +						},
> +	.num_clks				= 2,
> +	.cdc_dma_clk_names		= (const char*[]) {
> +								"lpass_audio_cc_codec_mem0_clk",
> +								"lpass_audio_cc_codec_mem1_clk",
> +								"lpass_audio_cc_codec_mem2_clk",
> +								"lpass_aon_cc_va_mem0_clk"
> +							},
> +	.cdc_dma_num_clks				= 4,
> +	.dai_driver				= sc7280_lpass_cpu_dai_driver,
> +	.num_dai				= ARRAY_SIZE(sc7280_lpass_cpu_dai_driver),
> +	.dai_osr_clk_names		= (const char *[]) {
> +							   "null",
> +							   "null"
> +							},
> +	.dai_bit_clk_names		= (const char *[]) {
> +								"null",
> +								"lpass_core_cc_ext_if0_ibit_clk",
> +								"lpass_core_cc_ext_if1_ibit_clk"
> +							},
> +	.init					= sc7280_lpass_init,
> +	.exit					= sc7280_lpass_exit,
> +	.alloc_dma_channel		= sc7280_lpass_alloc_dma_channel,
> +	.free_dma_channel		= sc7280_lpass_free_dma_channel,
> +};
> +
> +static const struct of_device_id sc7280_lpass_cpu_device_id[] = {
> +	{.compatible = "qcom,sc7280-lpass-cpu", .data = &sc7280_data},
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, sc7280_lpass_cpu_device_id);
> +
> +static struct platform_driver sc7280_lpass_cpu_platform_driver = {
> +	.driver = {
> +		.name = "sc7280-lpass-cpu",
> +		.of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id),
> +	},
> +	.probe = asoc_qcom_lpass_cpu_platform_probe,
> +	.remove = asoc_qcom_lpass_cpu_platform_remove,
> +	.shutdown = asoc_qcom_lpass_cpu_platform_shutdown,
> +};
> +
> +module_platform_driver(sc7280_lpass_cpu_platform_driver);
> +
> +MODULE_DESCRIPTION("SC7280 LPASS CPU DRIVER");
> +MODULE_LICENSE("GPL v2");

use "GPL"

--srini

> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings
  2021-11-22 11:46   ` Srinivasa Rao Mandadapu
@ 2021-11-23 16:34     ` Rob Herring
  -1 siblings, 0 replies; 19+ messages in thread
From: Rob Herring @ 2021-11-23 16:34 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu
  Cc: alsa-devel, bgoswami, srinivas.kandagatla, linux-kernel,
	lgirdwood, rohitkr, judyhsiao, bjorn.andersson, plai, tiwai,
	agross, broonie, linux-arm-msm, swboyd, Venkata Prasad Potturu,
	devicetree, robh+dt, perex

On Mon, 22 Nov 2021 17:16:37 +0530, Srinivasa Rao Mandadapu wrote:
> Add bindings for lpass sc7280 based soundcards which supports
> audio over i2s based speaker, soundwire based headset, msm dmics
> and HDMI Port.
> 
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> ---
>  .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 69 +++++++++++++++++++---
>  1 file changed, 61 insertions(+), 8 deletions(-)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: reg: [[0, 1658351616, 0, 425984], [0, 1659895808, 0, 167936]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: reg-names: ['lpass-hdmiif', 'lpass-lpaif'] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupts: [[0, 160, 1], [0, 268, 1]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupt-names: ['lpass-irq-lpaif', 'lpass-irq-hdmi'] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: iommus: [[4294967295, 4128, 0], [4294967295, 4146, 0]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1558044

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings
@ 2021-11-23 16:34     ` Rob Herring
  0 siblings, 0 replies; 19+ messages in thread
From: Rob Herring @ 2021-11-23 16:34 UTC (permalink / raw)
  To: Srinivasa Rao Mandadapu
  Cc: devicetree, alsa-devel, bgoswami, Venkata Prasad Potturu,
	linux-arm-msm, plai, tiwai, linux-kernel, swboyd, lgirdwood,
	robh+dt, agross, rohitkr, broonie, bjorn.andersson, judyhsiao

On Mon, 22 Nov 2021 17:16:37 +0530, Srinivasa Rao Mandadapu wrote:
> Add bindings for lpass sc7280 based soundcards which supports
> audio over i2s based speaker, soundwire based headset, msm dmics
> and HDMI Port.
> 
> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
> ---
>  .../devicetree/bindings/sound/qcom,lpass-cpu.yaml  | 69 +++++++++++++++++++---
>  1 file changed, 61 insertions(+), 8 deletions(-)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: reg: [[0, 1658351616, 0, 425984], [0, 1659895808, 0, 167936]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: reg-names: ['lpass-hdmiif', 'lpass-lpaif'] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupts: [[0, 160, 1], [0, 268, 1]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: interrupt-names: ['lpass-irq-lpaif', 'lpass-irq-hdmi'] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
/builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.example.dt.yaml: lpass@62d80000: iommus: [[4294967295, 4128, 0], [4294967295, 4146, 0]] is too short
	From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/patch/1558044

This check can fail if there are any dependencies. The base for a patch
series is generally the most recent rc1.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit.


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v5 06/10] ASoC: qcom: Add support for codec dma driver
  2021-11-23 12:28   ` Srinivas Kandagatla
@ 2021-11-26 11:20     ` Srinivasa Rao Mandadapu
  0 siblings, 0 replies; 19+ messages in thread
From: Srinivasa Rao Mandadapu @ 2021-11-26 11:20 UTC (permalink / raw)
  To: Srinivas Kandagatla, agross, bjorn.andersson, lgirdwood, broonie,
	robh+dt, plai, bgoswami, perex, tiwai, rohitkr, linux-arm-msm,
	alsa-devel, devicetree, linux-kernel, swboyd, judyhsiao
  Cc: Venkata Prasad Potturu


On 11/23/2021 5:58 PM, Srinivas Kandagatla wrote:
Thanks for valuable time Srini!!!
>
> On 22/11/2021 11:46, Srinivasa Rao Mandadapu wrote:
>> Upadate lpass cpu and platform driver to support audio over codec dma
>> in ADSP bypass use case.
>>
>> Signed-off-by: Srinivasa Rao Mandadapu <srivasam@codeaurora.org>
>> Co-developed-by: Venkata Prasad Potturu <potturu@codeaurora.org>
>> Signed-off-by: Venkata Prasad Potturu <potturu@codeaurora.org>
>> ---
>>   sound/soc/qcom/common.c         |  39 ++++
>>   sound/soc/qcom/common.h         |   1 +
>
> common.c is mostly intended to be used by machine drivers, so I would 
> suggest that you move it to lpass.h and make is_cdc_dma_port a static 
> inlnie function.
>
Okay. will move to lpass.h
>>   sound/soc/qcom/lpass-cpu.c      |  60 +++++-
>>   sound/soc/qcom/lpass-platform.c | 424 
>> ++++++++++++++++++++++++++++++++++++++--
>>   4 files changed, 508 insertions(+), 16 deletions(-)
>>
>> diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
>> index 09af007..26d3752 100644
>> --- a/sound/soc/qcom/common.c
>> +++ b/sound/soc/qcom/common.c
>> @@ -4,6 +4,7 @@
>>     #include <linux/module.h>
>>   #include "common.h"
>> +#include "lpass.h"
>>     int qcom_snd_parse_of(struct snd_soc_card *card)
>>   {
>> @@ -169,4 +170,42 @@ int qcom_snd_parse_of(struct snd_soc_card *card)
>>   }
>>   EXPORT_SYMBOL(qcom_snd_parse_of);
>>   +bool is_cdc_dma_port(int dai_id)
>> +{
>> +    switch (dai_id) {
>> +    case LPASS_CDC_DMA_RX0:
>> +    case LPASS_CDC_DMA_RX1:
>> +    case LPASS_CDC_DMA_RX2:
>> +    case LPASS_CDC_DMA_RX3:
>> +    case LPASS_CDC_DMA_RX4:
>> +    case LPASS_CDC_DMA_RX5:
>> +    case LPASS_CDC_DMA_RX6:
>> +    case LPASS_CDC_DMA_RX7:
>> +    case LPASS_CDC_DMA_RX8:
>> +    case LPASS_CDC_DMA_RX9:
>> +    case LPASS_CDC_DMA_TX0:
>> +    case LPASS_CDC_DMA_TX1:
>> +    case LPASS_CDC_DMA_TX2:
>> +    case LPASS_CDC_DMA_TX3:
>> +    case LPASS_CDC_DMA_TX4:
>> +    case LPASS_CDC_DMA_TX5:
>> +    case LPASS_CDC_DMA_TX6:
>> +    case LPASS_CDC_DMA_TX7:
>> +    case LPASS_CDC_DMA_TX8:
>> +    case LPASS_CDC_DMA_VA_TX0:
>> +    case LPASS_CDC_DMA_VA_TX1:
>> +    case LPASS_CDC_DMA_VA_TX2:
>> +    case LPASS_CDC_DMA_VA_TX3:
>> +    case LPASS_CDC_DMA_VA_TX4:
>> +    case LPASS_CDC_DMA_VA_TX5:
>> +    case LPASS_CDC_DMA_VA_TX6:
>> +    case LPASS_CDC_DMA_VA_TX7:
>> +    case LPASS_CDC_DMA_VA_TX8:
>> +        return true;
>> +    default:
>> +        return false;
>> +    }
>> +}
>> +EXPORT_SYMBOL(is_cdc_dma_port);
>> +
>>   MODULE_LICENSE("GPL v2");
>> diff --git a/sound/soc/qcom/common.h b/sound/soc/qcom/common.h
>> index f05c05b..a8fea4c 100644
>> --- a/sound/soc/qcom/common.h
>> +++ b/sound/soc/qcom/common.h
>> @@ -7,5 +7,6 @@
>>   #include <sound/soc.h>
>>     int qcom_snd_parse_of(struct snd_soc_card *card);
>> +bool is_cdc_dma_port(int dai_id);
>>     #endif
>> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
>> index 3bd9eb3..9e6656c 100644
>> --- a/sound/soc/qcom/lpass-cpu.c
>> +++ b/sound/soc/qcom/lpass-cpu.c
>> @@ -17,6 +17,7 @@
>>   #include <sound/soc.h>
>>   #include <sound/soc-dai.h>
>>   #include "lpass-lpaif-reg.h"
>> +#include "common.h"
>>   #include "lpass.h"
>>     #define LPASS_CPU_MAX_MI2S_LINES    4
>> @@ -857,7 +858,9 @@ static void of_lpass_cpu_parse_dai_data(struct 
>> device *dev,
>>           }
>>           if (id == LPASS_DP_RX) {
>>               data->hdmi_port_enable = 1;
>> -        } else {
>> +        } else if (is_cdc_dma_port(id))
>> +            data->codec_dma_enable = 1;
>> +        else {
>>               data->mi2s_playback_sd_mode[id] =
>>                   of_lpass_cpu_parse_sd_lines(dev, node,
>>                                   "qcom,playback-sd-lines");
>> @@ -872,6 +875,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>   {
>>       struct lpass_data *drvdata;
>>       struct device_node *dsp_of_node;
>> +    struct resource *res;
>>       struct lpass_variant *variant;
>>       struct device *dev = &pdev->dev;
>>       const struct of_device_id *match;
>> @@ -897,6 +901,58 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>         of_lpass_cpu_parse_dai_data(dev, drvdata);
>>   +    drvdata->num_clks =  variant->num_clks;
>> +    if (drvdata->codec_dma_enable) {
>> +        drvdata->rxtx_lpaif =
>> +                devm_platform_ioremap_resource_byname(pdev, 
>> "lpass-rxtx-lpaif");
>> +        if (IS_ERR(drvdata->rxtx_lpaif))
>> +            return PTR_ERR(drvdata->rxtx_lpaif);
>> +
>> +        drvdata->va_lpaif = 
>> devm_platform_ioremap_resource_byname(pdev, "lpass-va-lpaif");
>> +        if (IS_ERR(drvdata->va_lpaif))
>> +            return PTR_ERR(drvdata->va_lpaif);
>> +
>> +        lpass_rxtx_regmap_config.max_register = 
>> LPAIF_CDC_WRDMAPER_REG(variant,
>> +                    variant->rxtx_wrdma_channels +
>> +                    variant->rxtx_wrdma_channel_start, 
>> LPASS_CDC_DMA_TX3);
>> +
>> +        drvdata->rxtx_lpaif_map = devm_regmap_init_mmio(dev, 
>> drvdata->rxtx_lpaif,
>> +                    &lpass_rxtx_regmap_config);
>> +        if (IS_ERR(drvdata->rxtx_lpaif_map)) {
>> +            dev_err(dev, "error initializing rxtx regmap: %ld\n",
>> +                PTR_ERR(drvdata->rxtx_lpaif_map));
>> +            return PTR_ERR(drvdata->rxtx_lpaif_map);
>> +        }
>> +        lpass_va_regmap_config.max_register = 
>> LPAIF_CDC_WRDMAPER_REG(variant,
>> +                    variant->va_wrdma_channels +
>> +                    variant->va_wrdma_channel_start, 
>> LPASS_CDC_DMA_VA_TX0);
>> +
>> +        drvdata->va_lpaif_map = devm_regmap_init_mmio(dev, 
>> drvdata->va_lpaif,
>> +                    &lpass_va_regmap_config);
>> +        if (IS_ERR(drvdata->va_lpaif_map)) {
>> +            dev_err(dev, "error initializing va regmap: %ld\n",
>> +                PTR_ERR(drvdata->va_lpaif_map));
> there is a 100 chars limit now, so you can wrap this to a single line.
>
Okay. it's crossing 102 lines.
>> +            return PTR_ERR(drvdata->va_lpaif_map);
>> +        }
>> +        drvdata->cdc_clks = devm_kcalloc(dev, 
>> variant->cdc_dma_num_clks,
>> +                    sizeof(*drvdata->cdc_clks), GFP_KERNEL);
>> +        drvdata->cdc_num_clks = variant->cdc_dma_num_clks;
> double space after =
>
okay.
>> +
>> +        for (i = 0; i < drvdata->cdc_num_clks; i++)
>> +            drvdata->cdc_clks[i].id = variant->cdc_dma_clk_names[i];
>> +
>> +        ret = devm_clk_bulk_get(dev, drvdata->cdc_num_clks, 
>> drvdata->cdc_clks);
>> +        if (ret) {
>> +            dev_err(dev, "Failed to get clocks %d\n", ret);
>> +            return ret;
>> +        }
>> +
>> +        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 
>> "lpass-rxtx-cdc-dma-lpm");
>> +        drvdata->rxtx_cdc_dma_lpm_buf = res->start;
>> +
>> +        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 
>> "lpass-va-cdc-dma-lpm");
>> +        drvdata->va_cdc_dma_lpm_buf = res->start;
>> +    }
>>       drvdata->lpaif = devm_platform_ioremap_resource_byname(pdev, 
>> "lpass-lpaif");
>>       if (IS_ERR(drvdata->lpaif))
>>           return PTR_ERR(drvdata->lpaif);
>> @@ -939,7 +995,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>         for (i = 0; i < variant->num_dai; i++) {
>>           dai_id = variant->dai_driver[i].id;
>> -        if (dai_id == LPASS_DP_RX)
>> +        if (dai_id == LPASS_DP_RX || is_cdc_dma_port(dai_id))
>>               continue;
>>             drvdata->mi2s_osr_clk[dai_id] = devm_clk_get_optional(dev,
>> diff --git a/sound/soc/qcom/lpass-platform.c 
>> b/sound/soc/qcom/lpass-platform.c
>> index 59c0884..4b79908 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>> @@ -14,12 +14,15 @@
>>   #include <linux/regmap.h>
>>   #include <sound/soc.h>
>>   #include "lpass-lpaif-reg.h"
>> +#include "common.h"
>>   #include "lpass.h"
>>     #define DRV_NAME "lpass-platform"
>>     #define LPASS_PLATFORM_BUFFER_SIZE    (24 *  2 * 1024)
>>   #define LPASS_PLATFORM_PERIODS        2
>> +#define LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE (24 * 1024)
>> +#define LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE (12 * 1024)
>>     static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>>       .info            =    SNDRV_PCM_INFO_MMAP |
>> @@ -45,6 +48,103 @@ static const struct snd_pcm_hardware 
>> lpass_platform_pcm_hardware = {
>>       .fifo_size        =    0,
>>   };
>>   +static const struct snd_pcm_hardware lpass_platform_rxtx_hardware = {
>> +    .info            =    SNDRV_PCM_INFO_MMAP |
>> +                    SNDRV_PCM_INFO_MMAP_VALID |
>> +                    SNDRV_PCM_INFO_INTERLEAVED |
>> +                    SNDRV_PCM_INFO_PAUSE |
>> +                    SNDRV_PCM_INFO_RESUME,
>> +    .formats        =    SNDRV_PCM_FMTBIT_S16 |
>> +                    SNDRV_PCM_FMTBIT_S24 |
>> +                    SNDRV_PCM_FMTBIT_S32,
>> +    .rates            =    SNDRV_PCM_RATE_8000_192000,
>> +    .rate_min        =    8000,
>> +    .rate_max        =    192000,
>> +    .channels_min        =    1,
>> +    .channels_max        =    8,
>> +    .buffer_bytes_max    =    LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE,
>> +    .period_bytes_max    =    LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
>> +                        LPASS_PLATFORM_PERIODS,
>> +    .period_bytes_min    =    LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE /
>> +                        LPASS_PLATFORM_PERIODS,
>> +    .periods_min        =    LPASS_PLATFORM_PERIODS,
>> +    .periods_max        =    LPASS_PLATFORM_PERIODS,
>> +    .fifo_size        =    0,
>> +};
>> +
>> +static const struct snd_pcm_hardware lpass_platform_va_hardware = {
>> +    .info            =    SNDRV_PCM_INFO_MMAP |
>> +                    SNDRV_PCM_INFO_MMAP_VALID |
>> +                    SNDRV_PCM_INFO_INTERLEAVED |
>> +                    SNDRV_PCM_INFO_PAUSE |
>> +                    SNDRV_PCM_INFO_RESUME,
>> +    .formats        =    SNDRV_PCM_FMTBIT_S16 |
>> +                    SNDRV_PCM_FMTBIT_S24 |
>> +                    SNDRV_PCM_FMTBIT_S32,
>> +    .rates            =    SNDRV_PCM_RATE_8000_192000,
>> +    .rate_min        =    8000,
>> +    .rate_max        =    192000,
>> +    .channels_min        =    1,
>> +    .channels_max        =    8,
>> +    .buffer_bytes_max    =    LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE,
>> +    .period_bytes_max    =    LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
>> +                        LPASS_PLATFORM_PERIODS,
>> +    .period_bytes_min    =    LPSAS_VA_CDC_DMA_LPM_BUFF_SIZE /
>> +                        LPASS_PLATFORM_PERIODS,
>> +    .periods_min        =    LPASS_PLATFORM_PERIODS,
>> +    .periods_max        =    LPASS_PLATFORM_PERIODS,
>> +    .fifo_size        =    0,
>> +};
>> +
>> +static int lpass_platform_alloc_rxtx_dmactl_fields(struct device *dev,
>> +                     struct regmap *map)
>> +{
>> +    struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +    struct lpass_variant *v = drvdata->variant;
>> +    struct lpaif_dmactl *rd_dmactl, *wr_dmactl;
>> +    int rval;
>> +
>> +    drvdata->rxtx_rd_dmactl = devm_kzalloc(dev, sizeof(struct 
>> lpaif_dmactl),
>> +                      GFP_KERNEL);
>> +    if (drvdata->rxtx_rd_dmactl == NULL)
>> +        return -ENOMEM;
>> +
>> +    drvdata->rxtx_wr_dmactl = devm_kzalloc(dev, sizeof(struct 
>> lpaif_dmactl),
>> +                      GFP_KERNEL);
>> +    if (drvdata->rxtx_wr_dmactl == NULL)
>> +        return -ENOMEM;
>> +
>> +    rd_dmactl = drvdata->rxtx_rd_dmactl;
>> +    wr_dmactl = drvdata->rxtx_wr_dmactl;
>
> may be rewrite this to:
>
>     rd_dmactl = devm_kzalloc(dev, sizeof(*rd_dmactl), GFP_KERNEL);
>     if (rd_dmactl == NULL)
>         return -ENOMEM;
>
>     wr_dmactl = devm_kzalloc(dev, sizeof(*wr_dmactl), GFP_KERNEL);
>     if (wr_dmactl == NULL)
>         return -ENOMEM;
>
>     drvdata->rxtx_rd_dmactl = rd_dmactl;
>     drvdata->rxtx_wr_dmactl = wr_dmactl;
>
Okay.
>
>> +
>> +    rval = devm_regmap_field_bulk_alloc(dev, map, &rd_dmactl->intf,
>> +                        &v->rxtx_rdma_intf, 15);
>
> can we define this magic number 15 properly?
Okay.
>> +    if (rval)
>> +        return rval;
>> +
>> +    return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
>> +                        &v->rxtx_wrdma_intf, 15);
>> +}
>> +
>> +static int lpass_platform_alloc_va_dmactl_fields(struct device *dev,
>> +                     struct regmap *map)
>> +{
>> +    struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +    struct lpass_variant *v = drvdata->variant;
>> +    struct lpaif_dmactl *wr_dmactl;
>> +
>> +    drvdata->va_wr_dmactl = devm_kzalloc(dev, sizeof(struct 
>> lpaif_dmactl),
>> +                      GFP_KERNEL);
>> +    if (drvdata->va_wr_dmactl == NULL)
>> +        return -ENOMEM;
>> +
>> +    wr_dmactl = drvdata->va_wr_dmactl;
> simillar comment.
>
Okay.
>> +
>> +    return devm_regmap_field_bulk_alloc(dev, map, &wr_dmactl->intf,
>> +                        &v->va_wrdma_intf, 15);
>> +}
>> +
>> +
>>   static int lpass_platform_alloc_dmactl_fields(struct device *dev,
>>                        struct regmap *map)
>>   {
>> @@ -126,22 +226,43 @@ static int lpass_platform_pcmops_open(struct 
>> snd_soc_component *component,
>>       if (cpu_dai->driver->id == LPASS_DP_RX) {
>>           map = drvdata->hdmiif_map;
>>           drvdata->hdmi_substream[dma_ch] = substream;
>> +    } else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == 
>> LPASS_CDC_DMA_TX3) {
>> +        map = drvdata->rxtx_lpaif_map;
>> +        drvdata->rxtx_substream[dma_ch] = substream;
>> +    } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
>> +        map = drvdata->va_lpaif_map;
>> +        drvdata->va_substream[dma_ch] = substream;
>>       } else {
>>           map = drvdata->lpaif_map;
>>           drvdata->substream[dma_ch] = substream;
>>       }
>>       data->dma_ch = dma_ch;
>> -    ret = regmap_write(map,
>> -            LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
>> -    if (ret) {
>> -        dev_err(soc_runtime->dev,
>> -            "error writing to rdmactl reg: %d\n", ret);
>> -        return ret;
>> +    if (!(dai_id == LPASS_CDC_DMA_RX0 ||
>> +        dai_id == LPASS_CDC_DMA_TX3 ||
>> +        dai_id == LPASS_CDC_DMA_VA_TX0)) {
>> +        ret = regmap_write(map, LPAIF_DMACTL_REG(v, dma_ch, dir, 
>> data->i2s_port), 0);
>> +        if (ret) {
>> +            dev_err(soc_runtime->dev,
>> +                "error writing to rdmactl reg: %d\n", ret);
>> +            return ret;
>> +        }
>>       }
>> -    snd_soc_set_runtime_hwparams(substream, 
>> &lpass_platform_pcm_hardware);
>> -
>> -    runtime->dma_bytes = lpass_platform_pcm_hardware.buffer_bytes_max;
>>   +    switch (dai_id) {
>> +    case LPASS_CDC_DMA_RX0:
>> +    case LPASS_CDC_DMA_TX3:
>> +        snd_soc_set_runtime_hwparams(substream, 
>> &lpass_platform_rxtx_hardware);
>> +        runtime->dma_bytes = 
>> lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +        break;
>> +    case LPASS_CDC_DMA_VA_TX0:
>> +        snd_soc_set_runtime_hwparams(substream, 
>> &lpass_platform_va_hardware);
>> +        runtime->dma_bytes = 
>> lpass_platform_va_hardware.buffer_bytes_max;
>> +        break;
>> +    default:
>> +        snd_soc_set_runtime_hwparams(substream, 
>> &lpass_platform_pcm_hardware);
>> +        runtime->dma_bytes = 
>> lpass_platform_pcm_hardware.buffer_bytes_max;
>> +        break;
>> +    }
>>       ret = snd_pcm_hw_constraint_integer(runtime,
>>               SNDRV_PCM_HW_PARAM_PERIODS);
>>       if (ret < 0) {
>> @@ -168,6 +289,10 @@ static int lpass_platform_pcmops_close(struct 
>> snd_soc_component *component,
>>       data = runtime->private_data;
>>       if (dai_id == LPASS_DP_RX)
>>           drvdata->hdmi_substream[data->dma_ch] = NULL;
>> +    else if (dai_id == LPASS_CDC_DMA_RX0 || dai_id == 
>> LPASS_CDC_DMA_TX3)
>> +        drvdata->rxtx_substream[data->dma_ch] = NULL;
>> +    else if (dai_id == LPASS_CDC_DMA_VA_TX0)
>> +        drvdata->va_substream[data->dma_ch] = NULL;
>>       else
>>           drvdata->substream[data->dma_ch] = NULL;
>>       if (v->free_dma_channel)
>> @@ -198,14 +323,27 @@ static void __get_lpaif_handle(struct 
>> snd_pcm_substream *substream,
>>           if (dai_id == LPASS_DP_RX) {
>>               l_dmactl = drvdata->hdmi_rd_dmactl;
>>               l_map = drvdata->hdmiif_map;
>> +        } else if (dai_id == LPASS_CDC_DMA_RX0) {
>> +            l_map = drvdata->rxtx_lpaif_map;
>> +            l_dmactl = drvdata->rxtx_rd_dmactl;
>>           } else {
>>               l_dmactl = drvdata->rd_dmactl;
>>               l_map = drvdata->lpaif_map;
>>           }
>>       } else {
>> -        l_dmactl = drvdata->wr_dmactl;
>> -        l_id = pcm_data->dma_ch - v->wrdma_channel_start;
>> -        l_map = drvdata->lpaif_map;
>> +        if (dai_id == LPASS_CDC_DMA_TX3) {
>> +            l_dmactl = drvdata->rxtx_wr_dmactl;
>> +            l_map = drvdata->rxtx_lpaif_map;
>> +            l_id = pcm_data->dma_ch - v->rxtx_wrdma_channel_start;
>> +        } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
>> +            l_dmactl = drvdata->va_wr_dmactl;
>> +            l_map = drvdata->va_lpaif_map;
>> +            l_id = pcm_data->dma_ch - v->va_wrdma_channel_start;
>> +        } else {
>> +            l_dmactl = drvdata->wr_dmactl;
>> +            l_id = pcm_data->dma_ch - v->wrdma_channel_start;
>> +            l_map = drvdata->lpaif_map;
>> +        }
>>       }
>>       if (dmactl)
>>           *dmactl = l_dmactl;
>> @@ -256,6 +394,10 @@ static int 
>> lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
>>       }
>>         switch (dai_id) {
>> +    case LPASS_CDC_DMA_RX0:
>> +    case LPASS_CDC_DMA_TX3:
>> +    case LPASS_CDC_DMA_VA_TX0:
>
> Is there a reason why we can not add support to other CDC_DMA dais as 
> part of this patchset?
>
Okay.. will include all possible dais.
>> +        break;
>>       case LPASS_DP_RX:
>>           ret = regmap_fields_write(dmactl->burst8, id,
>>                               LPAIF_DMACTL_BURSTEN_INCR4);
>> @@ -380,6 +522,10 @@ static int lpass_platform_pcmops_hw_free(struct 
>> snd_soc_component *component,
>>         if (dai_id == LPASS_DP_RX)
>>           map = drvdata->hdmiif_map;
>> +    else if (dai_id == LPASS_CDC_DMA_RX0 ||
>> +        dai_id == LPASS_CDC_DMA_TX3 ||
>> +        dai_id == LPASS_CDC_DMA_VA_TX0)
>> +        return 0;
>>       else
>>           map = drvdata->lpaif_map;
>>   @@ -434,6 +580,16 @@ static int 
>> lpass_platform_pcmops_prepare(struct snd_soc_component *component,
>>           return ret;
>>       }
>>   +    if (dai_id == LPASS_CDC_DMA_RX0 ||
>> +        dai_id == LPASS_CDC_DMA_TX3 ||
>> +        dai_id == LPASS_CDC_DMA_VA_TX0) {
>> +        ret = regmap_fields_write(dmactl->fifowm, id, 
>> LPAIF_DMACTL_FIFOWM_8);
>> +        if (ret) {
>> +            dev_err(soc_runtime->dev, "error writing fifowm field to 
>> dmactl reg: %d, id: %d\n",
>> +                ret, id);
>> +            return ret;
>> +        }
>> +    }
>>       ret = regmap_fields_write(dmactl->enable, id, 
>> LPAIF_DMACTL_ENABLE_ON);
>>       if (ret) {
>>           dev_err(soc_runtime->dev, "error writing to rdmactl reg: 
>> %d\n",
>> @@ -476,6 +632,22 @@ static int lpass_platform_pcmops_trigger(struct 
>> snd_soc_component *component,
>>               return ret;
>>           }
>>           switch (dai_id) {
>> +        case LPASS_CDC_DMA_RX0:
>> +        case LPASS_CDC_DMA_TX3:
>> +        case LPASS_CDC_DMA_VA_TX0:
>> +            ret = regmap_fields_write(dmactl->dyncclk, id, 
>> LPAIF_DMACTL_DYNCLK_ON);
>> +            if (ret) {
>> +                dev_err(soc_runtime->dev,
>> +                    "error writing to rdmactl reg field: %d\n", ret);
>> +                return ret;
>> +            }
>> +            reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, 
>> LPAIF_IRQ_PORT_HOST, dai_id);
>> +            val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +            reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, 
>> dai_id);
>> +            val_mask = LPAIF_IRQ_ALL(ch);
>> +            val_irqen = LPAIF_IRQ_ALL(ch);
>> +            break;
>>           case LPASS_DP_RX:
>>               ret = regmap_fields_write(dmactl->dyncclk, id,
>>                        LPAIF_DMACTL_DYNCLK_ON);
>> @@ -540,6 +712,24 @@ static int lpass_platform_pcmops_trigger(struct 
>> snd_soc_component *component,
>>               return ret;
>>           }
>>           switch (dai_id) {
>> +        case LPASS_CDC_DMA_RX0:
>> +        case LPASS_CDC_DMA_TX3:
>> +        case LPASS_CDC_DMA_VA_TX0:
>> +            ret = regmap_fields_write(dmactl->dyncclk, id, 
>> LPAIF_DMACTL_DYNCLK_OFF);
>> +            if (ret) {
>> +                dev_err(soc_runtime->dev,
>> +                    "error writing to rdmactl reg field: %d\n", ret);
>> +                return ret;
>> +            }
>> +
>> +            reg_irqclr = LPAIF_RXTX_IRQCLEAR_REG(v, 
>> LPAIF_IRQ_PORT_HOST, dai_id);
>> +            val_irqclr = LPAIF_IRQ_ALL(ch);
>> +
>> +            reg_irqen = LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, 
>> dai_id);
>> +            val_mask = LPAIF_IRQ_ALL(ch);
>> +            val_irqen = LPAIF_IRQ_ALL(ch);
>> +
>> +        break;
>>           case LPASS_DP_RX:
>>               ret = regmap_fields_write(dmactl->dyncclk, id,
>>                        LPAIF_DMACTL_DYNCLK_OFF);
>> @@ -619,6 +809,38 @@ static snd_pcm_uframes_t 
>> lpass_platform_pcmops_pointer(
>>       return bytes_to_frames(substream->runtime, curr_addr - base_addr);
>>   }
>>   +static int lpass_platform_cdc_dma_mmap(struct snd_soc_component 
>> *component,
>> +            struct snd_pcm_substream *substream,
>> +            struct vm_area_struct *vma)
>> +{
>> +    struct snd_pcm_runtime *runtime = substream->runtime;
>> +    unsigned long size, offset;
>> +
>> +    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
>> +    size = vma->vm_end - vma->vm_start;
>> +    offset = vma->vm_pgoff << PAGE_SHIFT;
>> +    return io_remap_pfn_range(vma, vma->vm_start,
>> +            (runtime->dma_addr + offset) >> PAGE_SHIFT,
>> +            size, vma->vm_page_prot);
>> +
>> +}
>> +
>> +static int lpass_platform_pcmops_mmap(struct snd_soc_component 
>> *component,
>> +                      struct snd_pcm_substream *substream,
>> +                      struct vm_area_struct *vma)
>> +{
>> +    struct snd_soc_pcm_runtime *soc_runtime = 
>> asoc_substream_to_rtd(substream);
>> +    struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +    unsigned int dai_id = cpu_dai->driver->id;
>> +
>> +    if (dai_id == LPASS_CDC_DMA_RX0 ||
>> +        dai_id == LPASS_CDC_DMA_TX3 ||
>> +        dai_id == LPASS_CDC_DMA_VA_TX0) {
>> +        return lpass_platform_cdc_dma_mmap(component, substream, vma);
>> +    }
>> +    return 0;
>> +}
>> +
>>   static irqreturn_t lpass_dma_interrupt_handler(
>>               struct snd_pcm_substream *substream,
>>               struct lpass_data *drvdata,
>> @@ -635,6 +857,14 @@ static irqreturn_t lpass_dma_interrupt_handler(
>>         mask = LPAIF_IRQ_ALL(chan);
>>       switch (dai_id) {
>> +    case LPASS_CDC_DMA_RX0:
>> +    case LPASS_CDC_DMA_TX3:
>> +    case LPASS_CDC_DMA_VA_TX0:
>> +        map = (dai_id == LPASS_CDC_DMA_VA_TX0) ?
>> +                drvdata->va_lpaif_map : drvdata->rxtx_lpaif_map;
>> +        reg = LPAIF_RXTX_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST, dai_id);
>> +        val = 0;
>> +        break;
>>       case LPASS_DP_RX:
>>           map = drvdata->hdmiif_map;
>>           reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
>> @@ -758,18 +988,112 @@ static irqreturn_t 
>> lpass_platform_hdmiif_irq(int irq, void *data)
>>                   return rv;
>>           }
>>       }
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static irqreturn_t lpass_platform_rxtxif_irq(int irq, void *data)
>> +{
>> +    struct lpass_data *drvdata = data;
>> +    struct lpass_variant *v = drvdata->variant;
>> +    unsigned int irqs;
>> +    int rv, chan;
>> +
>> +    rv = regmap_read(drvdata->rxtx_lpaif_map,
>> +            LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST, 
>> LPASS_CDC_DMA_RX0), &irqs);
>> +    if (rv)
>> +        return IRQ_NONE;
>> +    /* Handle per channel interrupts */
>> +    for (chan = 0; chan < LPASS_MAX_CDC_DMA_CHANNELS; chan++) {
>> +        if (irqs & LPAIF_IRQ_ALL(chan) && 
>> drvdata->rxtx_substream[chan]) {
>> +            rv = lpass_dma_interrupt_handler(
>> +                        drvdata->rxtx_substream[chan],
>> +                        drvdata, chan, irqs);
>> +            if (rv != IRQ_HANDLED)
>> +                return rv;
>> +        }
>> +    }
>> +
>> +    return IRQ_HANDLED;
>> +}
>> +
>> +static irqreturn_t lpass_platform_vaif_irq(int irq, void *data)
>> +{
>> +    struct lpass_data *drvdata = data;
>> +    struct lpass_variant *v = drvdata->variant;
>> +    unsigned int irqs;
>> +    int rv, chan;
>>   +    rv = regmap_read(drvdata->va_lpaif_map,
>> +            LPAIF_RXTX_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST,
>> +            LPASS_CDC_DMA_VA_TX0), &irqs);
>> +    if (rv)
>> +        return IRQ_NONE;
>> +    /* Handle per channel interrupts */
>> +    for (chan = 0; chan < LPASS_MAX_VA_CDC_DMA_CHANNELS; chan++) {
>> +        if (irqs & LPAIF_IRQ_ALL(chan) && 
>> drvdata->va_substream[chan]) {
>> +            rv = lpass_dma_interrupt_handler(
>> +                        drvdata->va_substream[chan],
>> +                        drvdata, chan, irqs);
>> +            if (rv != IRQ_HANDLED)
>> +                return rv;
>> +        }
>> +    }
>>       return IRQ_HANDLED;
>>   }
>>   +static int lpass_platform_prealloc_cdc_dma_buffer(struct 
>> snd_soc_component *component,
>> +            struct snd_pcm *pcm, int dai_id)
>> +{
>> +    struct lpass_data *drvdata = 
>> snd_soc_component_get_drvdata(component);
>> +    struct snd_pcm_substream *substream;
>> +    struct snd_dma_buffer *buf;
>> +    int ret;
>> +
>> +    if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
>> +        substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
>> +    else
>> +        substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
>> +
>> +    ret = dma_coerce_mask_and_coherent(pcm->card->dev, 
>> DMA_BIT_MASK(64));
>> +    if (ret)
>> +        return ret;
>> +
>> +    buf = &substream->dma_buffer;
>> +    buf->dev.dev = pcm->card->dev;
>> +    buf->private_data = NULL;
>> +
>> +    /* Assign Codec DMA buffer pointers */
>> +    buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
>> +    if (dai_id == LPASS_CDC_DMA_RX0) {
>> +        buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +        buf->addr = drvdata->rxtx_cdc_dma_lpm_buf;
>> +    } else if (dai_id == LPASS_CDC_DMA_TX3) {
>> +        buf->bytes = lpass_platform_rxtx_hardware.buffer_bytes_max;
>> +        buf->addr = drvdata->rxtx_cdc_dma_lpm_buf + 
>> LPSAS_RXTX_CDC_DMA_LPM_BUFF_SIZE;
>> +    } else if (dai_id == LPASS_CDC_DMA_VA_TX0) {
>> +        buf->bytes = lpass_platform_va_hardware.buffer_bytes_max;
>> +        buf->addr = drvdata->va_cdc_dma_lpm_buf;
>> +    }
>> +
>> +    buf->area = (unsigned char * __force)ioremap(buf->addr, 
>> buf->bytes);
>> +
>> +    return 0;
>> +}
>> +
>>   static int lpass_platform_pcm_new(struct snd_soc_component *component,
>>                     struct snd_soc_pcm_runtime *soc_runtime)
>>   {
>>       struct snd_pcm *pcm = soc_runtime->pcm;
>> +    struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
>> +    unsigned int dai_id = cpu_dai->driver->id;
>> +
>>       size_t size = lpass_platform_pcm_hardware.buffer_bytes_max;
>>   -    return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
>> -                        component->dev, size);
>> +    if (is_cdc_dma_port(dai_id))
>> +        return lpass_platform_prealloc_cdc_dma_buffer(component, 
>> pcm, dai_id);
> May be a comment here would be nice for reader to understand why we 
> allocate this buffer.
Okay. will add comments.
>
>> +    else
>> +        return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
>> +                        component->dev, size);
>>   }
>>     static int lpass_platform_pcmops_suspend(struct snd_soc_component 
>> *component)
>> @@ -804,6 +1128,22 @@ static int lpass_platform_pcmops_resume(struct 
>> snd_soc_component *component)
>>       return regcache_sync(map);
>>   }
>>   +int lpass_platform_copy(struct snd_soc_component *component,
>> +             struct snd_pcm_substream *substream, int channel,
>> +             unsigned long pos, void __user *buf, unsigned long bytes)
>> +{
>> +    struct snd_pcm_runtime *rt = substream->runtime;
>> +
>> +    unsigned char *dma_buf = rt->dma_area + pos +
>> +                channel * (rt->dma_bytes / rt->channels);
>> +
>> +    if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> +        return copy_from_user_toio(dma_buf, buf, bytes);
>> +    else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
>> +        return copy_to_user_fromio(buf, dma_buf, bytes);
>> +
>> +    return 0;
>> +}
>>     static const struct snd_soc_component_driver 
>> lpass_component_driver = {
>>       .name        = DRV_NAME,
>> @@ -814,9 +1154,11 @@ static const struct snd_soc_component_driver 
>> lpass_component_driver = {
>>       .prepare    = lpass_platform_pcmops_prepare,
>>       .trigger    = lpass_platform_pcmops_trigger,
>>       .pointer    = lpass_platform_pcmops_pointer,
>> +    .mmap        = lpass_platform_pcmops_mmap,
>
> isn't this just snd_pcm_lib_mmap_iomem for cdc dma.
Yes. it's required for only cdc dma.
>
>>       .pcm_construct    = lpass_platform_pcm_new,
>>       .suspend        = lpass_platform_pcmops_suspend,
>>       .resume            = lpass_platform_pcmops_resume,
>> +    .copy_user        = lpass_platform_copy,
>
> Why do we need this for other non cdc dma dais?
>
>
> Am thinking that we shoudl have a seperate instance of this for dais 
> that can only do dma with hardware buffers.
Okay. How to maintain 2 instances in the same platform driver?
>
>>     };
>>   @@ -854,6 +1196,60 @@ int asoc_qcom_lpass_platform_register(struct 
>> platform_device *pdev)
>>           return ret;
>>       }
>>   +    if (drvdata->codec_dma_enable) {
>> +        ret = regmap_write(drvdata->rxtx_lpaif_map,
>> +            LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, 
>> LPASS_CDC_DMA_TX3), 0x0);
>> +        if (ret) {
>> +            dev_err(&pdev->dev, "error writing to rxtx irqen reg: 
>> %d\n", ret);
>> +            return ret;
>> +        }
>> +        ret = regmap_write(drvdata->va_lpaif_map,
>> +            LPAIF_RXTX_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST, 
>> LPASS_CDC_DMA_VA_TX0), 0x0);
>> +        if (ret) {
>> +            dev_err(&pdev->dev, "error writing to rxtx irqen reg: 
>> %d\n", ret);
>> +            return ret;
>> +        }
>> +        drvdata->rxtxif_irq = platform_get_irq_byname(pdev, 
>> "lpass-irq-rxtxif");
>> +        if (drvdata->rxtxif_irq < 0)
>> +            return -ENODEV;
>> +
>> +        ret = devm_request_irq(&pdev->dev, drvdata->rxtxif_irq,
>> +                lpass_platform_rxtxif_irq, IRQF_TRIGGER_RISING,
>> +                "lpass-irq-rxtxif", drvdata);
>> +        if (ret) {
>> +            dev_err(&pdev->dev, "rxtx irq request failed: %d\n", ret);
>> +            return ret;
>> +        }
>> +
>> +        ret = lpass_platform_alloc_rxtx_dmactl_fields(&pdev->dev,
>> +                         drvdata->rxtx_lpaif_map);
>> +        if (ret) {
>> +            dev_err(&pdev->dev,
>> +                "error initializing rxtx dmactl fields: %d\n", ret);
>> +            return ret;
>> +        }
>> +
>> +        drvdata->vaif_irq = platform_get_irq_byname(pdev, 
>> "lpass-irq-vaif");
>> +        if (drvdata->vaif_irq < 0)
>> +            return -ENODEV;
>> +
>> +        ret = devm_request_irq(&pdev->dev, drvdata->vaif_irq,
>> +                lpass_platform_vaif_irq, IRQF_TRIGGER_RISING,
>> +                "lpass-irq-vaif", drvdata);
>> +        if (ret) {
>> +            dev_err(&pdev->dev, "va irq request failed: %d\n", ret);
>> +            return ret;
>> +        }
>> +
>> +        ret = lpass_platform_alloc_va_dmactl_fields(&pdev->dev,
>> +                         drvdata->va_lpaif_map);
>> +        if (ret) {
>> +            dev_err(&pdev->dev,
>> +                "error initializing va dmactl fields: %d\n", ret);
>> +            return ret;
>> +        }
>> +    }
>> +
>>       if (drvdata->hdmi_port_enable) {
>>           drvdata->hdmiif_irq = platform_get_irq_byname(pdev, 
>> "lpass-irq-hdmi");
>>           if (drvdata->hdmiif_irq < 0)
>>
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.,
is a member of Code Aurora Forum, a Linux Foundation Collaborative Project.


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2021-11-26 11:22 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-22 11:46 [PATCH v5 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivasa Rao Mandadapu
2021-11-22 11:46 ` Srinivasa Rao Mandadapu
2021-11-22 11:46 ` [PATCH v5 06/10] ASoC: qcom: Add support for codec dma driver Srinivasa Rao Mandadapu
2021-11-22 11:46   ` Srinivasa Rao Mandadapu
2021-11-23 12:28   ` Srinivas Kandagatla
2021-11-26 11:20     ` Srinivasa Rao Mandadapu
2021-11-22 11:46 ` [PATCH v5 07/10] ASoC: qcom: Add regmap config " Srinivasa Rao Mandadapu
2021-11-22 11:46   ` Srinivasa Rao Mandadapu
2021-11-22 11:46 ` [PATCH v5 08/10] ASoC: dt-bindings: Add SC7280 sound card bindings Srinivasa Rao Mandadapu
2021-11-22 11:46   ` Srinivasa Rao Mandadapu
2021-11-23 12:28   ` Srinivas Kandagatla
2021-11-23 16:34   ` Rob Herring
2021-11-23 16:34     ` Rob Herring
2021-11-22 11:46 ` [PATCH v5 09/10] ASoC: qcom: lpass-sc7280: Add platform driver for lpass audio Srinivasa Rao Mandadapu
2021-11-22 11:46   ` Srinivasa Rao Mandadapu
2021-11-23 12:28   ` Srinivas Kandagatla
2021-11-22 11:46 ` [PATCH v5 10/10] ASoC: qcom: SC7280: Update config for building codec dma drivers Srinivasa Rao Mandadapu
2021-11-22 11:46   ` Srinivasa Rao Mandadapu
2021-11-23 12:28 ` [PATCH v5 05/10] ASoC: qcom: Add helper function to get dma control and lpaif handle Srinivas Kandagatla

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.