All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Ujfalusi <peter.ujfalusi@ti.com>
To: Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Liam Girdwood <lrg@ti.com>, Tony Lindgren <tony@atomide.com>,
	Russell King <rmk+kernel@arm.linux.org.uk>,
	Vinod Koul <vinod.koul@intel.com>, Dan Williams <djbw@fb.com>,
	Jarkko Nikula <jarkko.nikula@bitmer.com>
Cc: alsa-devel@alsa-project.org, linux-omap@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,
	Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>,
	Ricardo Neri <ricardo.neri@ti.com>
Subject: [PATCH 11/11] ASoC: omap-pcm: Convert to use dmaengine
Date: Wed, 12 Sep 2012 14:47:07 +0300	[thread overview]
Message-ID: <1347450427-27627-12-git-send-email-peter.ujfalusi@ti.com> (raw)
In-Reply-To: <1347450427-27627-1-git-send-email-peter.ujfalusi@ti.com>

Original author: Russell King <rmk+kernel@arm.linux.org.uk>

Switch the omap-pcm to use dmaengine.
Certain features are not supported by after dmaengine conversion:
1. No period wakeup mode
   DMA engine has no way to communicate this information through
   standard channels.

2. Pause/Resume
   OMAP DMA engine backend does not support pausing and resuming
   an in-progress transfer.  It is unclear from the specs what
   effect clearing the enable bit has on the DMA position of a
   destination synchronized transfer, and whether the transfer
   can be restarted from the exact point that it was paused (or
   whether the data in the FIFO read from memory is simply
   discarded.)

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
CC: Russell King <rmk+kernel@arm.linux.org.uk>
---
 sound/soc/omap/Kconfig    |   3 +-
 sound/soc/omap/omap-pcm.c | 279 +++++++++++-----------------------------------
 2 files changed, 67 insertions(+), 215 deletions(-)

diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 2c484a5..7048137 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,6 +1,7 @@
 config SND_OMAP_SOC
 	tristate "SoC Audio for the Texas Instruments OMAP chips"
-	depends on ARCH_OMAP
+	depends on ARCH_OMAP && DMA_OMAP
+	select SND_SOC_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
 	tristate
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 74da4b7..eb68c9e 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -25,21 +25,24 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/omap-dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 
-#include <plat/dma.h>
 #include "omap-pcm.h"
 
 static const struct snd_pcm_hardware omap_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME |
-				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+				  SNDRV_PCM_INFO_INTERLEAVED,
+				  /*
+				   * TODO: support for
+				   * SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
+				   * via dmaengine.
+				   */
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 				  SNDRV_PCM_FMTBIT_S32_LE,
 	.period_bytes_min	= 32,
@@ -49,61 +52,34 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
 	.buffer_bytes_max	= 128 * 1024,
 };
 
-struct omap_runtime_data {
-	spinlock_t			lock;
-	struct omap_pcm_dma_data	*dma_data;
-	int				dma_ch;
-	int				period_index;
-};
-
-static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
+static int omap_pcm_get_dma_buswidth(int num_bits)
 {
-	struct snd_pcm_substream *substream = data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	unsigned long flags;
-
-	if ((cpu_is_omap1510())) {
-		/*
-		 * OMAP1510 doesn't fully support DMA progress counter
-		 * and there is no software emulation implemented yet,
-		 * so have to maintain our own progress counters
-		 * that can be used by omap_pcm_pointer() instead.
-		 */
-		spin_lock_irqsave(&prtd->lock, flags);
-		if ((stat == OMAP_DMA_LAST_IRQ) &&
-				(prtd->period_index == runtime->periods - 1)) {
-			/* we are in sync, do nothing */
-			spin_unlock_irqrestore(&prtd->lock, flags);
-			return;
-		}
-		if (prtd->period_index >= 0) {
-			if (stat & OMAP_DMA_BLOCK_IRQ) {
-				/* end of buffer reached, loop back */
-				prtd->period_index = 0;
-			} else if (stat & OMAP_DMA_LAST_IRQ) {
-				/* update the counter for the last period */
-				prtd->period_index = runtime->periods - 1;
-			} else if (++prtd->period_index >= runtime->periods) {
-				/* end of buffer missed? loop back */
-				prtd->period_index = 0;
-			}
-		}
-		spin_unlock_irqrestore(&prtd->lock, flags);
-	}
+	int buswidth;
 
-	snd_pcm_period_elapsed(substream);
+	switch (num_bits) {
+	case 16:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case 32:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	default:
+		buswidth = -EINVAL;
+		break;
+	}
+	return buswidth;
 }
 
+
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *params)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct omap_runtime_data *prtd = runtime->private_data;
 	struct omap_pcm_dma_data *dma_data;
-
+	struct dma_slave_config config;
+	struct dma_chan *chan;
 	int err = 0;
 
 	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -116,195 +92,78 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	runtime->dma_bytes = params_buffer_bytes(params);
 
-	if (prtd->dma_data)
-		return 0;
-	prtd->dma_data = dma_data;
-	err = omap_request_dma(dma_data->dma_req, dma_data->name,
-			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
-	if (!err) {
-		/*
-		 * Link channel with itself so DMA doesn't need any
-		 * reprogramming while looping the buffer
-		 */
-		omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
-	}
-
-	return err;
-}
-
-static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-
-	if (prtd->dma_data == NULL)
-		return 0;
+	chan = snd_dmaengine_pcm_get_chan(substream);
+	if (!chan)
+		return -EINVAL;
 
-	omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
-	omap_free_dma(prtd->dma_ch);
-	prtd->dma_data = NULL;
+	/* fills in addr_width and direction */
+	err = snd_hwparams_to_dma_slave_config(substream, params, &config);
+	if (err)
+		return err;
 
-	snd_pcm_set_runtime_buffer(substream, NULL);
+	/* Override the *_dma addr_width if requested by the DAI driver */
+	if (dma_data->data_type) {
+		int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
 
-	return 0;
-}
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			config.dst_addr_width = buswidth;
+		else
+			config.src_addr_width = buswidth;
+	}
 
-static int omap_pcm_get_dma_type(int num_bits)
-{
-	int data_type;
+	config.src_addr = dma_data->port_addr;
+	config.dst_addr = dma_data->port_addr;
+	config.src_maxburst = dma_data->packet_size;
+	config.dst_maxburst = dma_data->packet_size;
 
-	switch (num_bits) {
-	case 16:
-		data_type = OMAP_DMA_DATA_TYPE_S16;
-		break;
-	case 32:
-		data_type = OMAP_DMA_DATA_TYPE_S32;
-		break;
-	default:
-		data_type = -EINVAL;
-		break;
-	}
-	return data_type;
+	return dmaengine_slave_config(chan, &config);
 }
 
-static int omap_pcm_prepare(struct snd_pcm_substream *substream)
+static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-	struct omap_dma_channel_params dma_params;
-	int bytes;
-
-	/* return if this is a bufferless transfer e.g.
-	 * codec <--> BT codec or GSM modem -- lg FIXME */
-	if (!prtd->dma_data)
-		return 0;
-
-	memset(&dma_params, 0, sizeof(dma_params));
-
-	if (dma_data->data_type)
-		dma_params.data_type = omap_pcm_get_dma_type(
-				dma_data->data_type);
-	else
-		dma_params.data_type = omap_pcm_get_dma_type(
-				snd_pcm_format_physical_width(runtime->format));
-
-	if (dma_params.data_type < 0)
-		return dma_params.data_type;
-
-	dma_params.trigger			= dma_data->dma_req;
-
-	if (dma_data->packet_size)
-		dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
-	else
-		dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		dma_params.src_amode		= OMAP_DMA_AMODE_POST_INC;
-		dma_params.dst_amode		= OMAP_DMA_AMODE_CONSTANT;
-		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC;
-		dma_params.src_start		= runtime->dma_addr;
-		dma_params.dst_start		= dma_data->port_addr;
-		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
-		dma_params.dst_fi		= dma_data->packet_size;
-	} else {
-		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
-		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
-		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC;
-		dma_params.src_start		= dma_data->port_addr;
-		dma_params.dst_start		= runtime->dma_addr;
-		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
-		dma_params.src_fi		= dma_data->packet_size;
-	}
-	/*
-	 * Set DMA transfer frame size equal to ALSA period size and frame
-	 * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
-	 * we can transfer the whole ALSA buffer with single DMA transfer but
-	 * still can get an interrupt at each period bounary
-	 */
-	bytes = snd_pcm_lib_period_bytes(substream);
-	dma_params.elem_count	= bytes >> dma_params.data_type;
-	dma_params.frame_count	= runtime->periods;
-	omap_set_dma_params(prtd->dma_ch, &dma_params);
-
-	if ((cpu_is_omap1510()))
-		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
-			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-	else if (!substream->runtime->no_period_wakeup)
-		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
-	else {
-		/*
-		 * No period wakeup:
-		 * we need to disable BLOCK_IRQ, which is enabled by the omap
-		 * dma core at request dma time.
-		 */
-		omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
-	}
-
-	if (!(cpu_class_is_omap1())) {
-		omap_set_dma_src_burst_mode(prtd->dma_ch,
-						OMAP_DMA_DATA_BURST_16);
-		omap_set_dma_dest_burst_mode(prtd->dma_ch,
-						OMAP_DMA_DATA_BURST_16);
-	}
-
+	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
 }
 
 static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-	unsigned long flags;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct omap_pcm_dma_data *dma_data;
 	int ret = 0;
 
-	spin_lock_irqsave(&prtd->lock, flags);
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		prtd->period_index = 0;
 		/* Configure McBSP internal buffer usage */
 		if (dma_data->set_threshold)
 			dma_data->set_threshold(substream);
-
-		omap_start_dma(prtd->dma_ch);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		prtd->period_index = -1;
-		omap_stop_dma(prtd->dma_ch);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	if (ret == 0)
+		ret = snd_dmaengine_pcm_trigger(substream, cmd);
 
 	return ret;
 }
 
 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	dma_addr_t ptr;
 	snd_pcm_uframes_t offset;
 
-	if (cpu_is_omap1510()) {
-		offset = prtd->period_index * runtime->period_size;
-	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ptr = omap_get_dma_dst_pos(prtd->dma_ch);
-		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-	} else {
-		ptr = omap_get_dma_src_pos(prtd->dma_ch);
-		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-	}
-
-	if (offset >= runtime->buffer_size)
-		offset = 0;
+	if (cpu_is_omap1510())
+		offset = snd_dmaengine_pcm_pointer_no_residue(substream);
+	else
+		offset = snd_dmaengine_pcm_pointer(substream);
 
 	return offset;
 }
@@ -312,7 +171,8 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 static int omap_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct omap_pcm_dma_data *dma_data;
 	int ret;
 
 	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
@@ -321,25 +181,17 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
 	ret = snd_pcm_hw_constraint_integer(runtime,
 					    SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0)
-		goto out;
-
-	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-	if (prtd == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	spin_lock_init(&prtd->lock);
-	runtime->private_data = prtd;
+		return ret;
 
-out:
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
+				     &dma_data->dma_req);
 	return ret;
 }
 
 static int omap_pcm_close(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	kfree(runtime->private_data);
+	snd_dmaengine_pcm_close(substream);
 	return 0;
 }
 
@@ -360,7 +212,6 @@ static struct snd_pcm_ops omap_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= omap_pcm_hw_params,
 	.hw_free	= omap_pcm_hw_free,
-	.prepare	= omap_pcm_prepare,
 	.trigger	= omap_pcm_trigger,
 	.pointer	= omap_pcm_pointer,
 	.mmap		= omap_pcm_mmap,
-- 
1.7.12


WARNING: multiple messages have this Message-ID (diff)
From: peter.ujfalusi@ti.com (Peter Ujfalusi)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 11/11] ASoC: omap-pcm: Convert to use dmaengine
Date: Wed, 12 Sep 2012 14:47:07 +0300	[thread overview]
Message-ID: <1347450427-27627-12-git-send-email-peter.ujfalusi@ti.com> (raw)
In-Reply-To: <1347450427-27627-1-git-send-email-peter.ujfalusi@ti.com>

Original author: Russell King <rmk+kernel@arm.linux.org.uk>

Switch the omap-pcm to use dmaengine.
Certain features are not supported by after dmaengine conversion:
1. No period wakeup mode
   DMA engine has no way to communicate this information through
   standard channels.

2. Pause/Resume
   OMAP DMA engine backend does not support pausing and resuming
   an in-progress transfer.  It is unclear from the specs what
   effect clearing the enable bit has on the DMA position of a
   destination synchronized transfer, and whether the transfer
   can be restarted from the exact point that it was paused (or
   whether the data in the FIFO read from memory is simply
   discarded.)

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
CC: Russell King <rmk+kernel@arm.linux.org.uk>
---
 sound/soc/omap/Kconfig    |   3 +-
 sound/soc/omap/omap-pcm.c | 279 +++++++++++-----------------------------------
 2 files changed, 67 insertions(+), 215 deletions(-)

diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 2c484a5..7048137 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -1,6 +1,7 @@
 config SND_OMAP_SOC
 	tristate "SoC Audio for the Texas Instruments OMAP chips"
-	depends on ARCH_OMAP
+	depends on ARCH_OMAP && DMA_OMAP
+	select SND_SOC_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
 	tristate
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 74da4b7..eb68c9e 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -25,21 +25,24 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/omap-dma.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 
-#include <plat/dma.h>
 #include "omap-pcm.h"
 
 static const struct snd_pcm_hardware omap_pcm_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
-				  SNDRV_PCM_INFO_INTERLEAVED |
-				  SNDRV_PCM_INFO_PAUSE |
-				  SNDRV_PCM_INFO_RESUME |
-				  SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
+				  SNDRV_PCM_INFO_INTERLEAVED,
+				  /*
+				   * TODO: support for
+				   * SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
+				   * via dmaengine.
+				   */
 	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
 				  SNDRV_PCM_FMTBIT_S32_LE,
 	.period_bytes_min	= 32,
@@ -49,61 +52,34 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
 	.buffer_bytes_max	= 128 * 1024,
 };
 
-struct omap_runtime_data {
-	spinlock_t			lock;
-	struct omap_pcm_dma_data	*dma_data;
-	int				dma_ch;
-	int				period_index;
-};
-
-static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
+static int omap_pcm_get_dma_buswidth(int num_bits)
 {
-	struct snd_pcm_substream *substream = data;
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	unsigned long flags;
-
-	if ((cpu_is_omap1510())) {
-		/*
-		 * OMAP1510 doesn't fully support DMA progress counter
-		 * and there is no software emulation implemented yet,
-		 * so have to maintain our own progress counters
-		 * that can be used by omap_pcm_pointer() instead.
-		 */
-		spin_lock_irqsave(&prtd->lock, flags);
-		if ((stat == OMAP_DMA_LAST_IRQ) &&
-				(prtd->period_index == runtime->periods - 1)) {
-			/* we are in sync, do nothing */
-			spin_unlock_irqrestore(&prtd->lock, flags);
-			return;
-		}
-		if (prtd->period_index >= 0) {
-			if (stat & OMAP_DMA_BLOCK_IRQ) {
-				/* end of buffer reached, loop back */
-				prtd->period_index = 0;
-			} else if (stat & OMAP_DMA_LAST_IRQ) {
-				/* update the counter for the last period */
-				prtd->period_index = runtime->periods - 1;
-			} else if (++prtd->period_index >= runtime->periods) {
-				/* end of buffer missed? loop back */
-				prtd->period_index = 0;
-			}
-		}
-		spin_unlock_irqrestore(&prtd->lock, flags);
-	}
+	int buswidth;
 
-	snd_pcm_period_elapsed(substream);
+	switch (num_bits) {
+	case 16:
+		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
+		break;
+	case 32:
+		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
+		break;
+	default:
+		buswidth = -EINVAL;
+		break;
+	}
+	return buswidth;
 }
 
+
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 			      struct snd_pcm_hw_params *params)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct omap_runtime_data *prtd = runtime->private_data;
 	struct omap_pcm_dma_data *dma_data;
-
+	struct dma_slave_config config;
+	struct dma_chan *chan;
 	int err = 0;
 
 	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -116,195 +92,78 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	runtime->dma_bytes = params_buffer_bytes(params);
 
-	if (prtd->dma_data)
-		return 0;
-	prtd->dma_data = dma_data;
-	err = omap_request_dma(dma_data->dma_req, dma_data->name,
-			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
-	if (!err) {
-		/*
-		 * Link channel with itself so DMA doesn't need any
-		 * reprogramming while looping the buffer
-		 */
-		omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
-	}
-
-	return err;
-}
-
-static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
-{
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-
-	if (prtd->dma_data == NULL)
-		return 0;
+	chan = snd_dmaengine_pcm_get_chan(substream);
+	if (!chan)
+		return -EINVAL;
 
-	omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
-	omap_free_dma(prtd->dma_ch);
-	prtd->dma_data = NULL;
+	/* fills in addr_width and direction */
+	err = snd_hwparams_to_dma_slave_config(substream, params, &config);
+	if (err)
+		return err;
 
-	snd_pcm_set_runtime_buffer(substream, NULL);
+	/* Override the *_dma addr_width if requested by the DAI driver */
+	if (dma_data->data_type) {
+		int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
 
-	return 0;
-}
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			config.dst_addr_width = buswidth;
+		else
+			config.src_addr_width = buswidth;
+	}
 
-static int omap_pcm_get_dma_type(int num_bits)
-{
-	int data_type;
+	config.src_addr = dma_data->port_addr;
+	config.dst_addr = dma_data->port_addr;
+	config.src_maxburst = dma_data->packet_size;
+	config.dst_maxburst = dma_data->packet_size;
 
-	switch (num_bits) {
-	case 16:
-		data_type = OMAP_DMA_DATA_TYPE_S16;
-		break;
-	case 32:
-		data_type = OMAP_DMA_DATA_TYPE_S32;
-		break;
-	default:
-		data_type = -EINVAL;
-		break;
-	}
-	return data_type;
+	return dmaengine_slave_config(chan, &config);
 }
 
-static int omap_pcm_prepare(struct snd_pcm_substream *substream)
+static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-	struct omap_dma_channel_params dma_params;
-	int bytes;
-
-	/* return if this is a bufferless transfer e.g.
-	 * codec <--> BT codec or GSM modem -- lg FIXME */
-	if (!prtd->dma_data)
-		return 0;
-
-	memset(&dma_params, 0, sizeof(dma_params));
-
-	if (dma_data->data_type)
-		dma_params.data_type = omap_pcm_get_dma_type(
-				dma_data->data_type);
-	else
-		dma_params.data_type = omap_pcm_get_dma_type(
-				snd_pcm_format_physical_width(runtime->format));
-
-	if (dma_params.data_type < 0)
-		return dma_params.data_type;
-
-	dma_params.trigger			= dma_data->dma_req;
-
-	if (dma_data->packet_size)
-		dma_params.sync_mode = OMAP_DMA_SYNC_PACKET;
-	else
-		dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT;
-
-	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		dma_params.src_amode		= OMAP_DMA_AMODE_POST_INC;
-		dma_params.dst_amode		= OMAP_DMA_AMODE_CONSTANT;
-		dma_params.src_or_dst_synch	= OMAP_DMA_DST_SYNC;
-		dma_params.src_start		= runtime->dma_addr;
-		dma_params.dst_start		= dma_data->port_addr;
-		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
-		dma_params.dst_fi		= dma_data->packet_size;
-	} else {
-		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
-		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
-		dma_params.src_or_dst_synch	= OMAP_DMA_SRC_SYNC;
-		dma_params.src_start		= dma_data->port_addr;
-		dma_params.dst_start		= runtime->dma_addr;
-		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
-		dma_params.src_fi		= dma_data->packet_size;
-	}
-	/*
-	 * Set DMA transfer frame size equal to ALSA period size and frame
-	 * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
-	 * we can transfer the whole ALSA buffer with single DMA transfer but
-	 * still can get an interrupt at each period bounary
-	 */
-	bytes = snd_pcm_lib_period_bytes(substream);
-	dma_params.elem_count	= bytes >> dma_params.data_type;
-	dma_params.frame_count	= runtime->periods;
-	omap_set_dma_params(prtd->dma_ch, &dma_params);
-
-	if ((cpu_is_omap1510()))
-		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ |
-			      OMAP_DMA_LAST_IRQ | OMAP_DMA_BLOCK_IRQ);
-	else if (!substream->runtime->no_period_wakeup)
-		omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
-	else {
-		/*
-		 * No period wakeup:
-		 * we need to disable BLOCK_IRQ, which is enabled by the omap
-		 * dma core at request dma time.
-		 */
-		omap_disable_dma_irq(prtd->dma_ch, OMAP_DMA_BLOCK_IRQ);
-	}
-
-	if (!(cpu_class_is_omap1())) {
-		omap_set_dma_src_burst_mode(prtd->dma_ch,
-						OMAP_DMA_DATA_BURST_16);
-		omap_set_dma_dest_burst_mode(prtd->dma_ch,
-						OMAP_DMA_DATA_BURST_16);
-	}
-
+	snd_pcm_set_runtime_buffer(substream, NULL);
 	return 0;
 }
 
 static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	struct omap_pcm_dma_data *dma_data = prtd->dma_data;
-	unsigned long flags;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct omap_pcm_dma_data *dma_data;
 	int ret = 0;
 
-	spin_lock_irqsave(&prtd->lock, flags);
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		prtd->period_index = 0;
 		/* Configure McBSP internal buffer usage */
 		if (dma_data->set_threshold)
 			dma_data->set_threshold(substream);
-
-		omap_start_dma(prtd->dma_ch);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		prtd->period_index = -1;
-		omap_stop_dma(prtd->dma_ch);
 		break;
 	default:
 		ret = -EINVAL;
 	}
-	spin_unlock_irqrestore(&prtd->lock, flags);
+
+	if (ret == 0)
+		ret = snd_dmaengine_pcm_trigger(substream, cmd);
 
 	return ret;
 }
 
 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd = runtime->private_data;
-	dma_addr_t ptr;
 	snd_pcm_uframes_t offset;
 
-	if (cpu_is_omap1510()) {
-		offset = prtd->period_index * runtime->period_size;
-	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ptr = omap_get_dma_dst_pos(prtd->dma_ch);
-		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-	} else {
-		ptr = omap_get_dma_src_pos(prtd->dma_ch);
-		offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
-	}
-
-	if (offset >= runtime->buffer_size)
-		offset = 0;
+	if (cpu_is_omap1510())
+		offset = snd_dmaengine_pcm_pointer_no_residue(substream);
+	else
+		offset = snd_dmaengine_pcm_pointer(substream);
 
 	return offset;
 }
@@ -312,7 +171,8 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 static int omap_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct omap_runtime_data *prtd;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct omap_pcm_dma_data *dma_data;
 	int ret;
 
 	snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
@@ -321,25 +181,17 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
 	ret = snd_pcm_hw_constraint_integer(runtime,
 					    SNDRV_PCM_HW_PARAM_PERIODS);
 	if (ret < 0)
-		goto out;
-
-	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
-	if (prtd == NULL) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	spin_lock_init(&prtd->lock);
-	runtime->private_data = prtd;
+		return ret;
 
-out:
+	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
+	ret = snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
+				     &dma_data->dma_req);
 	return ret;
 }
 
 static int omap_pcm_close(struct snd_pcm_substream *substream)
 {
-	struct snd_pcm_runtime *runtime = substream->runtime;
-
-	kfree(runtime->private_data);
+	snd_dmaengine_pcm_close(substream);
 	return 0;
 }
 
@@ -360,7 +212,6 @@ static struct snd_pcm_ops omap_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= omap_pcm_hw_params,
 	.hw_free	= omap_pcm_hw_free,
-	.prepare	= omap_pcm_prepare,
 	.trigger	= omap_pcm_trigger,
 	.pointer	= omap_pcm_pointer,
 	.mmap		= omap_pcm_mmap,
-- 
1.7.12

  parent reply	other threads:[~2012-09-12 11:47 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-09-12 11:46 [PATCH 00/11] ASoC: OMAP: Convert to use dmaengine Peter Ujfalusi
2012-09-12 11:46 ` Peter Ujfalusi
2012-09-12 11:46 ` [PATCH 01/11] dmaengine: omap: Support for element mode in cyclic DMA Peter Ujfalusi
2012-09-12 11:46   ` Peter Ujfalusi
2012-09-12 11:46   ` Peter Ujfalusi
2012-09-12 11:46 ` [PATCH 02/11] ASoC: omap-mcbsp: Use sDMA packet mode instead of frame mode Peter Ujfalusi
2012-09-12 11:46   ` Peter Ujfalusi
2012-09-12 11:46 ` [PATCH 03/11] ASoC: omap-pcm: Select sDMA synchronization based on packet_size Peter Ujfalusi
2012-09-12 11:46   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 04/11] ASoC: OMAP: Remove sync_mode from omap_pcm_dma_data struct Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 05/11] ASoC: omap-pcm: Prepare to configure the DMA data_type based on stream properties Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 06/11] ARM: OMAP4: hwmod_data: Add resource names to McPDM memory ranges Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 07/11] ASoC: omap-mcpdm: Use platform_get_resource_* to get resources Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 08/11] ASoC: OMAP: mcbsp, mcpdm, dmic: Let omap-pcm to pick the dma_type Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 09/11] ASoC: omap-pcm, omap-hdmi: Change the use of omap_pcm_dma_data->data_type Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` [PATCH 10/11] ASoC: OMAP: mcbsp, mcpdm, dmic, hdmi: Set dma_data at startup time Peter Ujfalusi
2012-09-12 11:47   ` Peter Ujfalusi
2012-09-12 11:47 ` Peter Ujfalusi [this message]
2012-09-12 11:47   ` [PATCH 11/11] ASoC: omap-pcm: Convert to use dmaengine Peter Ujfalusi
2012-09-12 12:00   ` Russell King - ARM Linux
2012-09-12 12:00     ` Russell King - ARM Linux
2012-09-12 12:53     ` Peter Ujfalusi
2012-09-12 12:53       ` Peter Ujfalusi
2012-09-12 14:35       ` Peter Ujfalusi
2012-09-12 14:35         ` Peter Ujfalusi
2012-09-12 14:35         ` Peter Ujfalusi
2012-09-12 14:05     ` [alsa-devel] " Takashi Iwai
2012-09-12 14:05       ` Takashi Iwai
2012-09-12 14:05       ` Takashi Iwai
2012-09-13  8:11 ` [PATCH 00/11] ASoC: OMAP: " Mark Brown
2012-09-13  8:11   ` Mark Brown
2012-09-13  8:11   ` Mark Brown
2012-09-13  9:20   ` Peter Ujfalusi
2012-09-13  9:20     ` Peter Ujfalusi
2012-09-13  9:20     ` Peter Ujfalusi

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=1347450427-27627-12-git-send-email-peter.ujfalusi@ti.com \
    --to=peter.ujfalusi@ti.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=djbw@fb.com \
    --cc=jarkko.nikula@bitmer.com \
    --cc=jkrzyszt@tis.icnet.pl \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=lrg@ti.com \
    --cc=ricardo.neri@ti.com \
    --cc=rmk+kernel@arm.linux.org.uk \
    --cc=tony@atomide.com \
    --cc=vinod.koul@intel.com \
    /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 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.