[PATCH 8/8] ASoC i.MX: switch to new DMA api
Sascha Hauer
s.hauer at pengutronix.de
Mon Aug 9 05:05:43 EDT 2010
Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
sound/soc/imx/Makefile | 2 -
sound/soc/imx/imx-pcm-dma-mx2.c | 177 +++++++++++++++------------------------
sound/soc/imx/imx-ssi.c | 8 +-
3 files changed, 70 insertions(+), 117 deletions(-)
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 2d20363..87cf03c 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -1,9 +1,7 @@
# i.MX Platform Support
snd-soc-imx-objs := imx-ssi.o imx-pcm-fiq.o
-ifdef CONFIG_MACH_MX27
snd-soc-imx-objs += imx-pcm-dma-mx2.o
-endif
obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/imx/imx-pcm-dma-mx2.c
index 05f19c9..c672724 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/imx/imx-pcm-dma-mx2.c
@@ -27,117 +27,80 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
-#include <mach/dma-mx1-mx2.h>
+#include <mach/dma.h>
#include "imx-ssi.h"
struct imx_pcm_runtime_data {
int sg_count;
struct scatterlist *sg_list;
- int period;
+ int period_bytes;
int periods;
- unsigned long dma_addr;
int dma;
- struct snd_pcm_substream *substream;
unsigned long offset;
unsigned long size;
- unsigned long period_cnt;
void *buf;
int period_time;
};
-/* Called by the DMA framework when a period has elapsed */
-static void imx_ssi_dma_progression(int channel, void *data,
- struct scatterlist *sg)
+static void audio_dma_irq(int channel, void *data, int error)
{
- struct snd_pcm_substream *substream = data;
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- if (!sg)
- return;
-
- runtime = iprtd->substream->runtime;
-
- iprtd->offset = sg->dma_address - runtime->dma_addr;
-
- snd_pcm_period_elapsed(iprtd->substream);
-}
+ iprtd->offset += iprtd->period_bytes;
+ iprtd->offset %= iprtd->period_bytes * iprtd->periods;
-static void imx_ssi_dma_callback(int channel, void *data)
-{
- pr_err("%s shouldn't be called\n", __func__);
+ snd_pcm_period_elapsed(substream);
}
-static void snd_imx_dma_err_callback(int channel, void *data, int err)
-{
- struct snd_pcm_substream *substream = data;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct imx_pcm_dma_params *dma_params =
- snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- int ret;
-
- pr_err("DMA timeout on channel %d -%s%s%s%s\n",
- channel,
- err & IMX_DMA_ERR_BURST ? " burst" : "",
- err & IMX_DMA_ERR_REQUEST ? " request" : "",
- err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
- err & IMX_DMA_ERR_BUFFER ? " buffer" : "");
-
- imx_dma_disable(iprtd->dma);
- ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
- IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- DMA_MODE_WRITE : DMA_MODE_READ);
- if (!ret)
- imx_dma_enable(iprtd->dma);
-}
-
-static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
+static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct imx_pcm_dma_params *dma_params;
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+ struct imx_dma_config p;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
- iprtd->dma = imx_dma_request_by_prio(DRV_NAME, DMA_PRIO_HIGH);
+ iprtd->dma = imxdma_request(DMA_PRIO_HIGH);
if (iprtd->dma < 0) {
pr_err("Failed to claim the audio DMA\n");
- return -ENODEV;
+ return iprtd->dma;
}
- ret = imx_dma_setup_handlers(iprtd->dma,
- imx_ssi_dma_callback,
- snd_imx_dma_err_callback, substream);
- if (ret)
- goto out;
-
- ret = imx_dma_setup_progression_handler(iprtd->dma,
- imx_ssi_dma_progression);
- if (ret) {
- pr_err("Failed to setup the DMA handler\n");
- goto out;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ p.word_size = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ p.word_size = 4;
+ break;
}
- ret = imx_dma_config_channel(iprtd->dma,
- IMX_DMA_MEMSIZE_16 | IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
- dma_params->dma, 1);
- if (ret < 0) {
+ p.dma_request = dma_params->dma;
+ p.peripheral_type = IMX_DMATYPE_SSI;
+ p.burstlen = dma_params->burstsize;
+ p.dma_address = dma_params->dma_addr;
+ p.flags = IMX_DMA_SG_LOOP;
+ p.completion_handler = audio_dma_irq;
+ p.driver_data = substream;
+
+ ret = imxdma_config(iprtd->dma, &p);
+ if (ret) {
pr_err("Cannot configure DMA channel: %d\n", ret);
goto out;
}
- imx_dma_config_burstlen(iprtd->dma, dma_params->burstsize * 2);
-
return 0;
out:
- imx_dma_free(iprtd->dma);
+ imxdma_free(iprtd->dma);
+
return ret;
}
@@ -149,11 +112,11 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
int i;
unsigned long dma_addr;
- imx_ssi_dma_alloc(substream);
+ imx_ssi_dma_alloc(substream, params);
iprtd->size = params_buffer_bytes(params);
iprtd->periods = params_periods(params);
- iprtd->period = params_period_bytes(params);
+ iprtd->period_bytes = params_period_bytes(params);
iprtd->offset = 0;
iprtd->period_time = HZ / (params_rate(params) /
params_period_size(params));
@@ -163,30 +126,33 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
if (iprtd->sg_count != iprtd->periods) {
kfree(iprtd->sg_list);
- iprtd->sg_list = kcalloc(iprtd->periods + 1,
+ iprtd->sg_list = kcalloc(iprtd->periods,
sizeof(struct scatterlist), GFP_KERNEL);
if (!iprtd->sg_list)
return -ENOMEM;
- iprtd->sg_count = iprtd->periods + 1;
+ iprtd->sg_count = iprtd->periods;
}
sg_init_table(iprtd->sg_list, iprtd->sg_count);
dma_addr = runtime->dma_addr;
+ pr_debug("%s: setting up %d sg entries with %d bytes each\n",
+ __func__, iprtd->periods, iprtd->period_bytes);
+
for (i = 0; i < iprtd->periods; i++) {
iprtd->sg_list[i].page_link = 0;
iprtd->sg_list[i].offset = 0;
iprtd->sg_list[i].dma_address = dma_addr;
- iprtd->sg_list[i].length = iprtd->period;
- dma_addr += iprtd->period;
+ iprtd->sg_list[i].length = iprtd->period_bytes;
+ dma_addr += iprtd->period_bytes;
}
- /* close the loop */
- iprtd->sg_list[iprtd->sg_count - 1].offset = 0;
- iprtd->sg_list[iprtd->sg_count - 1].length = 0;
- iprtd->sg_list[iprtd->sg_count - 1].page_link =
- ((unsigned long) iprtd->sg_list | 0x01) & ~0x02;
- return 0;
+ iprtd->buf = (unsigned int *)substream->dma_buffer.area;
+
+ return imxdma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
+ iprtd->period_bytes * iprtd->periods,
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ DMA_MODE_WRITE : DMA_MODE_READ);
}
static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -195,7 +161,7 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
if (iprtd->dma >= 0) {
- imx_dma_free(iprtd->dma);
+ imxdma_free(iprtd->dma);
iprtd->dma = -EINVAL;
}
@@ -207,28 +173,6 @@ static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct imx_pcm_dma_params *dma_params;
- struct imx_pcm_runtime_data *iprtd = runtime->private_data;
- int err;
-
- dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
-
- iprtd->substream = substream;
- iprtd->buf = (unsigned int *)substream->dma_buffer.area;
- iprtd->period_cnt = 0;
-
- pr_debug("%s: buf: %p period: %d periods: %d\n",
- __func__, iprtd->buf, iprtd->period, iprtd->periods);
-
- err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
- IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
- DMA_MODE_WRITE : DMA_MODE_READ);
- if (err)
- return err;
-
return 0;
}
@@ -241,14 +185,14 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- imx_dma_enable(iprtd->dma);
+ imxdma_enable(iprtd->dma);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- imx_dma_disable(iprtd->dma);
+ imxdma_disable(iprtd->dma);
break;
default:
@@ -263,6 +207,9 @@ static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream
struct snd_pcm_runtime *runtime = substream->runtime;
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+ pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
+ bytes_to_frames(substream->runtime, iprtd->offset));
+
return bytes_to_frames(substream->runtime, iprtd->offset);
}
@@ -279,7 +226,7 @@ static struct snd_pcm_hardware snd_imx_hardware = {
.channels_max = 2,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
- .period_bytes_max = 16 * 1024,
+ .period_bytes_max = 65535, /* Limited by SDMA engine */
.periods_min = 2,
.periods_max = 255,
.fifo_size = 0,
@@ -303,8 +250,19 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
return 0;
}
+static int snd_imx_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+
+ kfree(iprtd);
+
+ return 0;
+}
+
static struct snd_pcm_ops imx_pcm_ops = {
.open = snd_imx_open,
+ .close = snd_imx_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params,
.hw_free = snd_imx_pcm_hw_free,
@@ -324,9 +282,8 @@ static struct snd_soc_platform imx_soc_platform_dma = {
struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev,
struct imx_ssi *ssi)
{
- ssi->dma_params_tx.burstsize = DMA_TXFIFO_BURST;
- ssi->dma_params_rx.burstsize = DMA_RXFIFO_BURST;
+ ssi->dma_params_tx.burstsize = 4;
+ ssi->dma_params_rx.burstsize = 6;
return &imx_soc_platform_dma;
}
-
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 4fd13d0..c187fe4 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -655,12 +655,10 @@ static int imx_ssi_probe(struct platform_device *pdev)
dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
dai->private_data = ssi;
- if ((cpu_is_mx27() || cpu_is_mx21()) &&
- !(ssi->flags & IMX_SSI_USE_AC97) &&
- (ssi->flags & IMX_SSI_DMA)) {
- ssi->flags |= IMX_SSI_DMA;
+ if (!(ssi->flags & IMX_SSI_USE_AC97) &&
+ (ssi->flags & IMX_SSI_DMA))
platform = imx_ssi_dma_mx2_init(pdev, ssi);
- } else
+ else
platform = imx_ssi_fiq_init(pdev, ssi);
imx_soc_platform.pcm_ops = platform->pcm_ops;
--
1.7.1
More information about the linux-arm-kernel
mailing list