From: Kukjin Kim <kgene.kim@samsung.com> To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org Cc: Vinod Koul <vinod.koul@intel.com>, Dan Williams <dan.j.williams@intel.com>, Grant Likely <grant.likely@secretlab.ca>, Jassi Brar <jassisinghbrar@gmail.com>, Liam Girdwood <lrg@ti.com>, Mark Brown <broonie@opensource.wolfsonmicro.com>, Boojin Kim <boojin.kim@samsung.com>, Kukjin Kim <kgene.kim@samsung.com> Subject: [PATCH 7/7] ASoC: Samsung: Update DMA interface Date: Mon, 4 Jul 2011 21:18:35 +0900 [thread overview] Message-ID: <1309781915-31549-8-git-send-email-kgene.kim@samsung.com> (raw) In-Reply-To: <1309781915-31549-1-git-send-email-kgene.kim@samsung.com> From: Boojin Kim <boojin.kim@samsung.com> This patch adds to support the DMA PL330 driver that uses DMA generic API. Samsung sound driver uses DMA generic API if architecture supports it. Otherwise, use samsung specific S3C-PL330 API driver to transfer PCM data. Signed-off-by: Boojin Kim <boojin.kim@samsung.com> Cc: Jassi Brar <jassisinghbrar@gmail.com> Cc: Liam Girdwood <lrg@ti.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s3c2410/include/mach/dma.h | 2 +- arch/arm/mach-s3c64xx/include/mach/dma.h | 2 +- arch/arm/plat-samsung/include/plat/dma-pl330.h | 2 +- sound/soc/samsung/ac97.c | 4 + sound/soc/samsung/dma.c | 204 +++++++++++++++++++++++- sound/soc/samsung/dma.h | 4 + 6 files changed, 211 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index b2b2a5b..e2db38b 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -196,7 +196,7 @@ struct s3c2410_dma_chan { typedef unsigned long dma_device_t; -static inline bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return false; } diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 0a5d926..d752e27 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -58,7 +58,7 @@ enum dma_ch { DMACH_MAX /* the end */ }; -static __inline__ bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return true; } diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 1122c8b..4f19eb3 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -98,7 +98,7 @@ enum dma_ch { DMACH_MAX, }; -static inline bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return true; } diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index f97110e..ec6b3dd 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -271,7 +271,9 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); +#if !defined(CONFIG_DMADEV_PL330) s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); +#endif return 0; } @@ -317,7 +319,9 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); +#if !defined(CONFIG_DMADEV_PL330) s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); +#endif return 0; } diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 5cb3b88..6ba0632 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -17,6 +17,11 @@ #include <linux/slab.h> #include <linux/dma-mapping.h> +#if defined(CONFIG_DMADEV_PL330) +#include <linux/dmaengine.h> +#include <linux/amba/pl330.h> +#endif + #include <sound/soc.h> #include <sound/pcm_params.h> @@ -62,6 +67,103 @@ struct runtime_data { struct s3c_dma_params *params; }; +#if defined(CONFIG_DMADEV_PL330) +static bool filter(struct dma_chan *chan, void *param) +{ + struct snd_pcm_substream *substream = (struct snd_pcm_substream *)param; + struct runtime_data *prtd = substream->runtime->private_data; + + struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private; + + if (peri->peri_id != prtd->params->channel) + return false; + + /* dma client should fill fifo_addr */ + peri->fifo_addr = prtd->params->dma_addr; + + return true; +} + +static void audio_buffdone(void *data) +{ + struct snd_pcm_substream *substream = data; + struct runtime_data *prtd; + struct dma_chan *chan; + + prtd = substream->runtime->private_data; + + chan = prtd->params->chan; + prtd->params->desc = + chan->device->device_prep_dma_cyclic( + chan, prtd->dma_pos, prtd->dma_period, prtd->dma_period, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!prtd->params->desc) + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + + prtd->params->desc->callback = audio_buffdone; + prtd->params->desc->callback_param = substream; + dmaengine_submit(prtd->params->desc); + + prtd->dma_pos += prtd->dma_period; + if (prtd->dma_pos >= prtd->dma_end) + prtd->dma_pos = prtd->dma_start; + + if (substream) + snd_pcm_period_elapsed(substream); +} + +/* dma_enqueue + * + * place a dma buffer onto the queue for the dma system + * to handle. + */ +static void dma_enqueue(struct snd_pcm_substream *substream) +{ + struct runtime_data *prtd = substream->runtime->private_data; + dma_addr_t pos = prtd->dma_pos; + unsigned int limit; + struct dma_chan *chan = prtd->params->chan; + + pr_debug("Entered %s\n", __func__); + + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; + + chan = prtd->params->chan; + + while (prtd->dma_loaded < limit) { + unsigned long len = prtd->dma_period; + + pr_debug("dma_loaded: %d\n", prtd->dma_loaded); + + if ((pos + len) > prtd->dma_end) { + len = prtd->dma_end - pos; + pr_debug("%s: corrected dma len %ld\n", + __func__, len); + } + + prtd->params->desc = + chan->device->device_prep_dma_cyclic( + chan, pos, prtd->dma_period, prtd->dma_period, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!prtd->params->desc) + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + + prtd->params->desc->callback = audio_buffdone; + prtd->params->desc->callback_param = substream; + dmaengine_submit(prtd->params->desc); + + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; + } + + prtd->dma_pos = pos; +} + +#else /* dma_enqueue * * place a dma buffer onto the queue for the dma system @@ -76,7 +178,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); - if (s3c_dma_has_circular()) + if (dma_has_circular()) limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; else limit = prtd->dma_limit; @@ -127,13 +229,14 @@ static void audio_buffdone(struct s3c2410_dma_chan *channel, snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { + if (prtd->state & ST_RUNNING && !dma_has_circular()) { prtd->dma_loaded--; dma_enqueue(substream); } spin_unlock(&prtd->lock); } +#endif /* CONFIG_DMADEV_PL330 */ static int dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -146,6 +249,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + dma_cap_mask_t mask; pr_debug("Entered %s\n", __func__); @@ -154,6 +259,28 @@ static int dma_hw_params(struct snd_pcm_substream *substream, if (!dma) return 0; + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_CYCLIC, mask); + prtd->params->chan = + dma_request_channel(mask, filter, substream); + if (!prtd->params->chan) { + printk(KERN_ERR "failed to get dma channel\n"); + return ret; + } + } +#else + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!dma) + return 0; + /* this may get called several times by oss emulation * with different params -HW */ if (prtd->params == NULL) { @@ -172,14 +299,14 @@ static int dma_hw_params(struct snd_pcm_substream *substream, } /* use the circular buffering if we have it available. */ - if (s3c_dma_has_circular()) + if (dma_has_circular()) s3c2410_dma_setflags(prtd->params->channel, S3C2410_DMAF_CIRCULAR); } s3c2410_dma_set_buffdone_fn(prtd->params->channel, audio_buffdone); - +#endif /* CONFIG_DMADEV_PL330 */ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; @@ -206,7 +333,11 @@ static int dma_hw_free(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); if (prtd->params) { +#if defined(CONFIG_DMADEV_PL330) + dma_release_channel(prtd->params->chan); +#else s3c2410_dma_free(prtd->params->channel, prtd->params->client); +#endif prtd->params = NULL; } @@ -218,6 +349,33 @@ static int dma_prepare(struct snd_pcm_substream *substream) struct runtime_data *prtd = substream->runtime->private_data; int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + struct dma_chan *chan = prtd->params->chan; + struct dma_slave_config slave_config; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!prtd->params) + return 0; + + ret = dmaengine_terminate_all(chan); + if (ret) + dev_err(&chan->dev->device, "cannot flush dma channel\n"); + + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_TO_DEVICE; + slave_config.dst_addr_width = prtd->params->dma_size; + } else { + slave_config.direction = DMA_FROM_DEVICE; + slave_config.src_addr_width = prtd->params->dma_size; + } + ret = dmaengine_slave_config(chan, &slave_config); + if (ret) + dev_err(&chan->dev->device, "cannot config dma channel\n"); +#else pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. @@ -242,6 +400,7 @@ static int dma_prepare(struct snd_pcm_substream *substream) /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); +#endif /* CONFIG_DMADEV_PL330 */ prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; @@ -256,6 +415,33 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) struct runtime_data *prtd = substream->runtime->private_data; int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + struct dma_chan *chan = prtd->params->chan; + + pr_debug("Entered %s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + prtd->state |= ST_RUNNING; + dma_async_issue_pending(prtd->params->chan); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->state &= ~ST_RUNNING; + ret = dmaengine_terminate_all(chan); + if (ret) + dev_err(&chan->dev->device, "cannot flush dma channel\n"); + break; + + default: + ret = -EINVAL; + break; + } +#else pr_debug("Entered %s\n", __func__); spin_lock(&prtd->lock); @@ -281,6 +467,7 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) } spin_unlock(&prtd->lock); +#endif /* CONFIG_DMADEV_PL330 */ return ret; } @@ -291,6 +478,14 @@ dma_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct runtime_data *prtd = runtime->private_data; unsigned long res; + +#if defined(CONFIG_DMADEV_PL330) + pr_debug("Entered %s\n", __func__); + + res = prtd->dma_pos - prtd->dma_start; + + pr_debug("Pointer offset: %lu\n", res); +#else dma_addr_t src, dst; pr_debug("Entered %s\n", __func__); @@ -306,6 +501,7 @@ dma_pointer(struct snd_pcm_substream *substream) spin_unlock(&prtd->lock); pr_debug("Pointer %x %x\n", src, dst); +#endif /* CONFIG_DMADEV_PL330 */ /* we seem to be getting the odd error from the pcm library due * to out-of-bounds pointers. this is maybe due to the dma engine diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index c506592..b6fae7e 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -17,6 +17,10 @@ struct s3c_dma_params { int channel; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ +#ifdef CONFIG_DMADEV_PL330 + struct dma_chan *chan; + struct dma_async_tx_descriptor *desc; +#endif }; #endif -- 1.7.1
WARNING: multiple messages have this Message-ID (diff)
From: kgene.kim@samsung.com (Kukjin Kim) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 7/7] ASoC: Samsung: Update DMA interface Date: Mon, 4 Jul 2011 21:18:35 +0900 [thread overview] Message-ID: <1309781915-31549-8-git-send-email-kgene.kim@samsung.com> (raw) In-Reply-To: <1309781915-31549-1-git-send-email-kgene.kim@samsung.com> From: Boojin Kim <boojin.kim@samsung.com> This patch adds to support the DMA PL330 driver that uses DMA generic API. Samsung sound driver uses DMA generic API if architecture supports it. Otherwise, use samsung specific S3C-PL330 API driver to transfer PCM data. Signed-off-by: Boojin Kim <boojin.kim@samsung.com> Cc: Jassi Brar <jassisinghbrar@gmail.com> Cc: Liam Girdwood <lrg@ti.com> Cc: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com> --- arch/arm/mach-s3c2410/include/mach/dma.h | 2 +- arch/arm/mach-s3c64xx/include/mach/dma.h | 2 +- arch/arm/plat-samsung/include/plat/dma-pl330.h | 2 +- sound/soc/samsung/ac97.c | 4 + sound/soc/samsung/dma.c | 204 +++++++++++++++++++++++- sound/soc/samsung/dma.h | 4 + 6 files changed, 211 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-s3c2410/include/mach/dma.h b/arch/arm/mach-s3c2410/include/mach/dma.h index b2b2a5b..e2db38b 100644 --- a/arch/arm/mach-s3c2410/include/mach/dma.h +++ b/arch/arm/mach-s3c2410/include/mach/dma.h @@ -196,7 +196,7 @@ struct s3c2410_dma_chan { typedef unsigned long dma_device_t; -static inline bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return false; } diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 0a5d926..d752e27 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -58,7 +58,7 @@ enum dma_ch { DMACH_MAX /* the end */ }; -static __inline__ bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return true; } diff --git a/arch/arm/plat-samsung/include/plat/dma-pl330.h b/arch/arm/plat-samsung/include/plat/dma-pl330.h index 1122c8b..4f19eb3 100644 --- a/arch/arm/plat-samsung/include/plat/dma-pl330.h +++ b/arch/arm/plat-samsung/include/plat/dma-pl330.h @@ -98,7 +98,7 @@ enum dma_ch { DMACH_MAX, }; -static inline bool s3c_dma_has_circular(void) +static inline bool dma_has_circular(void) { return true; } diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index f97110e..ec6b3dd 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -271,7 +271,9 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); +#if !defined(CONFIG_DMADEV_PL330) s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); +#endif return 0; } @@ -317,7 +319,9 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); +#if !defined(CONFIG_DMADEV_PL330) s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED); +#endif return 0; } diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 5cb3b88..6ba0632 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c @@ -17,6 +17,11 @@ #include <linux/slab.h> #include <linux/dma-mapping.h> +#if defined(CONFIG_DMADEV_PL330) +#include <linux/dmaengine.h> +#include <linux/amba/pl330.h> +#endif + #include <sound/soc.h> #include <sound/pcm_params.h> @@ -62,6 +67,103 @@ struct runtime_data { struct s3c_dma_params *params; }; +#if defined(CONFIG_DMADEV_PL330) +static bool filter(struct dma_chan *chan, void *param) +{ + struct snd_pcm_substream *substream = (struct snd_pcm_substream *)param; + struct runtime_data *prtd = substream->runtime->private_data; + + struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private; + + if (peri->peri_id != prtd->params->channel) + return false; + + /* dma client should fill fifo_addr */ + peri->fifo_addr = prtd->params->dma_addr; + + return true; +} + +static void audio_buffdone(void *data) +{ + struct snd_pcm_substream *substream = data; + struct runtime_data *prtd; + struct dma_chan *chan; + + prtd = substream->runtime->private_data; + + chan = prtd->params->chan; + prtd->params->desc = + chan->device->device_prep_dma_cyclic( + chan, prtd->dma_pos, prtd->dma_period, prtd->dma_period, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!prtd->params->desc) + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + + prtd->params->desc->callback = audio_buffdone; + prtd->params->desc->callback_param = substream; + dmaengine_submit(prtd->params->desc); + + prtd->dma_pos += prtd->dma_period; + if (prtd->dma_pos >= prtd->dma_end) + prtd->dma_pos = prtd->dma_start; + + if (substream) + snd_pcm_period_elapsed(substream); +} + +/* dma_enqueue + * + * place a dma buffer onto the queue for the dma system + * to handle. + */ +static void dma_enqueue(struct snd_pcm_substream *substream) +{ + struct runtime_data *prtd = substream->runtime->private_data; + dma_addr_t pos = prtd->dma_pos; + unsigned int limit; + struct dma_chan *chan = prtd->params->chan; + + pr_debug("Entered %s\n", __func__); + + limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; + + chan = prtd->params->chan; + + while (prtd->dma_loaded < limit) { + unsigned long len = prtd->dma_period; + + pr_debug("dma_loaded: %d\n", prtd->dma_loaded); + + if ((pos + len) > prtd->dma_end) { + len = prtd->dma_end - pos; + pr_debug("%s: corrected dma len %ld\n", + __func__, len); + } + + prtd->params->desc = + chan->device->device_prep_dma_cyclic( + chan, pos, prtd->dma_period, prtd->dma_period, + substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (!prtd->params->desc) + dev_err(&chan->dev->device, "cannot prepare cyclic dma\n"); + + prtd->params->desc->callback = audio_buffdone; + prtd->params->desc->callback_param = substream; + dmaengine_submit(prtd->params->desc); + + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; + } + + prtd->dma_pos = pos; +} + +#else /* dma_enqueue * * place a dma buffer onto the queue for the dma system @@ -76,7 +178,7 @@ static void dma_enqueue(struct snd_pcm_substream *substream) pr_debug("Entered %s\n", __func__); - if (s3c_dma_has_circular()) + if (dma_has_circular()) limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period; else limit = prtd->dma_limit; @@ -127,13 +229,14 @@ static void audio_buffdone(struct s3c2410_dma_chan *channel, snd_pcm_period_elapsed(substream); spin_lock(&prtd->lock); - if (prtd->state & ST_RUNNING && !s3c_dma_has_circular()) { + if (prtd->state & ST_RUNNING && !dma_has_circular()) { prtd->dma_loaded--; dma_enqueue(substream); } spin_unlock(&prtd->lock); } +#endif /* CONFIG_DMADEV_PL330 */ static int dma_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -146,6 +249,8 @@ static int dma_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + dma_cap_mask_t mask; pr_debug("Entered %s\n", __func__); @@ -154,6 +259,28 @@ static int dma_hw_params(struct snd_pcm_substream *substream, if (!dma) return 0; + if (prtd->params == NULL) { + /* prepare DMA */ + prtd->params = dma; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_CYCLIC, mask); + prtd->params->chan = + dma_request_channel(mask, filter, substream); + if (!prtd->params->chan) { + printk(KERN_ERR "failed to get dma channel\n"); + return ret; + } + } +#else + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!dma) + return 0; + /* this may get called several times by oss emulation * with different params -HW */ if (prtd->params == NULL) { @@ -172,14 +299,14 @@ static int dma_hw_params(struct snd_pcm_substream *substream, } /* use the circular buffering if we have it available. */ - if (s3c_dma_has_circular()) + if (dma_has_circular()) s3c2410_dma_setflags(prtd->params->channel, S3C2410_DMAF_CIRCULAR); } s3c2410_dma_set_buffdone_fn(prtd->params->channel, audio_buffdone); - +#endif /* CONFIG_DMADEV_PL330 */ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); runtime->dma_bytes = totbytes; @@ -206,7 +333,11 @@ static int dma_hw_free(struct snd_pcm_substream *substream) snd_pcm_set_runtime_buffer(substream, NULL); if (prtd->params) { +#if defined(CONFIG_DMADEV_PL330) + dma_release_channel(prtd->params->chan); +#else s3c2410_dma_free(prtd->params->channel, prtd->params->client); +#endif prtd->params = NULL; } @@ -218,6 +349,33 @@ static int dma_prepare(struct snd_pcm_substream *substream) struct runtime_data *prtd = substream->runtime->private_data; int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + struct dma_chan *chan = prtd->params->chan; + struct dma_slave_config slave_config; + + pr_debug("Entered %s\n", __func__); + + /* return if this is a bufferless transfer e.g. + * codec <--> BT codec or GSM modem -- lg FIXME */ + if (!prtd->params) + return 0; + + ret = dmaengine_terminate_all(chan); + if (ret) + dev_err(&chan->dev->device, "cannot flush dma channel\n"); + + memset(&slave_config, 0, sizeof(struct dma_slave_config)); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_TO_DEVICE; + slave_config.dst_addr_width = prtd->params->dma_size; + } else { + slave_config.direction = DMA_FROM_DEVICE; + slave_config.src_addr_width = prtd->params->dma_size; + } + ret = dmaengine_slave_config(chan, &slave_config); + if (ret) + dev_err(&chan->dev->device, "cannot config dma channel\n"); +#else pr_debug("Entered %s\n", __func__); /* return if this is a bufferless transfer e.g. @@ -242,6 +400,7 @@ static int dma_prepare(struct snd_pcm_substream *substream) /* flush the DMA channel */ s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_FLUSH); +#endif /* CONFIG_DMADEV_PL330 */ prtd->dma_loaded = 0; prtd->dma_pos = prtd->dma_start; @@ -256,6 +415,33 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) struct runtime_data *prtd = substream->runtime->private_data; int ret = 0; +#if defined(CONFIG_DMADEV_PL330) + struct dma_chan *chan = prtd->params->chan; + + pr_debug("Entered %s\n", __func__); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + prtd->state |= ST_RUNNING; + dma_async_issue_pending(prtd->params->chan); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->state &= ~ST_RUNNING; + ret = dmaengine_terminate_all(chan); + if (ret) + dev_err(&chan->dev->device, "cannot flush dma channel\n"); + break; + + default: + ret = -EINVAL; + break; + } +#else pr_debug("Entered %s\n", __func__); spin_lock(&prtd->lock); @@ -281,6 +467,7 @@ static int dma_trigger(struct snd_pcm_substream *substream, int cmd) } spin_unlock(&prtd->lock); +#endif /* CONFIG_DMADEV_PL330 */ return ret; } @@ -291,6 +478,14 @@ dma_pointer(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct runtime_data *prtd = runtime->private_data; unsigned long res; + +#if defined(CONFIG_DMADEV_PL330) + pr_debug("Entered %s\n", __func__); + + res = prtd->dma_pos - prtd->dma_start; + + pr_debug("Pointer offset: %lu\n", res); +#else dma_addr_t src, dst; pr_debug("Entered %s\n", __func__); @@ -306,6 +501,7 @@ dma_pointer(struct snd_pcm_substream *substream) spin_unlock(&prtd->lock); pr_debug("Pointer %x %x\n", src, dst); +#endif /* CONFIG_DMADEV_PL330 */ /* we seem to be getting the odd error from the pcm library due * to out-of-bounds pointers. this is maybe due to the dma engine diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index c506592..b6fae7e 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -17,6 +17,10 @@ struct s3c_dma_params { int channel; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ +#ifdef CONFIG_DMADEV_PL330 + struct dma_chan *chan; + struct dma_async_tx_descriptor *desc; +#endif }; #endif -- 1.7.1
next prev parent reply other threads:[~2011-07-04 12:29 UTC|newest] Thread overview: 86+ messages / expand[flat|nested] mbox.gz Atom feed top 2011-07-04 12:18 [PATCH 0/7] ARM: S5P: Use generic DMA APIs Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-04 12:18 ` [PATCH 1/7] DMA: PL330: Add support runtime PM for PL330 DMAC Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-05 6:11 ` Alim Akhtar 2011-07-05 6:11 ` Alim Akhtar 2011-07-05 7:26 ` Kukjin Kim 2011-07-05 7:26 ` Kukjin Kim 2011-07-05 8:04 ` Russell King - ARM Linux 2011-07-05 8:04 ` Russell King - ARM Linux 2011-07-08 10:18 ` Kukjin Kim 2011-07-08 10:18 ` Kukjin Kim 2011-07-04 12:18 ` [PATCH 2/7] DMA: PL330: Update PL330 DMA API driver Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-05 7:36 ` Russell King - ARM Linux 2011-07-05 7:36 ` Russell King - ARM Linux 2011-07-08 7:57 ` Kukjin Kim 2011-07-08 7:57 ` Kukjin Kim 2011-07-04 12:18 ` [PATCH 3/7] DMA: PL330: Add DMA capabilities Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-05 4:50 ` Chanho Park 2011-07-05 6:33 ` Chanho Park 2011-07-05 6:33 ` Chanho Park 2011-07-05 7:10 ` Kukjin Kim 2011-07-05 7:10 ` Kukjin Kim 2011-07-05 8:08 ` Chanho Park 2011-07-05 8:08 ` Chanho Park 2011-07-12 8:32 ` Jassi Brar 2011-07-12 8:32 ` Jassi Brar 2011-07-14 0:57 ` boojin 2011-07-14 0:57 ` boojin 2011-07-14 3:53 ` Jassi Brar 2011-07-14 3:53 ` Jassi Brar 2011-07-14 9:04 ` boojin 2011-07-14 9:04 ` boojin 2011-07-04 12:18 ` [PATCH 4/7] ARM: SAMSUNG: Update to use PL330-DMA driver Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-04 12:18 ` [PATCH 5/7] ARM: EXYNOS4: Use generic DMA PL330 driver Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-05 2:36 ` Chanho Park 2011-07-05 6:07 ` Alim Akhtar 2011-07-05 6:07 ` Alim Akhtar 2011-07-05 8:30 ` Sangwook Lee 2011-07-05 8:30 ` Sangwook Lee 2011-07-04 12:18 ` [PATCH 6/7] spi/s3c64xx: Add support DMA engine API Kukjin Kim 2011-07-04 12:18 ` Kukjin Kim 2011-07-04 16:42 ` Grant Likely 2011-07-04 16:42 ` Grant Likely 2011-07-04 16:56 ` Mark Brown 2011-07-04 16:56 ` Mark Brown 2011-07-04 16:59 ` Heiko Stübner 2011-07-04 16:59 ` Heiko Stübner 2011-07-04 17:02 ` Grant Likely 2011-07-04 17:02 ` Grant Likely 2011-07-04 19:51 ` Heiko Stübner 2011-07-04 19:51 ` Heiko Stübner 2011-07-04 23:27 ` Grant Likely 2011-07-04 23:27 ` Grant Likely 2011-07-05 7:05 ` Kukjin Kim 2011-07-05 7:05 ` Kukjin Kim 2011-07-05 7:53 ` Russell King - ARM Linux 2011-07-05 7:53 ` Russell King - ARM Linux 2011-07-05 10:51 ` Heiko Stübner 2011-07-05 10:51 ` Heiko Stübner 2011-07-05 11:16 ` Jassi Brar 2011-07-05 11:16 ` Jassi Brar 2011-07-05 11:27 ` Russell King - ARM Linux 2011-07-05 11:27 ` Russell King - ARM Linux 2011-07-05 11:45 ` Jassi Brar 2011-07-05 11:45 ` Jassi Brar 2011-07-08 9:26 ` Kukjin Kim 2011-07-08 9:26 ` Kukjin Kim 2011-07-05 7:48 ` Russell King - ARM Linux 2011-07-05 7:48 ` Russell King - ARM Linux 2011-07-05 8:39 ` Chanho Park 2011-07-05 8:39 ` Chanho Park 2011-07-04 12:18 ` Kukjin Kim [this message] 2011-07-04 12:18 ` [PATCH 7/7] ASoC: Samsung: Update DMA interface Kukjin Kim 2011-07-04 17:03 ` Mark Brown 2011-07-04 17:03 ` Mark Brown 2011-07-05 7:19 ` Kukjin Kim 2011-07-05 7:19 ` Kukjin Kim 2011-07-05 18:04 ` Grant Likely 2011-07-05 18:04 ` Grant Likely 2011-07-05 7:45 ` Seungwhan Youn 2011-07-05 7:45 ` Seungwhan Youn
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=1309781915-31549-8-git-send-email-kgene.kim@samsung.com \ --to=kgene.kim@samsung.com \ --cc=boojin.kim@samsung.com \ --cc=broonie@opensource.wolfsonmicro.com \ --cc=dan.j.williams@intel.com \ --cc=grant.likely@secretlab.ca \ --cc=jassisinghbrar@gmail.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-samsung-soc@vger.kernel.org \ --cc=lrg@ti.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: linkBe 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.