From: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
To: Srinivas Kandagatla <srini@kernel.org>
Cc: Mark Brown <broonie@kernel.org>,
Liam Girdwood <lgirdwood@gmail.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
linux-sound@vger.kernel.org, linux-arm-msm@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 08/11] ASoC: qcom: Add QAIF PCM operations
Date: Wed, 1 Jul 2026 16:27:54 +0530 [thread overview]
Message-ID: <20260701105757.2779738-9-harendra.gautam@oss.qualcomm.com> (raw)
In-Reply-To: <20260701105757.2779738-1-harendra.gautam@oss.qualcomm.com>
Add PCM operation callbacks for the QAIF platform driver so AIF and CIF
DAIs can manage the DMA stream lifecycle.
The callbacks allocate and release stream DMA channels, set the ALSA
hardware constraints, manage the stream buffer, program the DMA registers
during prepare, enable or disable DMA and interrupts on trigger, report the
current DMA position to ALSA, and provide mmap support for userspace audio
buffers.
This completes the platform-side PCM support needed for QAIF playback and
capture streams.
Signed-off-by: Harendra Gautam <harendra.gautam@oss.qualcomm.com>
---
sound/soc/qcom/qaif-platform.c | 626 +++++++++++++++++++++++++++++++++
1 file changed, 626 insertions(+)
diff --git a/sound/soc/qcom/qaif-platform.c b/sound/soc/qcom/qaif-platform.c
index 12addfb85180..643def474aa0 100644
--- a/sound/soc/qcom/qaif-platform.c
+++ b/sound/soc/qcom/qaif-platform.c
@@ -290,2 +290,629 @@ static int qaif_init(struct snd_soc_component *component)
return 0;
}
+
+static int qaif_platform_pcmops_open(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct snd_dma_buffer *buf;
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ int ret, stream_dma_idx = -1, dir = substream->stream;
+ struct qaif_pcm_data *data;
+ struct qaif_dmactl *dmactl;
+ struct qaif_dma_mem_info *dma_mem_info = NULL;
+ struct regmap *map;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ runtime->private_data = data;
+ map = drvdata->audio_qaif_map;
+
+ dmactl = qaif_get_dmactl_handle(substream, component);
+ if (!dmactl) {
+ ret = -EINVAL;
+ goto err_dealloc_mem;
+ }
+
+ buf = &substream->dma_buffer;
+ buf->dev.dev = component->dev;
+ buf->private_data = NULL;
+ buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS;
+
+ dma_mem_info = qaif_mem_alloc_attach(component,
+ qaif_platform_aif_hardware.buffer_bytes_max);
+ if (!dma_mem_info) {
+ ret = -ENOMEM;
+ goto err_dealloc_mem;
+ }
+
+ ret = clk_prepare_enable(drvdata->aud_dma_clk);
+ if (ret) {
+ dev_err(soc_runtime->dev, "failed to enable aud_dma_clk: %d\n", ret);
+ goto err_dealloc_mem;
+ }
+
+ ret = clk_prepare_enable(drvdata->aud_dma_mem_clk);
+ if (ret) {
+ dev_err(soc_runtime->dev, "failed to enable aud_dma_mem_clk: %d\n", ret);
+ goto err_disable_dma_clk;
+ }
+
+ mutex_lock(&drvdata->stream_lock);
+ if (v->alloc_stream_dma_idx) {
+ stream_dma_idx = v->alloc_stream_dma_idx(drvdata, dir, dai_id);
+ } else {
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+
+ if (stream_dma_idx < 0) {
+ ret = stream_dma_idx;
+ goto err_unlock;
+ }
+
+ ret = qaif_init(component);
+ if (ret) {
+ dev_err(soc_runtime->dev, "qaif_init failed: %d\n", ret);
+ goto err_free_dma_idx;
+ }
+ drvdata->qaif_init_ref_cnt++;
+ mutex_unlock(&drvdata->stream_lock);
+
+ data->stream_dma_idx = stream_dma_idx;
+
+ switch (dai_id) {
+ case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12:
+ drvdata->aif_substream[stream_dma_idx] = substream;
+ drvdata->aif_dma_heap[stream_dma_idx] = dma_mem_info;
+ buf->bytes = qaif_platform_aif_hardware.buffer_bytes_max;
+ buf->addr = drvdata->aif_dma_heap[stream_dma_idx]->dma_addr;
+ buf->area = (unsigned char *)drvdata->aif_dma_heap[stream_dma_idx]->vaddr;
+
+ snd_soc_set_runtime_hwparams(substream, &qaif_platform_aif_hardware);
+ runtime->dma_bytes = qaif_platform_aif_hardware.buffer_bytes_max;
+ break;
+ case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9:
+ case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9:
+ case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9:
+ drvdata->cif_substream[stream_dma_idx] = substream;
+ drvdata->cif_dma_heap[stream_dma_idx] = dma_mem_info;
+ buf->bytes = qaif_platform_cif_hardware.buffer_bytes_max;
+ buf->addr = drvdata->cif_dma_heap[stream_dma_idx]->dma_addr;
+ buf->area = (unsigned char *)drvdata->cif_dma_heap[stream_dma_idx]->vaddr;
+
+ snd_soc_set_runtime_hwparams(substream, &qaif_platform_cif_hardware);
+ runtime->dma_bytes = qaif_platform_cif_hardware.buffer_bytes_max;
+ break;
+ default:
+ break;
+ }
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0) {
+ dev_err(soc_runtime->dev, "setting constraints failed: %d\n", ret);
+ if (is_cif_dma_port(dai_id)) {
+ drvdata->cif_substream[stream_dma_idx] = NULL;
+ drvdata->cif_dma_heap[stream_dma_idx] = NULL;
+ } else {
+ drvdata->aif_substream[stream_dma_idx] = NULL;
+ drvdata->aif_dma_heap[stream_dma_idx] = NULL;
+ }
+ mutex_lock(&drvdata->stream_lock);
+ drvdata->qaif_init_ref_cnt--;
+ if (v->free_stream_dma_idx)
+ v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id);
+ mutex_unlock(&drvdata->stream_lock);
+ goto err_disable_dma_mem_clk;
+ }
+
+ return 0;
+
+err_free_dma_idx:
+ if (v->free_stream_dma_idx)
+ v->free_stream_dma_idx(drvdata, stream_dma_idx, dai_id);
+err_unlock:
+ mutex_unlock(&drvdata->stream_lock);
+err_disable_dma_mem_clk:
+ clk_disable_unprepare(drvdata->aud_dma_mem_clk);
+err_disable_dma_clk:
+ clk_disable_unprepare(drvdata->aud_dma_clk);
+err_dealloc_mem:
+ qaif_mem_dealloc_detach(component->dev, dma_mem_info);
+ kfree(data);
+ return ret;
+}
+
+static int qaif_platform_pcmops_close(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ struct qaif_pcm_data *data;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ data = runtime->private_data;
+
+ switch (dai_id) {
+ case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12:
+ drvdata->aif_substream[data->stream_dma_idx] = NULL;
+ qaif_mem_dealloc_detach(component->dev,
+ drvdata->aif_dma_heap[data->stream_dma_idx]);
+ drvdata->aif_dma_heap[data->stream_dma_idx] = NULL;
+ break;
+ case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9:
+ case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9:
+ case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9:
+ drvdata->cif_substream[data->stream_dma_idx] = NULL;
+ qaif_mem_dealloc_detach(component->dev,
+ drvdata->cif_dma_heap[data->stream_dma_idx]);
+ drvdata->cif_dma_heap[data->stream_dma_idx] = NULL;
+ break;
+ default:
+ break;
+ }
+
+ mutex_lock(&drvdata->stream_lock);
+ if (drvdata->qaif_init_ref_cnt > 0)
+ drvdata->qaif_init_ref_cnt--;
+ else
+ dev_dbg(component->dev,
+ "%s: QAIF init ref cnt: %d, skipping decrement\n",
+ __func__, drvdata->qaif_init_ref_cnt);
+ if (v->free_stream_dma_idx)
+ v->free_stream_dma_idx(drvdata, data->stream_dma_idx, dai_id);
+ mutex_unlock(&drvdata->stream_lock);
+
+ clk_disable_unprepare(drvdata->aud_dma_clk);
+ clk_disable_unprepare(drvdata->aud_dma_mem_clk);
+ kfree(data);
+ return 0;
+}
+
+static int qaif_platform_pcmops_hw_params(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ struct qaif_dmactl *dmactl;
+ unsigned int dai_id = cpu_dai->driver->id;
+ int idx;
+ int ret;
+
+ dmactl = qaif_get_dmactl_handle(substream, component);
+ if (!dmactl)
+ return -EINVAL;
+ idx = v->get_dma_idx(dai_id);
+
+ if (idx < 0) {
+ dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ ret = regmap_fields_write(dmactl->burst4, idx, QAIF_DMACTL_BURSTEN);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error updating burst4 field: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_fields_write(dmactl->shram_wm, idx, QAIF_DMACTL_WM_5);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error updating shram_wm field: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qaif_platform_pcmops_hw_free(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ unsigned int reg;
+ int ret, idx;
+ unsigned int dai_id = cpu_dai->driver->id;
+ struct regmap *map = drvdata->audio_qaif_map;
+ struct qaif_dmactl *dmactl;
+
+ dmactl = qaif_get_dmactl_handle(substream, component);
+ if (!dmactl)
+ return -EINVAL;
+ idx = v->get_dma_idx(dai_id);
+
+ if (idx < 0) {
+ dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_OFF);
+ if (ret)
+ dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
+
+ reg = QAIF_DMACFG_REG(v, idx, substream->stream, dai_id);
+ ret = regmap_write(map, reg, 0);
+ if (ret)
+ dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", ret);
+
+ return ret;
+}
+
+static int qaif_platform_pcmops_prepare(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ struct qaif_dmactl *dmactl;
+ struct regmap *map;
+ int bitwidth = QAIF_DMA_DEFAULT_BIT_WIDTH;
+ unsigned int channels = runtime->channels;
+ unsigned int rate = runtime->rate;
+ int ret, idx, dir = substream->stream;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ dmactl = qaif_get_dmactl_handle(substream, component);
+ if (!dmactl)
+ return -EINVAL;
+ idx = v->get_dma_idx(dai_id);
+ map = drvdata->audio_qaif_map;
+
+ if (idx < 0) {
+ dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ clk_set_rate(drvdata->aud_dma_clk, QAIF_DMA_CLOCK_FREQ);
+ clk_set_rate(drvdata->aud_dma_mem_clk, QAIF_DMA_CLOCK_FREQ);
+ dev_dbg(soc_runtime->dev,
+ "setting aud_dma_clk & aud_dma_mem_clk to %u\n",
+ QAIF_DMA_CLOCK_FREQ);
+
+ ret = regmap_write(map, QAIF_SID_MAP_REG(dir, dai_id),
+ drvdata->smmu_csid_bits);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error writing to SID MAP reg: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regmap_write(map, QAIF_DMABASE_REG(v, idx, dir, dai_id),
+ runtime->dma_addr);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regmap_write(map, QAIF_DMABUFF_REG(v, idx, dir, dai_id),
+ (snd_pcm_lib_buffer_bytes(substream) >>
+ QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = regmap_write(map, QAIF_DMAPER_LEN_REG(v, idx, dir, dai_id),
+ (snd_pcm_lib_period_bytes(substream) >>
+ QAIF_DMA_BYTES_TO_WORDS_SHIFT) - 1);
+ if (ret) {
+ dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int qaif_platform_irq_clear(struct qaif_drv_data *drvdata,
+ int dir,
+ enum qaif_irq_type irq_type,
+ int idx)
+{
+ int ret = 0;
+ const struct qaif_variant *v = drvdata->variant;
+ struct regmap *map = drvdata->audio_qaif_map;
+ unsigned int val_irqclr = BIT(idx);
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret |= regmap_write(map, QAIF_EE_RDDMA_PERIOD_IRQ_CLR_REG(v, irq_type), val_irqclr);
+ ret |= regmap_write(map,
+ QAIF_EE_RDDMA_UNDERFLOW_IRQ_CLR_REG(v, irq_type),
+ val_irqclr);
+ ret |= regmap_write(map,
+ QAIF_EE_RDDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type),
+ val_irqclr);
+ } else {
+ ret |= regmap_write(map, QAIF_EE_WRDMA_PERIOD_IRQ_CLR_REG(v, irq_type), val_irqclr);
+ ret |= regmap_write(map,
+ QAIF_EE_WRDMA_OVERFLOW_IRQ_CLR_REG(v, irq_type),
+ val_irqclr);
+ ret |= regmap_write(map,
+ QAIF_EE_WRDMA_ERR_RSP_IRQ_CLR_REG(v, irq_type),
+ val_irqclr);
+ }
+ return ret;
+}
+
+static int qaif_platform_irq_enable(struct qaif_drv_data *drvdata,
+ int dir,
+ enum qaif_irq_type irq_type,
+ int idx)
+{
+ int ret = 0;
+ const struct qaif_variant *v = drvdata->variant;
+ struct regmap *map = drvdata->audio_qaif_map;
+ unsigned int val_irqen = BIT(idx);
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ } else {
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, irq_type),
+ val_irqen, val_irqen);
+ }
+ return ret;
+}
+
+static int qaif_platform_irq_disable(struct qaif_drv_data *drvdata,
+ int dir,
+ enum qaif_irq_type irq_type,
+ int idx)
+{
+ int ret = 0;
+ const struct qaif_variant *v = drvdata->variant;
+ struct regmap *map = drvdata->audio_qaif_map;
+ unsigned int val_irq_disable = BIT(idx);
+
+ if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_PERIOD_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_UNDERFLOW_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_RDDMA_ERR_RSP_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ } else {
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_PERIOD_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_OVERFLOW_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ ret |= regmap_write_bits(map,
+ QAIF_EE_WRDMA_ERR_RSP_IRQ_EN_REG(v, irq_type),
+ val_irq_disable, 0);
+ }
+ return ret;
+}
+
+static int qaif_platform_pcmops_trigger(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ struct qaif_dmactl *dmactl;
+ struct regmap *map;
+ int ret, idx;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ dmactl = qaif_get_dmactl_handle(substream, component);
+ if (!dmactl)
+ return -EINVAL;
+ idx = v->get_dma_idx(dai_id);
+ map = drvdata->audio_qaif_map;
+
+ if (idx < 0) {
+ dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = regmap_fields_write(dmactl->dma_dyncclk, idx, QAIF_DMACTL_DYNCLK_ON);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to dma_dyncclk reg field: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_ON);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to dma enable reg: %d\n", ret);
+ return ret;
+ }
+ switch (dai_id) {
+ case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12:
+ ret = qaif_platform_irq_clear(drvdata,
+ substream->stream,
+ QAIF_AIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to clear irq reg: %d\n", ret);
+ return ret;
+ }
+ ret = qaif_platform_irq_enable(drvdata,
+ substream->stream,
+ QAIF_AIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to enable irq reg: %d\n", ret);
+ return ret;
+ }
+ break;
+ case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9:
+ case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9:
+ case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9:
+ ret = qaif_platform_irq_clear(drvdata,
+ substream->stream,
+ QAIF_CIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to clear irq reg: %d\n", ret);
+ return ret;
+ }
+ ret = qaif_platform_irq_enable(drvdata,
+ substream->stream,
+ QAIF_CIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to enable irq reg: %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
+ return -EINVAL;
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = regmap_fields_write(dmactl->dma_dyncclk, idx, QAIF_DMACTL_DYNCLK_OFF);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to dma_dyncclk reg field: %d\n", ret);
+ return ret;
+ }
+ ret = regmap_fields_write(dmactl->enable, idx, QAIF_DMACTL_ENABLE_OFF);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to dma enable reg: %d\n", ret);
+ return ret;
+ }
+ switch (dai_id) {
+ case QAIF_MI2S_TDM_AIF0 ... QAIF_MI2S_TDM_AIF12:
+ ret = qaif_platform_irq_disable(drvdata,
+ substream->stream,
+ QAIF_AIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to enable irq reg: %d\n", ret);
+ return ret;
+ }
+ break;
+ case QAIF_CDC_DMA_RX0 ... QAIF_CDC_DMA_RX9:
+ case QAIF_CDC_DMA_TX0 ... QAIF_CDC_DMA_TX9:
+ case QAIF_CDC_DMA_VA_TX0 ... QAIF_CDC_DMA_VA_TX9:
+ ret = qaif_platform_irq_disable(drvdata,
+ substream->stream,
+ QAIF_CIF_IRQ, idx);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error writing to enable irq reg: %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
+ dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static snd_pcm_uframes_t qaif_platform_pcmops_pointer(struct snd_soc_component *component,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ struct qaif_drv_data *drvdata = snd_soc_component_get_drvdata(component);
+ const struct qaif_variant *v = drvdata->variant;
+ unsigned int base_addr, curr_addr;
+ int ret, idx, dir = substream->stream;
+ struct regmap *map;
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ map = drvdata->audio_qaif_map;
+ idx = v->get_dma_idx(dai_id);
+
+ if (idx < 0) {
+ dev_err(soc_runtime->dev, "%s: Invalid DMA index: %d\n", __func__, idx);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(map,
+ QAIF_DMABASE_REG(v, idx, dir, dai_id),
+ &base_addr);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error reading from rdmabase reg: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(map,
+ QAIF_DMACURR_REG(v, idx, dir, dai_id),
+ &curr_addr);
+ if (ret) {
+ dev_err(soc_runtime->dev,
+ "error reading from rdmacurr reg: %d\n", ret);
+ return ret;
+ }
+
+ return bytes_to_frames(substream->runtime, curr_addr - base_addr);
+}
+
+static int qaif_platform_cdc_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_coherent(substream->pcm->card->dev, vma,
+ runtime->dma_area, runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static int qaif_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 = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_runtime, 0);
+ unsigned int dai_id = cpu_dai->driver->id;
+
+ if (is_cif_dma_port(dai_id))
+ return qaif_platform_cdc_dma_mmap(substream, vma);
+
+ return snd_pcm_lib_default_mmap(substream, vma);
+}
--
2.34.1
next prev parent reply other threads:[~2026-07-01 10:58 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-01 10:57 [PATCH v2 00/11] ASoC: qcom: Add QAIF driver for Shikra audio platform Harendra Gautam
2026-07-01 10:57 ` [PATCH v2 01/11] dt-bindings: sound: qcom,qaif-cpu: Add binding Harendra Gautam
2026-07-01 11:04 ` Konrad Dybcio
2026-07-02 6:52 ` Krzysztof Kozlowski
2026-07-01 11:09 ` sashiko-bot
2026-07-01 11:19 ` Mark Brown
2026-07-01 12:26 ` Mark Brown
2026-07-02 6:50 ` Krzysztof Kozlowski
2026-07-01 10:57 ` [PATCH v2 02/11] ASoC: qcom: Add QAIF hardware register map Harendra Gautam
2026-07-01 10:57 ` [PATCH v2 03/11] ASoC: qcom: Add QAIF shared data structures and variant interface Harendra Gautam
2026-07-01 11:26 ` sashiko-bot
2026-07-01 10:57 ` [PATCH v2 04/11] ASoC: qcom: Add QAIF CIF (CDC DMA) DAI ops Harendra Gautam
2026-07-01 11:09 ` sashiko-bot
2026-07-01 10:57 ` [PATCH v2 05/11] ASoC: qcom: Add QAIF AIF " Harendra Gautam
2026-07-01 11:14 ` sashiko-bot
2026-07-01 10:57 ` [PATCH v2 06/11] ASoC: qcom: Add generic of_xlate_dai_name helper and use it in lpass-cpu and qaif-cpu Harendra Gautam
2026-07-01 11:11 ` sashiko-bot
2026-07-02 7:12 ` Krzysztof Kozlowski
2026-07-01 10:57 ` [PATCH v2 07/11] ASoC: qcom: Add QAIF regmap, DT parsing and platform init Harendra Gautam
2026-07-01 11:11 ` sashiko-bot
2026-07-02 7:07 ` Krzysztof Kozlowski
2026-07-01 10:57 ` Harendra Gautam [this message]
2026-07-01 11:12 ` [PATCH v2 08/11] ASoC: qcom: Add QAIF PCM operations sashiko-bot
2026-07-01 10:57 ` [PATCH v2 09/11] ASoC: qcom: Add QAIF IRQ handling, suspend/resume and platform register Harendra Gautam
2026-07-01 11:27 ` sashiko-bot
2026-07-01 10:57 ` [PATCH v2 10/11] ASoC: qcom: Add Shikra QAIF support Harendra Gautam
2026-07-01 11:22 ` sashiko-bot
2026-07-02 7:01 ` Krzysztof Kozlowski
2026-07-01 10:57 ` [PATCH v2 11/11] MAINTAINERS: Add Qualcomm QAIF driver entry Harendra Gautam
2026-07-02 6:58 ` [PATCH v2 00/11] ASoC: qcom: Add QAIF driver for Shikra audio platform Krzysztof Kozlowski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260701105757.2779738-9-harendra.gautam@oss.qualcomm.com \
--to=harendra.gautam@oss.qualcomm.com \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sound@vger.kernel.org \
--cc=robh@kernel.org \
--cc=srini@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox