diff options
author | Cliff Cai <cliff.cai@analog.com> | 2008-09-27 22:32:20 +0800 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-10-13 02:16:30 +0200 |
commit | 6b58a82121320f96513d88032dc3495a9c6f450b (patch) | |
tree | 0290ca3031c1ec04fca96fdb303f981f7aedcac0 | |
parent | 5564b14b88a5a34ea848732030fbc202a050daa6 (diff) | |
download | linux-6b58a82121320f96513d88032dc3495a9c6f450b.tar.bz2 |
ALSA: ASoC Blackfin: fix bug - Audio Latency on AD1981 with MMAP enabled
With MMAP enabled (DMA mode) on the AD1981, there is +/- 250ms of delay between
writing data to alsa and audio starts coming out of the AD1981.
Copy more data to local buffer before starting DMA
Signed-off-by: Cliff Cai <cliff.cai@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.c | 42 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97.c | 1 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-sport.h | 2 |
3 files changed, 37 insertions, 8 deletions
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 51f4907c4831..25e50d2ea1ec 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -56,6 +56,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, sport->tx_pos += runtime->period_size; if (sport->tx_pos >= runtime->buffer_size) sport->tx_pos %= runtime->buffer_size; + sport->tx_delay_pos = sport->tx_pos; } else { bf5xx_ac97_to_pcm( (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, @@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data) struct snd_pcm_substream *pcm = data; #if defined(CONFIG_SND_MMAP_SUPPORT) struct snd_pcm_runtime *runtime = pcm->runtime; + struct sport_device *sport = runtime->private_data; bf5xx_mmap_copy(pcm, runtime->period_size); + if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (sport->once == 0) { + snd_pcm_period_elapsed(pcm); + bf5xx_mmap_copy(pcm, runtime->period_size); + sport->once = 1; + } + } #endif snd_pcm_period_elapsed(pcm); } @@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) { + struct snd_pcm_runtime *runtime = substream->runtime; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + memset(runtime->dma_area, 0, runtime->buffer_size); snd_pcm_lib_free_pages(substream); return 0; } @@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) * SPORT working in TMD mode(include AC97). */ #if defined(CONFIG_SND_MMAP_SUPPORT) - size_t size = bf5xx_pcm_hardware.buffer_bytes_max - * sizeof(struct ac97_frame) / 4; - /*clean up intermediate buffer*/ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - memset(sport->tx_dma_buf, 0, size); sport_set_tx_callback(sport, bf5xx_dma_irq, substream); sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, runtime->period_size * sizeof(struct ac97_frame)); } else { - memset(sport->rx_dma_buf, 0, size); sport_set_rx_callback(sport, bf5xx_dma_irq, substream); sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, runtime->period_size * sizeof(struct ac97_frame)); @@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) pr_debug("%s enter\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + bf5xx_mmap_copy(substream, runtime->period_size); + snd_pcm_period_elapsed(substream); + sport->tx_delay_pos = 0; sport_tx_start(sport); + } else sport_rx_start(sport); break; @@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) #if defined(CONFIG_SND_MMAP_SUPPORT) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - curr = sport->tx_pos; + curr = sport->tx_delay_pos; else curr = sport->rx_pos; #else @@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) return ret; } +static int bf5xx_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct sport_device *sport = runtime->private_data; + + pr_debug("%s enter\n", __func__); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + sport->once = 0; + memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + } else + memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); + + return 0; +} + #ifdef CONFIG_SND_MMAP_SUPPORT static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) @@ -272,6 +299,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, struct snd_pcm_ops bf5xx_pcm_ac97_ops = { .open = bf5xx_pcm_open, + .close = bf5xx_pcm_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = bf5xx_pcm_hw_params, .hw_free = bf5xx_pcm_hw_free, diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index c782e311fd56..5e5aafb6485f 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c @@ -129,7 +129,6 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) struct ac97_frame *nextwrite; sport_incfrag(sport, &nextfrag, 1); - sport_incfrag(sport, &nextfrag, 1); nextwrite = (struct ac97_frame *)(sport->tx_buf + \ nextfrag * sport->tx_fragsize); diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h index 4c163454bbf8..fcadcc081f7f 100644 --- a/sound/soc/blackfin/bf5xx-sport.h +++ b/sound/soc/blackfin/bf5xx-sport.h @@ -123,6 +123,8 @@ struct sport_device { int rx_pos; unsigned int tx_buffer_size; unsigned int rx_buffer_size; + int tx_delay_pos; + int once; #endif void *private_data; }; |