summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/mpc5200_dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/mpc5200_dma.c')
-rw-r--r--sound/soc/fsl/mpc5200_dma.c123
1 files changed, 25 insertions, 98 deletions
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index 6096d22283e6..30ed568afb2e 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -58,47 +58,15 @@ static void psc_dma_bcom_enqueue_next_buffer(struct psc_dma_stream *s)
/* Prepare and enqueue the next buffer descriptor */
bd = bcom_prepare_next_buffer(s->bcom_task);
bd->status = s->period_bytes;
- bd->data[0] = s->period_next_pt;
+ bd->data[0] = s->runtime->dma_addr + (s->period_next * s->period_bytes);
bcom_submit_next_buffer(s->bcom_task, NULL);
/* Update for next period */
- s->period_next_pt += s->period_bytes;
- if (s->period_next_pt >= s->period_end)
- s->period_next_pt = s->period_start;
-}
-
-static void psc_dma_bcom_enqueue_tx(struct psc_dma_stream *s)
-{
- if (s->appl_ptr > s->runtime->control->appl_ptr) {
- /*
- * In this case s->runtime->control->appl_ptr has wrapped around.
- * Play the data to the end of the boundary, then wrap our own
- * appl_ptr back around.
- */
- while (s->appl_ptr < s->runtime->boundary) {
- if (bcom_queue_full(s->bcom_task))
- return;
-
- s->appl_ptr += s->period_size;
-
- psc_dma_bcom_enqueue_next_buffer(s);
- }
- s->appl_ptr -= s->runtime->boundary;
- }
-
- while (s->appl_ptr < s->runtime->control->appl_ptr) {
-
- if (bcom_queue_full(s->bcom_task))
- return;
-
- s->appl_ptr += s->period_size;
-
- psc_dma_bcom_enqueue_next_buffer(s);
- }
+ s->period_next = (s->period_next + 1) % s->runtime->periods;
}
/* Bestcomm DMA irq handler */
-static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
+static irqreturn_t psc_dma_bcom_irq(int irq, void *_psc_dma_stream)
{
struct psc_dma_stream *s = _psc_dma_stream;
@@ -108,34 +76,8 @@ static irqreturn_t psc_dma_bcom_irq_tx(int irq, void *_psc_dma_stream)
while (bcom_buffer_done(s->bcom_task)) {
bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
- s->period_current_pt += s->period_bytes;
- if (s->period_current_pt >= s->period_end)
- s->period_current_pt = s->period_start;
- }
- psc_dma_bcom_enqueue_tx(s);
- spin_unlock(&s->psc_dma->lock);
-
- /* If the stream is active, then also inform the PCM middle layer
- * of the period finished event. */
- if (s->active)
- snd_pcm_period_elapsed(s->stream);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t psc_dma_bcom_irq_rx(int irq, void *_psc_dma_stream)
-{
- struct psc_dma_stream *s = _psc_dma_stream;
-
- spin_lock(&s->psc_dma->lock);
- /* For each finished period, dequeue the completed period buffer
- * and enqueue a new one in it's place. */
- while (bcom_buffer_done(s->bcom_task)) {
- bcom_retrieve_buffer(s->bcom_task, NULL, NULL);
-
- s->period_current_pt += s->period_bytes;
- if (s->period_current_pt >= s->period_end)
- s->period_current_pt = s->period_start;
+ s->period_current = (s->period_current+1) % s->runtime->periods;
+ s->period_count++;
psc_dma_bcom_enqueue_next_buffer(s);
}
@@ -166,54 +108,38 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
- struct psc_dma_stream *s;
+ struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
u16 imr;
unsigned long flags;
int i;
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- s = &psc_dma->capture;
- else
- s = &psc_dma->playback;
-
- dev_dbg(psc_dma->dev, "psc_dma_trigger(substream=%p, cmd=%i)"
- " stream_id=%i\n",
- substream, cmd, substream->pstr->stream);
-
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ dev_dbg(psc_dma->dev, "START: stream=%i fbits=%u ps=%u #p=%u\n",
+ substream->pstr->stream, runtime->frame_bits,
+ (int)runtime->period_size, runtime->periods);
s->period_bytes = frames_to_bytes(runtime,
runtime->period_size);
- s->period_start = virt_to_phys(runtime->dma_area);
- s->period_end = s->period_start +
- (s->period_bytes * runtime->periods);
- s->period_next_pt = s->period_start;
- s->period_current_pt = s->period_start;
- s->period_size = runtime->period_size;
+ s->period_next = 0;
+ s->period_current = 0;
s->active = 1;
-
- /* track appl_ptr so that we have a better chance of detecting
- * end of stream and not over running it.
- */
+ s->period_count = 0;
s->runtime = runtime;
- s->appl_ptr = s->runtime->control->appl_ptr -
- (runtime->period_size * runtime->periods);
/* Fill up the bestcomm bd queue and enable DMA.
* This will begin filling the PSC's fifo.
*/
spin_lock_irqsave(&psc_dma->lock, flags);
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
bcom_gen_bd_rx_reset(s->bcom_task);
- for (i = 0; i < runtime->periods; i++)
- if (!bcom_queue_full(s->bcom_task))
- psc_dma_bcom_enqueue_next_buffer(s);
- } else {
+ else
bcom_gen_bd_tx_reset(s->bcom_task);
- psc_dma_bcom_enqueue_tx(s);
- }
+
+ for (i = 0; i < runtime->periods; i++)
+ if (!bcom_queue_full(s->bcom_task))
+ psc_dma_bcom_enqueue_next_buffer(s);
bcom_enable(s->bcom_task);
spin_unlock_irqrestore(&psc_dma->lock, flags);
@@ -223,6 +149,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
break;
case SNDRV_PCM_TRIGGER_STOP:
+ dev_dbg(psc_dma->dev, "STOP: stream=%i periods_count=%i\n",
+ substream->pstr->stream, s->period_count);
s->active = 0;
spin_lock_irqsave(&psc_dma->lock, flags);
@@ -236,7 +164,8 @@ static int psc_dma_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
- dev_dbg(psc_dma->dev, "invalid command\n");
+ dev_dbg(psc_dma->dev, "unhandled trigger: stream=%i cmd=%i\n",
+ substream->pstr->stream, cmd);
return -EINVAL;
}
@@ -343,7 +272,7 @@ psc_dma_pointer(struct snd_pcm_substream *substream)
else
s = &psc_dma->playback;
- count = s->period_current_pt - s->period_start;
+ count = s->period_current * s->period_bytes;
return bytes_to_frames(substream->runtime, count);
}
@@ -532,11 +461,9 @@ int mpc5200_audio_dma_create(struct of_device *op)
rc = request_irq(psc_dma->irq, &psc_dma_status_irq, IRQF_SHARED,
"psc-dma-status", psc_dma);
- rc |= request_irq(psc_dma->capture.irq,
- &psc_dma_bcom_irq_rx, IRQF_SHARED,
+ rc |= request_irq(psc_dma->capture.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-capture", &psc_dma->capture);
- rc |= request_irq(psc_dma->playback.irq,
- &psc_dma_bcom_irq_tx, IRQF_SHARED,
+ rc |= request_irq(psc_dma->playback.irq, &psc_dma_bcom_irq, IRQF_SHARED,
"psc-dma-playback", &psc_dma->playback);
if (rc) {
ret = -ENODEV;