linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] ASoC: atmel-pcm: add dma support
@ 2012-11-23  6:14 Bo Shen
  2012-11-23  6:14 ` [PATCH 1/3] ASoC: snd_dmaengine_pcm: add inline empty function Bo Shen
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Bo Shen @ 2012-11-23  6:14 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series is intend to add dma support for atmel pcm which is
based on snd soc dmaengine pcm framework

Bo Shen (3):
  ASoC: snd_dmaengine_pcm: add inline empty function
  ASoC: atmel-pcm: prepare for adding dma support
  ASoC: atmel-pcm: add dma support

 include/sound/dmaengine_pcm.h   |   53 +++++++++
 sound/soc/atmel/atmel-pcm.c     |  247 ++++++++++++++++++++++++++++++++++-----
 sound/soc/atmel/atmel-pcm.h     |    4 +-
 sound/soc/atmel/atmel_ssc_dai.c |   30 ++---
 4 files changed, 292 insertions(+), 42 deletions(-)

-- 
1.7.9.5

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

* [PATCH 1/3] ASoC: snd_dmaengine_pcm: add inline empty function
  2012-11-23  6:14 [PATCH 0/3] ASoC: atmel-pcm: add dma support Bo Shen
@ 2012-11-23  6:14 ` Bo Shen
  2012-11-23  6:14 ` [PATCH 2/3] ASoC: atmel-pcm: prepare for adding dma support Bo Shen
  2012-11-23  6:14 ` [PATCH 3/3] ASoC: atmel-pcm: add " Bo Shen
  2 siblings, 0 replies; 7+ messages in thread
From: Bo Shen @ 2012-11-23  6:14 UTC (permalink / raw)
  To: linux-arm-kernel

As to atmel pcm driver support pdc and dma for audio transfer, which
will be used for audio transfer depends on the ssc capability.

If without these inline empty functions, when compile the driver, it will
give out following information. So, add these inline empty functions.
---<8---
sound/built-in.o: In function `atmel_pcm_hw_free':
last.c:(.text+0x20a84): undefined reference to `snd_dmaengine_pcm_get_data'
sound/built-in.o: In function `atmel_pcm_dma_prepare':
last.c:(.text+0x20adc): undefined reference to `snd_dmaengine_pcm_get_data'
sound/built-in.o: In function `atmel_pcm_hw_params':
last.c:(.text+0x20c1c): undefined reference to `snd_dmaengine_pcm_open'
last.c:(.text+0x20c40): undefined reference to `snd_dmaengine_pcm_set_data'
last.c:(.text+0x20c50): undefined reference to `snd_hwparams_to_dma_slave_config'
last.c:(.text+0x20ca0): undefined reference to `snd_dmaengine_pcm_get_chan'
last.c:(.text+0x20cd0): undefined reference to `snd_dmaengine_pcm_close'
last.c:(.text+0x20d00): undefined reference to `snd_dmaengine_pcm_get_chan'
sound/built-in.o: In function `atmel_pcm_dma_irq':
last.c:(.text+0x20ec0): undefined reference to `snd_dmaengine_pcm_get_data'
sound/built-in.o: In function `atmel_pcm_close':
last.c:(.text+0x20f90): undefined reference to `snd_dmaengine_pcm_get_data'
last.c:(.text+0x20f9c): undefined reference to `snd_dmaengine_pcm_close'
sound/built-in.o: In function `atmel_pcm_platform_register':
last.c:(.text+0x21078): undefined reference to `snd_dmaengine_pcm_trigger'
last.c:(.text+0x2107c): undefined reference to `snd_dmaengine_pcm_pointer_no_residue'
make: *** [vmlinux] Error 1
--->8---

Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
 include/sound/dmaengine_pcm.h |   53 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h
index b877334..58241e9 100644
--- a/include/sound/dmaengine_pcm.h
+++ b/include/sound/dmaengine_pcm.h
@@ -32,6 +32,7 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
 		return DMA_DEV_TO_MEM;
 }
 
+#ifdef CONFIG_SND_SOC_DMAENGINE_PCM
 void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data);
 void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream);
 
@@ -46,5 +47,57 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
 int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
 
 struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
+#else
+static inline void
+snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
+{
+}
+static inline void
+*snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
+{
+	return NULL;
+}
+
+static inline int
+snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
+		const struct snd_pcm_hw_params *params,
+		struct dma_slave_config *slave_config)
+{
+	return 0;
+}
+static inline int
+snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	return 0;
+}
+static inline snd_pcm_uframes_t
+snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+static inline snd_pcm_uframes_t
+snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static inline int
+snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
+		dma_filter_fn filter_fn, void *filter_data)
+{
+	return 0;
+}
+static inline int
+snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static inline struct dma_chan
+*snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
+{
+	return NULL;
+}
+#endif
 
 #endif
-- 
1.7.9.5

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

* [PATCH 2/3] ASoC: atmel-pcm: prepare for adding dma support
  2012-11-23  6:14 [PATCH 0/3] ASoC: atmel-pcm: add dma support Bo Shen
  2012-11-23  6:14 ` [PATCH 1/3] ASoC: snd_dmaengine_pcm: add inline empty function Bo Shen
@ 2012-11-23  6:14 ` Bo Shen
  2012-11-23  6:14 ` [PATCH 3/3] ASoC: atmel-pcm: add " Bo Shen
  2 siblings, 0 replies; 7+ messages in thread
From: Bo Shen @ 2012-11-23  6:14 UTC (permalink / raw)
  To: linux-arm-kernel

Change xfer_size name to apply to PDC and DMA aswell.
Specify overrun bit in interrupt mask.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
[voice.shen at atmel.com: split as one patch]
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
 sound/soc/atmel/atmel-pcm.c     |   36 ++++++++++++++++++++----------------
 sound/soc/atmel/atmel-pcm.h     |    4 +++-
 sound/soc/atmel/atmel_ssc_dai.c |   30 +++++++++++++++++-------------
 3 files changed, 40 insertions(+), 30 deletions(-)

diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index 40e17d1..a3471e9 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -53,7 +53,7 @@
 /* TODO: These values were taken from the AT91 platform driver, check
  *	 them against real values for AT32
  */
-static const struct snd_pcm_hardware atmel_pcm_hardware = {
+static const struct snd_pcm_hardware atmel_pcm_pdc_hardware = {
 	.info			= SNDRV_PCM_INFO_MMAP |
 				  SNDRV_PCM_INFO_MMAP_VALID |
 				  SNDRV_PCM_INFO_INTERLEAVED |
@@ -66,6 +66,8 @@ static const struct snd_pcm_hardware atmel_pcm_hardware = {
 	.buffer_bytes_max	= 32 * 1024,
 };
 
+static const struct snd_pcm_hardware *atmel_pcm_hardware;
+
 
 /*--------------------------------------------------------------------------*\
  * Data types
@@ -94,7 +96,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
 {
 	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 	struct snd_dma_buffer *buf = &substream->dma_buffer;
-	size_t size = atmel_pcm_hardware.buffer_bytes_max;
+	size_t size = atmel_pcm_hardware->buffer_bytes_max;
 
 	buf->dev.type = SNDRV_DMA_TYPE_DEV;
 	buf->dev.dev = pcm->card->dev;
@@ -116,7 +118,7 @@ static int atmel_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
 /*--------------------------------------------------------------------------*\
  * ISR
 \*--------------------------------------------------------------------------*/
-static void atmel_pcm_dma_irq(u32 ssc_sr,
+static void atmel_pcm_pdc_irq(u32 ssc_sr,
 	struct snd_pcm_substream *substream)
 {
 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
@@ -142,7 +144,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
 		ssc_writex(params->ssc->regs, params->pdc->xpr,
 			   prtd->period_ptr);
 		ssc_writex(params->ssc->regs, params->pdc->xcr,
-			   prtd->period_size / params->pdc_xfer_size);
+			   prtd->period_size / params->data_xfer_size);
 		ssc_writex(params->ssc->regs, ATMEL_PDC_PTCR,
 			   params->mask->pdc_enable);
 	}
@@ -156,7 +158,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
 		ssc_writex(params->ssc->regs, params->pdc->xnpr,
 			   prtd->period_ptr);
 		ssc_writex(params->ssc->regs, params->pdc->xncr,
-			   prtd->period_size / params->pdc_xfer_size);
+			   prtd->period_size / params->data_xfer_size);
 	}
 
 	snd_pcm_period_elapsed(substream);
@@ -180,7 +182,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
 	runtime->dma_bytes = params_buffer_bytes(params);
 
 	prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
+	prtd->params->dma_intr_handler = atmel_pcm_pdc_irq;
 
 	prtd->dma_buffer = runtime->dma_addr;
 	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
@@ -209,7 +211,7 @@ static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
+static int atmel_pcm_pdc_prepare(struct snd_pcm_substream *substream)
 {
 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
 	struct atmel_pcm_dma_params *params = prtd->params;
@@ -221,7 +223,7 @@ static int atmel_pcm_prepare(struct snd_pcm_substream *substream)
 	return 0;
 }
 
-static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
+static int atmel_pcm_pdc_trigger(struct snd_pcm_substream *substream,
 	int cmd)
 {
 	struct snd_pcm_runtime *rtd = substream->runtime;
@@ -240,13 +242,13 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
 		ssc_writex(params->ssc->regs, params->pdc->xpr,
 			   prtd->period_ptr);
 		ssc_writex(params->ssc->regs, params->pdc->xcr,
-			   prtd->period_size / params->pdc_xfer_size);
+			   prtd->period_size / params->data_xfer_size);
 
 		prtd->period_ptr += prtd->period_size;
 		ssc_writex(params->ssc->regs, params->pdc->xnpr,
 			   prtd->period_ptr);
 		ssc_writex(params->ssc->regs, params->pdc->xncr,
-			   prtd->period_size / params->pdc_xfer_size);
+			   prtd->period_size / params->data_xfer_size);
 
 		pr_debug("atmel-pcm: trigger: "
 			"period_ptr=%lx, xpr=%u, "
@@ -264,7 +266,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
 
 		pr_debug("sr=%u imr=%u\n",
 			ssc_readx(params->ssc->regs, SSC_SR),
-			ssc_readx(params->ssc->regs, SSC_IER));
+			ssc_readx(params->ssc->regs, SSC_IMR));
 		break;		/* SNDRV_PCM_TRIGGER_START */
 
 	case SNDRV_PCM_TRIGGER_STOP:
@@ -287,7 +289,7 @@ static int atmel_pcm_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static snd_pcm_uframes_t atmel_pcm_pointer(
+static snd_pcm_uframes_t atmel_pcm_pdc_pointer(
 	struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -311,7 +313,7 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
 	struct atmel_runtime_data *prtd;
 	int ret = 0;
 
-	snd_soc_set_runtime_hwparams(substream, &atmel_pcm_hardware);
+	snd_soc_set_runtime_hwparams(substream, atmel_pcm_hardware);
 
 	/* ensure that buffer size is a multiple of period size */
 	ret = snd_pcm_hw_constraint_integer(runtime,
@@ -352,9 +354,9 @@ static struct snd_pcm_ops atmel_pcm_ops = {
 	.ioctl		= snd_pcm_lib_ioctl,
 	.hw_params	= atmel_pcm_hw_params,
 	.hw_free	= atmel_pcm_hw_free,
-	.prepare	= atmel_pcm_prepare,
-	.trigger	= atmel_pcm_trigger,
-	.pointer	= atmel_pcm_pointer,
+	.prepare	= atmel_pcm_pdc_prepare,
+	.trigger	= atmel_pcm_pdc_trigger,
+	.pointer	= atmel_pcm_pdc_pointer,
 	.mmap		= atmel_pcm_mmap,
 };
 
@@ -475,6 +477,8 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
 
 int atmel_pcm_platform_register(struct device *dev)
 {
+	atmel_pcm_hardware = &atmel_pcm_pdc_hardware;
+
 	return snd_soc_register_platform(dev, &atmel_soc_platform);
 }
 EXPORT_SYMBOL(atmel_pcm_platform_register);
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h
index e6d67b3..261331d 100644
--- a/sound/soc/atmel/atmel-pcm.h
+++ b/sound/soc/atmel/atmel-pcm.h
@@ -50,6 +50,7 @@ struct atmel_pdc_regs {
 struct atmel_ssc_mask {
 	u32	ssc_enable;		/* SSC recv/trans enable */
 	u32	ssc_disable;		/* SSC recv/trans disable */
+	u32	ssc_error;		/* SSC error conditions */
 	u32	ssc_endx;		/* SSC ENDTX or ENDRX */
 	u32	ssc_endbuf;		/* SSC TXBUFE or RXBUFF */
 	u32	pdc_enable;		/* PDC recv/trans enable */
@@ -66,7 +67,8 @@ struct atmel_ssc_mask {
  */
 struct atmel_pcm_dma_params {
 	char *name;			/* stream identifier */
-	int pdc_xfer_size;		/* PDC counter increment in bytes */
+	int data_xfer_size;		/* PDC counter increment in bytes,
+					   DMA data transfer size in bytes */
 	struct ssc_device *ssc;		/* SSC device for stream */
 	struct atmel_pdc_regs *pdc;	/* PDC receive or transmit registers */
 	struct atmel_ssc_mask *mask;	/* SSC & PDC status bits */
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 7932c05..a87d6d8 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -82,6 +82,7 @@ static struct atmel_ssc_mask ssc_tx_mask = {
 static struct atmel_ssc_mask ssc_rx_mask = {
 	.ssc_enable	= SSC_BIT(CR_RXEN),
 	.ssc_disable	= SSC_BIT(CR_RXDIS),
+	.ssc_error	= SSC_BIT(SR_OVRUN),
 	.ssc_endx	= SSC_BIT(SR_ENDRX),
 	.ssc_endbuf	= SSC_BIT(SR_RXBUFF),
 	.pdc_enable	= ATMEL_PDC_RXTEN,
@@ -175,7 +176,8 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
 		if ((dma_params != NULL) &&
 			(dma_params->dma_intr_handler != NULL)) {
 			ssc_substream_mask = (dma_params->mask->ssc_endx |
-					dma_params->mask->ssc_endbuf);
+					dma_params->mask->ssc_endbuf |
+					dma_params->mask->ssc_error);
 			if (ssc_sr & ssc_substream_mask) {
 				dma_params->dma_intr_handler(ssc_sr,
 						dma_params->
@@ -368,19 +370,19 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S8:
 		bits = 8;
-		dma_params->pdc_xfer_size = 1;
+		dma_params->data_xfer_size = 1;
 		break;
 	case SNDRV_PCM_FORMAT_S16_LE:
 		bits = 16;
-		dma_params->pdc_xfer_size = 2;
+		dma_params->data_xfer_size = 2;
 		break;
 	case SNDRV_PCM_FORMAT_S24_LE:
 		bits = 24;
-		dma_params->pdc_xfer_size = 4;
+		dma_params->data_xfer_size = 4;
 		break;
 	case SNDRV_PCM_FORMAT_S32_LE:
 		bits = 32;
-		dma_params->pdc_xfer_size = 4;
+		dma_params->data_xfer_size = 4;
 		break;
 	default:
 		printk(KERN_WARNING "atmel_ssc_dai: unsupported PCM format");
@@ -553,15 +555,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 		/* Reset the SSC and its PDC registers */
 		ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
 
-		ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+		if (!ssc_p->ssc->pdata->use_dma) {
+			ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
 
-		ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-		ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+			ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+		}
 
 		ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
 				ssc_p->name, ssc_p);
-- 
1.7.9.5

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

* [PATCH 3/3] ASoC: atmel-pcm: add dma support
  2012-11-23  6:14 [PATCH 0/3] ASoC: atmel-pcm: add dma support Bo Shen
  2012-11-23  6:14 ` [PATCH 1/3] ASoC: snd_dmaengine_pcm: add inline empty function Bo Shen
  2012-11-23  6:14 ` [PATCH 2/3] ASoC: atmel-pcm: prepare for adding dma support Bo Shen
@ 2012-11-23  6:14 ` Bo Shen
  2012-11-23 14:27   ` Mark Brown
  2 siblings, 1 reply; 7+ messages in thread
From: Bo Shen @ 2012-11-23  6:14 UTC (permalink / raw)
  To: linux-arm-kernel

Add dmaengine specific routines and replace PDC ones in
pcm_ops if appropriate.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
[voice.shen at atmel.com: adapt to soc dmaengine framework]
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
 sound/soc/atmel/atmel-pcm.c |  215 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 201 insertions(+), 14 deletions(-)

diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index a3471e9..d18a241 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -37,15 +37,19 @@
 #include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/atmel_pdc.h>
+#include <linux/dmaengine.h>
 #include <linux/atmel-ssc.h>
+#include <linux/platform_data/dma-atmel.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "atmel-pcm.h"
 
+static int use_dma;
 
 /*--------------------------------------------------------------------------*\
  * Hardware definition
@@ -66,6 +70,20 @@ static const struct snd_pcm_hardware atmel_pcm_pdc_hardware = {
 	.buffer_bytes_max	= 32 * 1024,
 };
 
+static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_RESUME |
+				  SNDRV_PCM_INFO_PAUSE,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.period_bytes_min	= 256,		/* lighting DMA overhead */
+	.period_bytes_max	= 2 * 0xffff,	/* if 2 bytes format */
+	.periods_min		= 8,
+	.periods_max		= 1024,		/* no limit */
+	.buffer_bytes_max	= 64 * 1024,	/* 64KiB */
+};
+
 static const struct snd_pcm_hardware *atmel_pcm_hardware;
 
 
@@ -85,6 +103,9 @@ struct atmel_runtime_data {
 	u32 pdc_xcr_save;
 	u32 pdc_xnpr_save;
 	u32 pdc_xncr_save;
+
+	/* dmaengine data */
+	struct at_dma_slave atslave;
 };
 
 
@@ -164,6 +185,101 @@ static void atmel_pcm_pdc_irq(u32 ssc_sr,
 	snd_pcm_period_elapsed(substream);
 }
 
+/**
+ * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC
+ *
+ * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to
+ * check if any overrun occured.
+ */
+static void atmel_pcm_dma_irq(u32 ssc_sr,
+	struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = snd_dmaengine_pcm_get_data(substream);
+	struct atmel_pcm_dma_params *params = prtd->params;
+
+	if (ssc_sr & params->mask->ssc_error) {
+		if (snd_pcm_running(substream))
+			pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n",
+				substream->stream == SNDRV_PCM_STREAM_PLAYBACK
+				? "underrun" : "overrun", params->name,
+				ssc_sr);
+
+		/* stop RX and capture: will be enabled again at restart */
+		ssc_writex(params->ssc->regs, SSC_CR,
+				params->mask->ssc_disable);
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+		/* now drain RHR and read status to remove xrun condition */
+		ssc_readx(params->ssc->regs, SSC_RHR);
+		ssc_readx(params->ssc->regs, SSC_SR);
+	}
+}
+
+/*--------------------------------------------------------------------------*\
+ * DMAENGINE operations
+\*--------------------------------------------------------------------------*/
+static bool filter(struct dma_chan *chan, void *slave)
+{
+	struct at_dma_slave *sl = slave;
+
+	if (sl->dma_dev == chan->device->dev) {
+		chan->private = sl;
+		return true;
+	} else {
+		return false;
+	}
+}
+
+static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct atmel_runtime_data *prtd = runtime->private_data;
+	struct ssc_device *ssc = prtd->params->ssc;
+	struct dma_chan *dma_chan;
+	struct dma_slave_config slave_config;
+	struct at_dma_slave *sdata = NULL;
+	int ret;
+
+	if (ssc->pdev)
+		sdata = ssc->pdev->dev.platform_data;
+
+	ret = snd_dmaengine_pcm_open(substream, filter, sdata);
+	if (ret) {
+		pr_err("atmel-pcm: dmaengine pcm open failed\n");
+		return -EINVAL;
+	}
+	snd_dmaengine_pcm_set_data(substream, prtd);
+
+	ret = snd_hwparams_to_dma_slave_config(substream, params,
+			&slave_config);
+	if (ret) {
+		pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
+		goto err;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
+		slave_config.dst_maxburst = 1;
+	} else {
+		slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
+		slave_config.src_maxburst = 1;
+	}
+	slave_config.device_fc = false;
+
+	dma_chan = snd_dmaengine_pcm_get_chan(substream);
+	if (dmaengine_slave_config(dma_chan, &slave_config)) {
+		pr_err("atmel-pcm: failed to configure dma channel\n");
+		ret = -EBUSY;
+		goto err;
+	}
+
+	return 0;
+
+err:
+	snd_dmaengine_pcm_close(substream);
+	return ret;
+}
 
 /*--------------------------------------------------------------------------*\
  * PCM operations
@@ -174,43 +290,74 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct atmel_runtime_data *prtd = runtime->private_data;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct dma_chan *dma_chan = NULL;
+	int ret;
 
 	/* this may get called several times by oss emulation
 	 * with different params */
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-	runtime->dma_bytes = params_buffer_bytes(params);
 
 	prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-	prtd->params->dma_intr_handler = atmel_pcm_pdc_irq;
 
 	prtd->dma_buffer = runtime->dma_addr;
 	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
 	prtd->period_size = params_period_bytes(params);
 
+	if (use_dma) {
+		ret = atmel_pcm_configure_dma(substream, params);
+		if (ret) {
+			pr_err("atmel-pcm: failed to configure dma");
+			return ret;
+		}
+
+		dma_chan = snd_dmaengine_pcm_get_chan(substream);
+
+		prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
+	} else {
+		prtd->params->dma_intr_handler = atmel_pcm_pdc_irq;
+	}
+
 	pr_debug("atmel-pcm: "
-		"hw_params: DMA for %s initialized "
+		"hw_params: %s%s for %s initialized "
 		"(dma_bytes=%u, period_size=%u)\n",
+		dma_chan ? "DMA " : "PDC",
+		dma_chan ? dma_chan_name(dma_chan) : "",
 		prtd->params->name,
 		runtime->dma_bytes,
 		prtd->period_size);
+
 	return 0;
 }
 
 static int atmel_pcm_hw_free(struct snd_pcm_substream *substream)
 {
-	struct atmel_runtime_data *prtd = substream->runtime->private_data;
-	struct atmel_pcm_dma_params *params = prtd->params;
+	struct atmel_runtime_data *prtd;
+	struct atmel_pcm_dma_params *params;
 
-	if (params != NULL) {
-		ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
-			   params->mask->pdc_disable);
-		prtd->params->dma_intr_handler = NULL;
+	if (use_dma) {
+		prtd = snd_dmaengine_pcm_get_data(substream);
+		params = prtd->params;
+
+		if (params != NULL)
+			prtd->params->dma_intr_handler = NULL;
+	} else {
+		prtd = substream->runtime->private_data;
+		params = prtd->params;
+
+		if (params != NULL) {
+			ssc_writex(params->ssc->regs, SSC_PDC_PTCR,
+				   params->mask->pdc_disable);
+			prtd->params->dma_intr_handler = NULL;
+		}
 	}
 
 	return 0;
 }
 
+/*--------------------------------------------------------------------------*\
+ * PCM callbacks using PDC
+\*--------------------------------------------------------------------------*/
 static int atmel_pcm_pdc_prepare(struct snd_pcm_substream *substream)
 {
 	struct atmel_runtime_data *prtd = substream->runtime->private_data;
@@ -307,6 +454,22 @@ static snd_pcm_uframes_t atmel_pcm_pdc_pointer(
 	return x;
 }
 
+/*--------------------------------------------------------------------------*\
+ * PCM callbacks using DMAENGINE
+\*--------------------------------------------------------------------------*/
+static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
+{
+	struct atmel_runtime_data *prtd = snd_dmaengine_pcm_get_data(substream);
+	struct atmel_pcm_dma_params *params = prtd->params;
+
+	ssc_writex(params->ssc->regs, SSC_IER, params->mask->ssc_error);
+	ssc_writex(params->ssc->regs, SSC_CR, params->mask->ssc_enable);
+	return 0;
+}
+
+/*--------------------------------------------------------------------------*\
+ * PCM open/close/mmap
+\*--------------------------------------------------------------------------*/
 static int atmel_pcm_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -334,7 +497,14 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
 
 static int atmel_pcm_close(struct snd_pcm_substream *substream)
 {
-	struct atmel_runtime_data *prtd = substream->runtime->private_data;
+	struct atmel_runtime_data *prtd;
+
+	if (use_dma) {
+		prtd = snd_dmaengine_pcm_get_data(substream);
+		snd_dmaengine_pcm_close(substream);
+	} else {
+		prtd = substream->runtime->private_data;
+	}
 
 	kfree(prtd);
 	return 0;
@@ -426,12 +596,14 @@ static int atmel_pcm_suspend(struct snd_soc_dai *dai)
 	if (!runtime)
 		return 0;
 
+	if (!use_dma)
+		return 0;
+
 	prtd = runtime->private_data;
 	params = prtd->params;
 
 	/* disable the PDC and save the PDC registers */
-
-	ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_disable);
+	ssc_writel(params->ssc->regs, PDC_PTCR,	params->mask->pdc_disable);
 
 	prtd->pdc_xpr_save = ssc_readx(params->ssc->regs, params->pdc->xpr);
 	prtd->pdc_xcr_save = ssc_readx(params->ssc->regs, params->pdc->xcr);
@@ -450,6 +622,9 @@ static int atmel_pcm_resume(struct snd_soc_dai *dai)
 	if (!runtime)
 		return 0;
 
+	if (use_dma)
+		return 0;
+
 	prtd = runtime->private_data;
 	params = prtd->params;
 
@@ -458,8 +633,8 @@ static int atmel_pcm_resume(struct snd_soc_dai *dai)
 	ssc_writex(params->ssc->regs, params->pdc->xcr, prtd->pdc_xcr_save);
 	ssc_writex(params->ssc->regs, params->pdc->xnpr, prtd->pdc_xnpr_save);
 	ssc_writex(params->ssc->regs, params->pdc->xncr, prtd->pdc_xncr_save);
-
 	ssc_writel(params->ssc->regs, PDC_PTCR, params->mask->pdc_enable);
+
 	return 0;
 }
 #else
@@ -477,7 +652,19 @@ static struct snd_soc_platform_driver atmel_soc_platform = {
 
 int atmel_pcm_platform_register(struct device *dev)
 {
-	atmel_pcm_hardware = &atmel_pcm_pdc_hardware;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct ssc_device *ssc = platform_get_drvdata(pdev);
+
+	if (ssc->pdata->use_dma) {
+		use_dma = 1;
+		atmel_pcm_ops.prepare = atmel_pcm_dma_prepare;
+		atmel_pcm_ops.trigger = snd_dmaengine_pcm_trigger;
+		atmel_pcm_ops.pointer = snd_dmaengine_pcm_pointer_no_residue;
+
+		atmel_pcm_hardware = &atmel_pcm_dma_hardware;
+	} else {
+		atmel_pcm_hardware = &atmel_pcm_pdc_hardware;
+	}
 
 	return snd_soc_register_platform(dev, &atmel_soc_platform);
 }
-- 
1.7.9.5

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

* [PATCH 3/3] ASoC: atmel-pcm: add dma support
  2012-11-23  6:14 ` [PATCH 3/3] ASoC: atmel-pcm: add " Bo Shen
@ 2012-11-23 14:27   ` Mark Brown
  2012-11-26  2:04     ` Bo Shen
  0 siblings, 1 reply; 7+ messages in thread
From: Mark Brown @ 2012-11-23 14:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Nov 23, 2012 at 02:14:17PM +0800, Bo Shen wrote:
> Add dmaengine specific routines and replace PDC ones in
> pcm_ops if appropriate.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> [voice.shen at atmel.com: adapt to soc dmaengine framework]
> Signed-off-by: Bo Shen <voice.shen@atmel.com>

Why is this not just two separate drivers?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121123/a44bbe27/attachment.sig>

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

* [PATCH 3/3] ASoC: atmel-pcm: add dma support
  2012-11-23 14:27   ` Mark Brown
@ 2012-11-26  2:04     ` Bo Shen
  2012-11-26  9:36       ` Mark Brown
  0 siblings, 1 reply; 7+ messages in thread
From: Bo Shen @ 2012-11-26  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Mark,

On 11/23/2012 22:27, Mark Brown wrote:
> On Fri, Nov 23, 2012 at 02:14:17PM +0800, Bo Shen wrote:
>> Add dmaengine specific routines and replace PDC ones in
>> pcm_ops if appropriate.
>>
>> Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
>> [voice.shen at atmel.com: adapt to soc dmaengine framework]
>> Signed-off-by: Bo Shen <voice.shen@atmel.com>
>
> Why is this not just two separate drivers?

I am not sure I got your means.
As I understand, I should keep the driver using pdc and won't touch it.
And create new a new driver using dma, am I right?

or else, ...?

Best Regards
Bo Shen

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

* [PATCH 3/3] ASoC: atmel-pcm: add dma support
  2012-11-26  2:04     ` Bo Shen
@ 2012-11-26  9:36       ` Mark Brown
  0 siblings, 0 replies; 7+ messages in thread
From: Mark Brown @ 2012-11-26  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Nov 26, 2012 at 10:04:28AM +0800, Bo Shen wrote:

> I am not sure I got your means.
> As I understand, I should keep the driver using pdc and won't touch it.
> And create new a new driver using dma, am I right?

Yes.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121126/08d37ce2/attachment-0001.sig>

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

end of thread, other threads:[~2012-11-26  9:36 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-11-23  6:14 [PATCH 0/3] ASoC: atmel-pcm: add dma support Bo Shen
2012-11-23  6:14 ` [PATCH 1/3] ASoC: snd_dmaengine_pcm: add inline empty function Bo Shen
2012-11-23  6:14 ` [PATCH 2/3] ASoC: atmel-pcm: prepare for adding dma support Bo Shen
2012-11-23  6:14 ` [PATCH 3/3] ASoC: atmel-pcm: add " Bo Shen
2012-11-23 14:27   ` Mark Brown
2012-11-26  2:04     ` Bo Shen
2012-11-26  9:36       ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).