diff options
Diffstat (limited to 'sound/soc/davinci/davinci-pcm.c')
-rw-r--r-- | sound/soc/davinci/davinci-pcm.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 7af3b5b3a53d..a05996588489 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -22,6 +22,7 @@ #include <sound/soc.h> #include <asm/dma.h> +#include <mach/edma.h> #include "davinci-pcm.h" @@ -51,7 +52,7 @@ struct davinci_runtime_data { spinlock_t lock; int period; /* current DMA period */ int master_lch; /* Master DMA channel */ - int slave_lch; /* Slave DMA channel */ + int slave_lch; /* linked parameter RAM reload slot */ struct davinci_pcm_dma_params *params; /* DMA params */ }; @@ -90,18 +91,18 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dst_bidx = data_type; } - davinci_set_dma_src_params(lch, src, INCR, W8BIT); - davinci_set_dma_dest_params(lch, dst, INCR, W8BIT); - davinci_set_dma_src_index(lch, src_bidx, 0); - davinci_set_dma_dest_index(lch, dst_bidx, 0); - davinci_set_dma_transfer_params(lch, data_type, count, 1, 0, ASYNC); + edma_set_src(lch, src, INCR, W8BIT); + edma_set_dest(lch, dst, INCR, W8BIT); + edma_set_src_index(lch, src_bidx, 0); + edma_set_dest_index(lch, dst_bidx, 0); + edma_set_transfer_params(lch, data_type, count, 1, 0, ASYNC); prtd->period++; if (unlikely(prtd->period >= runtime->periods)) prtd->period = 0; } -static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data) +static void davinci_pcm_dma_irq(unsigned lch, u16 ch_status, void *data) { struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; @@ -125,7 +126,7 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) struct davinci_runtime_data *prtd = substream->runtime->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_pcm_dma_params *dma_data = rtd->dai->cpu_dai->dma_data; - int tcc = TCC_ANY; + struct edmacc_param p_ram; int ret; if (!dma_data) @@ -134,22 +135,34 @@ static int davinci_pcm_dma_request(struct snd_pcm_substream *substream) prtd->params = dma_data; /* Request master DMA channel */ - ret = davinci_request_dma(prtd->params->channel, prtd->params->name, + ret = edma_alloc_channel(prtd->params->channel, davinci_pcm_dma_irq, substream, - &prtd->master_lch, &tcc, EVENTQ_0); - if (ret) + EVENTQ_0); + if (ret < 0) return ret; + prtd->master_lch = ret; - /* Request slave DMA channel */ - ret = davinci_request_dma(PARAM_ANY, "Link", - NULL, NULL, &prtd->slave_lch, &tcc, EVENTQ_0); - if (ret) { - davinci_free_dma(prtd->master_lch); + /* Request parameter RAM reload slot */ + ret = edma_alloc_slot(EDMA_SLOT_ANY); + if (ret < 0) { + edma_free_channel(prtd->master_lch); return ret; } - - /* Link slave DMA channel in loopback */ - davinci_dma_link_lch(prtd->slave_lch, prtd->slave_lch); + prtd->slave_lch = ret; + + /* Issue transfer completion IRQ when the channel completes a + * transfer, then always reload from the same slot (by a kind + * of loopback link). The completion IRQ handler will update + * the reload slot with a new buffer. + * + * REVISIT save p_ram here after setting up everything except + * the buffer and its length (ccnt) ... use it as a template + * so davinci_pcm_enqueue_dma() takes less time in IRQ. + */ + edma_read_slot(prtd->slave_lch, &p_ram); + p_ram.opt |= TCINTEN | EDMA_TCC(prtd->master_lch); + p_ram.link_bcntrld = prtd->slave_lch << 5; + edma_write_slot(prtd->slave_lch, &p_ram); return 0; } @@ -165,12 +178,12 @@ static int davinci_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: - davinci_start_dma(prtd->master_lch); + edma_start(prtd->master_lch); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - davinci_stop_dma(prtd->master_lch); + edma_stop(prtd->master_lch); break; default: ret = -EINVAL; @@ -185,14 +198,14 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int davinci_pcm_prepare(struct snd_pcm_substream *substream) { struct davinci_runtime_data *prtd = substream->runtime->private_data; - struct paramentry_descriptor temp; + struct edmacc_param temp; prtd->period = 0; davinci_pcm_enqueue_dma(substream); - /* Get slave channel dma params for master channel startup */ - davinci_get_dma_params(prtd->slave_lch, &temp); - davinci_set_dma_params(prtd->master_lch, &temp); + /* Copy self-linked parameter RAM entry into master channel */ + edma_read_slot(prtd->slave_lch, &temp); + edma_write_slot(prtd->master_lch, &temp); return 0; } @@ -208,7 +221,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) spin_lock(&prtd->lock); - davinci_dma_getposition(prtd->master_lch, &src, &dst); + edma_get_position(prtd->master_lch, &src, &dst); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) count = src - runtime->dma_addr; else @@ -253,10 +266,10 @@ static int davinci_pcm_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct davinci_runtime_data *prtd = runtime->private_data; - davinci_dma_unlink_lch(prtd->slave_lch, prtd->slave_lch); + edma_unlink(prtd->slave_lch); - davinci_free_dma(prtd->slave_lch); - davinci_free_dma(prtd->master_lch); + edma_free_slot(prtd->slave_lch); + edma_free_channel(prtd->master_lch); kfree(prtd); |