aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/davinci
diff options
context:
space:
mode:
authorBen Gardiner <bengardiner@nanometrics.ca>2011-05-24 14:50:20 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-05-25 07:14:31 -0400
commit52e2c5d38ea6f13a19c29da7ba5183e6fac55400 (patch)
tree7824cdb94a0f448862eb975795c8054c5aab5bca /sound/soc/davinci
parent10ab3bfda41ea21419f6a8d1e5a645521fea4b32 (diff)
ASoC: davinci-pcm: convert to BATCH mode
The davinci-pcm driver's snd_pcm_ops pointer function currently calls into the edma controller driver to read the current positions of the edma channels to determine pos to return to the ALSA framework. In particular, davinci_pcm_pointer() calls edma_get_position() and the latter has a comment indicating that "Its channel should not be active when this is called" whereas the channel is surely active when snd_pcm_ops.pointer is called. The operation of davinci-pcm in capture and playback appears to follow close the other pcm drivers who export SNDRV_PCM_INFO_BATCH except that davinci-pcm does not report it's positions from pointer() using the last transferred chunk. Instead it peeks directly into the edma controller to determine the current position as discussed above. Convert the davinci-pcm driver to BATCH mode: count the periods elapsed in the prtd->period member and use its value to report the 'pos' to the alsa framework in the davinci_pcm_pointer function. There is a phase offset of 2 periods between the position used by dma setup and the position reported in the pointer function. Either +2 in the dma setup or -2 in the pointer function (with wrapping, both) accounts for this offset -- I opted for the latter since it makes the first-time setup clearer. Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca> Reviewed-by: Steven Faludi <stevenfaludi@nanometrics.ca> Acked-by: Liam Girdwood <lrg@ti.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r--sound/soc/davinci/davinci-pcm.c67
1 files changed, 19 insertions, 48 deletions
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c
index fedca81b67b4..fa8fc617c0db 100644
--- a/sound/soc/davinci/davinci-pcm.c
+++ b/sound/soc/davinci/davinci-pcm.c
@@ -65,7 +65,8 @@ static void print_buf_info(int slot, char *name)
65static struct snd_pcm_hardware pcm_hardware_playback = { 65static struct snd_pcm_hardware pcm_hardware_playback = {
66 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 66 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
67 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 67 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
68 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), 68 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME|
69 SNDRV_PCM_INFO_BATCH),
69 .formats = DAVINCI_PCM_FMTBITS, 70 .formats = DAVINCI_PCM_FMTBITS,
70 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 71 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
71 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | 72 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
@@ -87,7 +88,8 @@ static struct snd_pcm_hardware pcm_hardware_playback = {
87static struct snd_pcm_hardware pcm_hardware_capture = { 88static struct snd_pcm_hardware pcm_hardware_capture = {
88 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 89 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
89 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | 90 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
90 SNDRV_PCM_INFO_PAUSE), 91 SNDRV_PCM_INFO_PAUSE |
92 SNDRV_PCM_INFO_BATCH),
91 .formats = DAVINCI_PCM_FMTBITS, 93 .formats = DAVINCI_PCM_FMTBITS,
92 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 94 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
93 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | 95 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |
@@ -231,8 +233,6 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
231 else 233 else
232 edma_set_transfer_params(link, acnt, fifo_level, count, 234 edma_set_transfer_params(link, acnt, fifo_level, count,
233 fifo_level, ABSYNC); 235 fifo_level, ABSYNC);
234
235 davinci_pcm_period_elapsed(substream);
236} 236}
237 237
238static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) 238static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
@@ -247,12 +247,13 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
247 return; 247 return;
248 248
249 if (snd_pcm_running(substream)) { 249 if (snd_pcm_running(substream)) {
250 spin_lock(&prtd->lock);
250 if (prtd->ram_channel < 0) { 251 if (prtd->ram_channel < 0) {
251 /* No ping/pong must fix up link dma data*/ 252 /* No ping/pong must fix up link dma data*/
252 spin_lock(&prtd->lock);
253 davinci_pcm_enqueue_dma(substream); 253 davinci_pcm_enqueue_dma(substream);
254 spin_unlock(&prtd->lock);
255 } 254 }
255 davinci_pcm_period_elapsed(substream);
256 spin_unlock(&prtd->lock);
256 snd_pcm_period_elapsed(substream); 257 snd_pcm_period_elapsed(substream);
257 } 258 }
258} 259}
@@ -588,6 +589,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
588{ 589{
589 struct davinci_runtime_data *prtd = substream->runtime->private_data; 590 struct davinci_runtime_data *prtd = substream->runtime->private_data;
590 591
592 davinci_pcm_period_reset(substream);
591 if (prtd->ram_channel >= 0) { 593 if (prtd->ram_channel >= 0) {
592 int ret = ping_pong_dma_setup(substream); 594 int ret = ping_pong_dma_setup(substream);
593 if (ret < 0) 595 if (ret < 0)
@@ -603,15 +605,19 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream)
603 print_buf_info(prtd->asp_link[0], "asp_link[0]"); 605 print_buf_info(prtd->asp_link[0], "asp_link[0]");
604 print_buf_info(prtd->asp_link[1], "asp_link[1]"); 606 print_buf_info(prtd->asp_link[1], "asp_link[1]");
605 607
608 davinci_pcm_period_elapsed(substream);
609 davinci_pcm_period_elapsed(substream);
610
606 return 0; 611 return 0;
607 } 612 }
608 davinci_pcm_period_reset(substream);
609 davinci_pcm_enqueue_dma(substream); 613 davinci_pcm_enqueue_dma(substream);
614 davinci_pcm_period_elapsed(substream);
610 615
611 /* Copy self-linked parameter RAM entry into master channel */ 616 /* Copy self-linked parameter RAM entry into master channel */
612 edma_read_slot(prtd->asp_link[0], &prtd->asp_params); 617 edma_read_slot(prtd->asp_link[0], &prtd->asp_params);
613 edma_write_slot(prtd->asp_channel, &prtd->asp_params); 618 edma_write_slot(prtd->asp_channel, &prtd->asp_params);
614 davinci_pcm_enqueue_dma(substream); 619 davinci_pcm_enqueue_dma(substream);
620 davinci_pcm_period_elapsed(substream);
615 621
616 return 0; 622 return 0;
617} 623}
@@ -623,51 +629,16 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream)
623 struct davinci_runtime_data *prtd = runtime->private_data; 629 struct davinci_runtime_data *prtd = runtime->private_data;
624 unsigned int offset; 630 unsigned int offset;
625 int asp_count; 631 int asp_count;
626 dma_addr_t asp_src, asp_dst; 632 unsigned int period_size = snd_pcm_lib_period_bytes(substream);
627 633
628 spin_lock(&prtd->lock); 634 spin_lock(&prtd->lock);
629 if (prtd->ram_channel >= 0) { 635 asp_count = prtd->period - 2;
630 int ram_count;
631 int mod_ram;
632 dma_addr_t ram_src, ram_dst;
633 unsigned int period_size = snd_pcm_lib_period_bytes(substream);
634 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
635 /* reading ram before asp should be safe
636 * as long as the asp transfers less than a ping size
637 * of bytes between the 2 reads
638 */
639 edma_get_position(prtd->ram_channel,
640 &ram_src, &ram_dst);
641 edma_get_position(prtd->asp_channel,
642 &asp_src, &asp_dst);
643 asp_count = asp_src - prtd->asp_params.src;
644 ram_count = ram_src - prtd->ram_params.src;
645 mod_ram = ram_count % period_size;
646 mod_ram -= asp_count;
647 if (mod_ram < 0)
648 mod_ram += period_size;
649 else if (mod_ram == 0) {
650 if (snd_pcm_running(substream))
651 mod_ram += period_size;
652 }
653 ram_count -= mod_ram;
654 if (ram_count < 0)
655 ram_count += period_size * runtime->periods;
656 } else {
657 edma_get_position(prtd->ram_channel,
658 &ram_src, &ram_dst);
659 ram_count = ram_dst - prtd->ram_params.dst;
660 }
661 asp_count = ram_count;
662 } else {
663 edma_get_position(prtd->asp_channel, &asp_src, &asp_dst);
664 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
665 asp_count = asp_src - runtime->dma_addr;
666 else
667 asp_count = asp_dst - runtime->dma_addr;
668 }
669 spin_unlock(&prtd->lock); 636 spin_unlock(&prtd->lock);
670 637
638 if (asp_count < 0)
639 asp_count += runtime->periods;
640 asp_count *= period_size;
641
671 offset = bytes_to_frames(runtime, asp_count); 642 offset = bytes_to_frames(runtime, asp_count);
672 if (offset >= runtime->buffer_size) 643 if (offset >= runtime->buffer_size)
673 offset = 0; 644 offset = 0;