diff options
author | Cliff Cai <cliff.cai@analog.com> | 2008-11-18 03:18:17 -0500 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2008-11-18 06:40:19 -0500 |
commit | 67f854b910613eeffec4fe71e35c0cd8c32c82ec (patch) | |
tree | e544eb4033514ec44c46e21323d0402f450ac84d /sound/soc/blackfin/bf5xx-ac97-pcm.c | |
parent | 9905ed35fdec0ebb3be8a724021ff3b104571667 (diff) |
ASoC: Blackfin: add multi-channel function support
This patch provides a option for users to enable multi-channel function support
in Blackfin ASoC driver. Because Blackfin is without MMU, it is easy for us and
the user to enable this function at compiling stage not dynamically on the fly.
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>
Diffstat (limited to 'sound/soc/blackfin/bf5xx-ac97-pcm.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.c | 80 |
1 files changed, 49 insertions, 31 deletions
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 25e50d2ea1ec..4be1a490f4fb 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -43,24 +43,34 @@ | |||
43 | #include "bf5xx-ac97.h" | 43 | #include "bf5xx-ac97.h" |
44 | #include "bf5xx-sport.h" | 44 | #include "bf5xx-sport.h" |
45 | 45 | ||
46 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 46 | static unsigned int ac97_chan_mask[] = { |
47 | SP_FL, /* Mono */ | ||
48 | SP_STEREO, /* Stereo */ | ||
49 | SP_2DOT1, /* 2.1*/ | ||
50 | SP_QUAD,/*Quadraquic*/ | ||
51 | SP_FL | SP_FR | SP_FC | SP_SL | SP_SR,/*5 channels */ | ||
52 | SP_5DOT1, /* 5.1 */ | ||
53 | }; | ||
54 | |||
55 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) | ||
47 | static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, | 56 | static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, |
48 | snd_pcm_uframes_t count) | 57 | snd_pcm_uframes_t count) |
49 | { | 58 | { |
50 | struct snd_pcm_runtime *runtime = substream->runtime; | 59 | struct snd_pcm_runtime *runtime = substream->runtime; |
51 | struct sport_device *sport = runtime->private_data; | 60 | struct sport_device *sport = runtime->private_data; |
61 | unsigned int chan_mask = ac97_chan_mask[runtime->channels - 1]; | ||
52 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 62 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
53 | bf5xx_pcm_to_ac97( | 63 | bf5xx_pcm_to_ac97((struct ac97_frame *)sport->tx_dma_buf + |
54 | (struct ac97_frame *)sport->tx_dma_buf + sport->tx_pos, | 64 | sport->tx_pos, (__u16 *)runtime->dma_area + sport->tx_pos * |
55 | (__u32 *)runtime->dma_area + sport->tx_pos, count); | 65 | runtime->channels, count, chan_mask); |
56 | sport->tx_pos += runtime->period_size; | 66 | sport->tx_pos += runtime->period_size; |
57 | if (sport->tx_pos >= runtime->buffer_size) | 67 | if (sport->tx_pos >= runtime->buffer_size) |
58 | sport->tx_pos %= runtime->buffer_size; | 68 | sport->tx_pos %= runtime->buffer_size; |
59 | sport->tx_delay_pos = sport->tx_pos; | 69 | sport->tx_delay_pos = sport->tx_pos; |
60 | } else { | 70 | } else { |
61 | bf5xx_ac97_to_pcm( | 71 | bf5xx_ac97_to_pcm((struct ac97_frame *)sport->rx_dma_buf + |
62 | (struct ac97_frame *)sport->rx_dma_buf + sport->rx_pos, | 72 | sport->rx_pos, (__u16 *)runtime->dma_area + sport->rx_pos * |
63 | (__u32 *)runtime->dma_area + sport->rx_pos, count); | 73 | runtime->channels, count); |
64 | sport->rx_pos += runtime->period_size; | 74 | sport->rx_pos += runtime->period_size; |
65 | if (sport->rx_pos >= runtime->buffer_size) | 75 | if (sport->rx_pos >= runtime->buffer_size) |
66 | sport->rx_pos %= runtime->buffer_size; | 76 | sport->rx_pos %= runtime->buffer_size; |
@@ -71,7 +81,7 @@ static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, | |||
71 | static void bf5xx_dma_irq(void *data) | 81 | static void bf5xx_dma_irq(void *data) |
72 | { | 82 | { |
73 | struct snd_pcm_substream *pcm = data; | 83 | struct snd_pcm_substream *pcm = data; |
74 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 84 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
75 | struct snd_pcm_runtime *runtime = pcm->runtime; | 85 | struct snd_pcm_runtime *runtime = pcm->runtime; |
76 | struct sport_device *sport = runtime->private_data; | 86 | struct sport_device *sport = runtime->private_data; |
77 | bf5xx_mmap_copy(pcm, runtime->period_size); | 87 | bf5xx_mmap_copy(pcm, runtime->period_size); |
@@ -90,7 +100,7 @@ static void bf5xx_dma_irq(void *data) | |||
90 | * The total rx/tx buffer is for ac97 frame to hold all pcm data | 100 | * The total rx/tx buffer is for ac97 frame to hold all pcm data |
91 | * is 0x20000 * sizeof(struct ac97_frame) / 4. | 101 | * is 0x20000 * sizeof(struct ac97_frame) / 4. |
92 | */ | 102 | */ |
93 | #ifdef CONFIG_SND_MMAP_SUPPORT | 103 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
94 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | 104 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { |
95 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 105 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
96 | SNDRV_PCM_INFO_MMAP | | 106 | SNDRV_PCM_INFO_MMAP | |
@@ -123,10 +133,20 @@ static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
123 | 133 | ||
124 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | 134 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) |
125 | { | 135 | { |
136 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) | ||
126 | struct snd_pcm_runtime *runtime = substream->runtime; | 137 | struct snd_pcm_runtime *runtime = substream->runtime; |
138 | struct sport_device *sport = runtime->private_data; | ||
127 | 139 | ||
128 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 140 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
129 | memset(runtime->dma_area, 0, runtime->buffer_size); | 141 | sport->once = 0; |
142 | if (runtime->dma_area) | ||
143 | memset(runtime->dma_area, 0, runtime->buffer_size); | ||
144 | memset(sport->tx_dma_buf, 0, runtime->buffer_size * | ||
145 | sizeof(struct ac97_frame)); | ||
146 | } else | ||
147 | memset(sport->rx_dma_buf, 0, runtime->buffer_size * | ||
148 | sizeof(struct ac97_frame)); | ||
149 | #endif | ||
130 | snd_pcm_lib_free_pages(substream); | 150 | snd_pcm_lib_free_pages(substream); |
131 | return 0; | 151 | return 0; |
132 | } | 152 | } |
@@ -139,7 +159,7 @@ static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
139 | /* An intermediate buffer is introduced for implementing mmap for | 159 | /* An intermediate buffer is introduced for implementing mmap for |
140 | * SPORT working in TMD mode(include AC97). | 160 | * SPORT working in TMD mode(include AC97). |
141 | */ | 161 | */ |
142 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 162 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
143 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 163 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
144 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); | 164 | sport_set_tx_callback(sport, bf5xx_dma_irq, substream); |
145 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, | 165 | sport_config_tx_dma(sport, sport->tx_dma_buf, runtime->periods, |
@@ -174,23 +194,21 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
174 | case SNDRV_PCM_TRIGGER_START: | 194 | case SNDRV_PCM_TRIGGER_START: |
175 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 195 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
176 | bf5xx_mmap_copy(substream, runtime->period_size); | 196 | bf5xx_mmap_copy(substream, runtime->period_size); |
177 | snd_pcm_period_elapsed(substream); | ||
178 | sport->tx_delay_pos = 0; | 197 | sport->tx_delay_pos = 0; |
179 | sport_tx_start(sport); | 198 | sport_tx_start(sport); |
180 | } | 199 | } else |
181 | else | ||
182 | sport_rx_start(sport); | 200 | sport_rx_start(sport); |
183 | break; | 201 | break; |
184 | case SNDRV_PCM_TRIGGER_STOP: | 202 | case SNDRV_PCM_TRIGGER_STOP: |
185 | case SNDRV_PCM_TRIGGER_SUSPEND: | 203 | case SNDRV_PCM_TRIGGER_SUSPEND: |
186 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 204 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
187 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 205 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
188 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 206 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
189 | sport->tx_pos = 0; | 207 | sport->tx_pos = 0; |
190 | #endif | 208 | #endif |
191 | sport_tx_stop(sport); | 209 | sport_tx_stop(sport); |
192 | } else { | 210 | } else { |
193 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 211 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
194 | sport->rx_pos = 0; | 212 | sport->rx_pos = 0; |
195 | #endif | 213 | #endif |
196 | sport_rx_stop(sport); | 214 | sport_rx_stop(sport); |
@@ -208,7 +226,7 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
208 | struct sport_device *sport = runtime->private_data; | 226 | struct sport_device *sport = runtime->private_data; |
209 | unsigned int curr; | 227 | unsigned int curr; |
210 | 228 | ||
211 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 229 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
212 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 230 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
213 | curr = sport->tx_delay_pos; | 231 | curr = sport->tx_delay_pos; |
214 | else | 232 | else |
@@ -257,14 +275,16 @@ static int bf5xx_pcm_close(struct snd_pcm_substream *substream) | |||
257 | pr_debug("%s enter\n", __func__); | 275 | pr_debug("%s enter\n", __func__); |
258 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 276 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
259 | sport->once = 0; | 277 | sport->once = 0; |
260 | memset(sport->tx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | 278 | memset(sport->tx_dma_buf, 0, runtime->buffer_size * |
279 | sizeof(struct ac97_frame)); | ||
261 | } else | 280 | } else |
262 | memset(sport->rx_dma_buf, 0, runtime->buffer_size * sizeof(struct ac97_frame)); | 281 | memset(sport->rx_dma_buf, 0, runtime->buffer_size * |
282 | sizeof(struct ac97_frame)); | ||
263 | 283 | ||
264 | return 0; | 284 | return 0; |
265 | } | 285 | } |
266 | 286 | ||
267 | #ifdef CONFIG_SND_MMAP_SUPPORT | 287 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
268 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | 288 | static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, |
269 | struct vm_area_struct *vma) | 289 | struct vm_area_struct *vma) |
270 | { | 290 | { |
@@ -286,13 +306,11 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
286 | substream->stream ? "Capture" : "Playback", pos, count); | 306 | substream->stream ? "Capture" : "Playback", pos, count); |
287 | 307 | ||
288 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 308 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
289 | bf5xx_pcm_to_ac97( | 309 | bf5xx_pcm_to_ac97((struct ac97_frame *)runtime->dma_area + pos, |
290 | (struct ac97_frame *)runtime->dma_area + pos, | 310 | (__u16 *)buf, count, chan_mask); |
291 | buf, count); | ||
292 | else | 311 | else |
293 | bf5xx_ac97_to_pcm( | 312 | bf5xx_ac97_to_pcm((struct ac97_frame *)runtime->dma_area + pos, |
294 | (struct ac97_frame *)runtime->dma_area + pos, | 313 | (__u16 *)buf, count); |
295 | buf, count); | ||
296 | return 0; | 314 | return 0; |
297 | } | 315 | } |
298 | #endif | 316 | #endif |
@@ -306,7 +324,7 @@ struct snd_pcm_ops bf5xx_pcm_ac97_ops = { | |||
306 | .prepare = bf5xx_pcm_prepare, | 324 | .prepare = bf5xx_pcm_prepare, |
307 | .trigger = bf5xx_pcm_trigger, | 325 | .trigger = bf5xx_pcm_trigger, |
308 | .pointer = bf5xx_pcm_pointer, | 326 | .pointer = bf5xx_pcm_pointer, |
309 | #ifdef CONFIG_SND_MMAP_SUPPORT | 327 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
310 | .mmap = bf5xx_pcm_mmap, | 328 | .mmap = bf5xx_pcm_mmap, |
311 | #else | 329 | #else |
312 | .copy = bf5xx_pcm_copy, | 330 | .copy = bf5xx_pcm_copy, |
@@ -344,7 +362,7 @@ static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
344 | * Need to allocate local buffer when enable | 362 | * Need to allocate local buffer when enable |
345 | * MMAP for SPORT working in TMD mode (include AC97). | 363 | * MMAP for SPORT working in TMD mode (include AC97). |
346 | */ | 364 | */ |
347 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 365 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
348 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 366 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
349 | if (!sport_handle->tx_dma_buf) { | 367 | if (!sport_handle->tx_dma_buf) { |
350 | sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ | 368 | sport_handle->tx_dma_buf = dma_alloc_coherent(NULL, \ |
@@ -381,7 +399,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
381 | struct snd_pcm_substream *substream; | 399 | struct snd_pcm_substream *substream; |
382 | struct snd_dma_buffer *buf; | 400 | struct snd_dma_buffer *buf; |
383 | int stream; | 401 | int stream; |
384 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 402 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
385 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max * | 403 | size_t size = bf5xx_pcm_hardware.buffer_bytes_max * |
386 | sizeof(struct ac97_frame) / 4; | 404 | sizeof(struct ac97_frame) / 4; |
387 | #endif | 405 | #endif |
@@ -395,7 +413,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
395 | continue; | 413 | continue; |
396 | dma_free_coherent(NULL, buf->bytes, buf->area, 0); | 414 | dma_free_coherent(NULL, buf->bytes, buf->area, 0); |
397 | buf->area = NULL; | 415 | buf->area = NULL; |
398 | #if defined(CONFIG_SND_MMAP_SUPPORT) | 416 | #if defined(CONFIG_SND_BF5XX_MMAP_SUPPORT) |
399 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 417 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
400 | if (sport_handle->tx_dma_buf) | 418 | if (sport_handle->tx_dma_buf) |
401 | dma_free_coherent(NULL, size, \ | 419 | dma_free_coherent(NULL, size, \ |