summaryrefslogtreecommitdiff
path: root/sound/soc/fsl
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r--sound/soc/fsl/mpc5200_dma.c123
-rw-r--r--sound/soc/fsl/mpc5200_dma.h24
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c39
3 files changed, 62 insertions, 124 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;
diff --git a/sound/soc/fsl/mpc5200_dma.h b/sound/soc/fsl/mpc5200_dma.h
index 8d396bb9d9fe..22208b373fb9 100644
--- a/sound/soc/fsl/mpc5200_dma.h
+++ b/sound/soc/fsl/mpc5200_dma.h
@@ -13,26 +13,25 @@
* @psc_dma: pointer back to parent psc_dma data structure
* @bcom_task: bestcomm task structure
* @irq: irq number for bestcomm task
- * @period_start: physical address of start of DMA region
* @period_end: physical address of end of DMA region
* @period_next_pt: physical address of next DMA buffer to enqueue
* @period_bytes: size of DMA period in bytes
+ * @ac97_slot_bits: Enable bits for turning on the correct AC97 slot
*/
struct psc_dma_stream {
struct snd_pcm_runtime *runtime;
- snd_pcm_uframes_t appl_ptr;
-
int active;
struct psc_dma *psc_dma;
struct bcom_task *bcom_task;
int irq;
struct snd_pcm_substream *stream;
- dma_addr_t period_start;
- dma_addr_t period_end;
- dma_addr_t period_next_pt;
- dma_addr_t period_current_pt;
+ int period_next;
+ int period_current;
int period_bytes;
- int period_size;
+ int period_count;
+
+ /* AC97 state */
+ u32 ac97_slot_bits;
};
/**
@@ -73,6 +72,15 @@ struct psc_dma {
} stats;
};
+/* Utility for retrieving psc_dma_stream structure from a substream */
+inline struct psc_dma_stream *
+to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
+{
+ if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
+ return &psc_dma->capture;
+ return &psc_dma->playback;
+}
+
int mpc5200_audio_dma_create(struct of_device *op);
int mpc5200_audio_dma_destroy(struct of_device *op);
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index c4ae3e096bb9..3dbc7f7cd7b9 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -130,6 +130,7 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct psc_dma *psc_dma = cpu_dai->private_data;
+ struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
" periods=%i buffer_size=%i buffer_bytes=%i channels=%i"
@@ -140,20 +141,10 @@ static int psc_ac97_hw_analog_params(struct snd_pcm_substream *substream,
params_channels(params), params_rate(params),
params_format(params));
-
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE) {
- if (params_channels(params) == 1)
- psc_dma->slots |= 0x00000100;
- else
- psc_dma->slots |= 0x00000300;
- } else {
- if (params_channels(params) == 1)
- psc_dma->slots |= 0x01000000;
- else
- psc_dma->slots |= 0x03000000;
- }
- out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
-
+ /* Determine the set of enable bits to turn on */
+ s->ac97_slot_bits = (params_channels(params) == 1) ? 0x100 : 0x300;
+ if (substream->pstr->stream != SNDRV_PCM_STREAM_CAPTURE)
+ s->ac97_slot_bits <<= 16;
return 0;
}
@@ -163,6 +154,8 @@ static int psc_ac97_hw_digital_params(struct snd_pcm_substream *substream,
{
struct psc_dma *psc_dma = cpu_dai->private_data;
+ dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
+
if (params_channels(params) == 1)
out_be32(&psc_dma->psc_regs->ac97_slots, 0x01000000);
else
@@ -176,14 +169,24 @@ static int psc_ac97_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 psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ dev_dbg(psc_dma->dev, "AC97 START: stream=%i\n",
+ substream->pstr->stream);
+
+ /* Set the slot enable bits */
+ psc_dma->slots |= s->ac97_slot_bits;
+ out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
+ break;
+
case SNDRV_PCM_TRIGGER_STOP:
- if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
- psc_dma->slots &= 0xFFFF0000;
- else
- psc_dma->slots &= 0x0000FFFF;
+ dev_dbg(psc_dma->dev, "AC97 STOP: stream=%i\n",
+ substream->pstr->stream);
+ /* Clear the slot enable bits */
+ psc_dma->slots &= ~(s->ac97_slot_bits);
out_be32(&psc_dma->psc_regs->ac97_slots, psc_dma->slots);
break;
}