diff options
author | Cliff Cai <cliff.cai@analog.com> | 2008-09-27 10:32:20 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-10-12 20:16:30 -0400 |
commit | 6b58a82121320f96513d88032dc3495a9c6f450b (patch) | |
tree | 0290ca3031c1ec04fca96fdb303f981f7aedcac0 /sound/soc/blackfin/bf5xx-ac97-pcm.c | |
parent | 5564b14b88a5a34ea848732030fbc202a050daa6 (diff) |
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>
Diffstat (limited to 'sound/soc/blackfin/bf5xx-ac97-pcm.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.c | 42 |
1 files changed, 35 insertions, 7 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, | |||
56 | sport->tx_pos += runtime->period_size; | 56 | sport->tx_pos += runtime->period_size; |
57 | if (sport->tx_pos >= runtime->buffer_size) | 57 | if (sport->tx_pos >= runtime->buffer_size) |
58 | sport->tx_pos %= runtime->buffer_size; | 58 | sport->tx_pos %= runtime->buffer_size; |
59 | sport->tx_delay_pos = sport->tx_pos; | ||
59 | } else { | 60 | } else { |
60 | bf5xx_ac97_to_pcm( | 61 | bf5xx_ac97_to_pcm( |
61 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, | 62 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, |
@@ -72,7 +73,15 @@ static void bf5xx_dma_irq(void *data) | |||
72 | struct snd_pcm_substream *pcm = data; | 73 | struct snd_pcm_substream *pcm = data; |
73 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 74 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
74 | struct snd_pcm_runtime *runtime = pcm->runtime; | 75 | struct snd_pcm_runtime *runtime = pcm->runtime; |
76 | struct sport_device *sport = runtime->private_data; | ||
75 | bf5xx_mmap_copy(pcm, runtime->period_size); | 77 | bf5xx_mmap_copy(pcm, runtime->period_size); |
78 | if (pcm->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
79 | if (sport->once == 0) { | ||
80 | snd_pcm_period_elapsed(pcm); | ||
81 | bf5xx_mmap_copy(pcm, runtime->period_size); | ||
82 | sport->once = 1; | ||
83 | } | ||
84 | } | ||
76 | #endif | 85 | #endif |
77 | snd_pcm_period_elapsed(pcm); | 86 | snd_pcm_period_elapsed(pcm); |
78 | } | 87 | } |
@@ -114,6 +123,10 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
114 | 123 | ||
115 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | 124 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) |
116 | { | 125 | { |
126 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
127 | |||
128 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
129 | memset(runtime->dma_area, 0, runtime->buffer_size); | ||
117 | snd_pcm_lib_free_pages(substream); | 130 | snd_pcm_lib_free_pages(substream); |
118 | return 0; | 131 | return 0; |
119 | } | 132 | } |
@@ -127,16 +140,11 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
127 | * SPORT working in TMD mode(include AC97). | 140 | * SPORT working in TMD mode(include AC97). |
128 | */ | 141 | */ |
129 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 142 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
130 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max | ||
131 | * sizeof(struct ac97_frame) / 4; | ||
132 | /*clean up intermediate buffer*/ | ||
133 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 143 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
134 | memset(sport->tx_dma_buf, 0, size); | ||
135 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | 144 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); |
136 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, | 145 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, |
137 | runtime->period_size * sizeof(struct ac97_frame)); | 146 | runtime->period_size * sizeof(struct ac97_frame)); |
138 | } else { | 147 | } else { |
139 | memset(sport->rx_dma_buf, 0, size); | ||
140 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); | 148 | sport_set_rx_callback(sport, bf5xx_dma_irq, substream); |
141 | sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, | 149 | sport_config_rx_dma(sport, sport->rx_dma_buf, runtime->periods, |
142 | runtime->period_size * sizeof(struct ac97_frame)); | 150 | runtime->period_size * sizeof(struct ac97_frame)); |
@@ -164,8 +172,12 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
164 | pr_debug("%s enter\n", __func__); | 172 | pr_debug("%s enter\n", __func__); |
165 | switch (cmd) { | 173 | switch (cmd) { |
166 | case SNDRV_PCM_TRIGGER_START: | 174 | case SNDRV_PCM_TRIGGER_START: |
167 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 175 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
176 | bf5xx_mmap_copy(substream, runtime->period_size); | ||
177 | snd_pcm_period_elapsed(substream); | ||
178 | sport->tx_delay_pos = 0; | ||
168 | sport_tx_start(sport); | 179 | sport_tx_start(sport); |
180 | } | ||
169 | else | 181 | else |
170 | sport_rx_start(sport); | 182 | sport_rx_start(sport); |
171 | break; | 183 | break; |
@@ -198,7 +210,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
198 | 210 | ||
199 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 211 | #if defined(CONFIG_SND_MMAP_SUPPORT) |
200 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 212 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
201 | curr = sport->tx_pos; | 213 | curr = sport->tx_delay_pos; |
202 | else | 214 | else |
203 | curr = sport->rx_pos; | 215 | curr = sport->rx_pos; |
204 | #else | 216 | #else |
@@ -237,6 +249,21 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | |||
237 | return ret; | 249 | return ret; |
238 | } | 250 | } |
239 | 251 | ||
252 | static int bf5xx_pcm_close(struct snd_pcm_substream *substream) | ||
253 | { | ||
254 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
255 | struct sport_device *sport = runtime->private_data; | ||
256 | |||
257 | pr_debug("%s enter\n", __func__); | ||
258 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
259 | sport->once = 0; | ||
260 | memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | ||
261 | } else | ||
262 | memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
240 | #ifdef CONFIG_SND_MMAP_SUPPORT | 267 | #ifdef CONFIG_SND_MMAP_SUPPORT |
241 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | 268 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, |
242 | struct vm_area_struct *vma) | 269 | struct vm_area_struct *vma) |
@@ -272,6 +299,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
272 | 299 | ||
273 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | 300 | struct snd_pcm_ops bf5xx_pcm_ac97_ops = { |
274 | .open = bf5xx_pcm_open, | 301 | .open = bf5xx_pcm_open, |
302 | .close = bf5xx_pcm_close, | ||
275 | .ioctl = snd_pcm_lib_ioctl, | 303 | .ioctl = snd_pcm_lib_ioctl, |
276 | .hw_params = bf5xx_pcm_hw_params, | 304 | .hw_params = bf5xx_pcm_hw_params, |
277 | .hw_free = bf5xx_pcm_hw_free, | 305 | .hw_free = bf5xx_pcm_hw_free, |