aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/blackfin/bf5xx-ac97-pcm.c
diff options
context:
space:
mode:
authorCliff Cai <cliff.cai@analog.com>2008-11-18 03:18:17 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2008-11-18 06:40:19 -0500
commit67f854b910613eeffec4fe71e35c0cd8c32c82ec (patch)
treee544eb4033514ec44c46e21323d0402f450ac84d /sound/soc/blackfin/bf5xx-ac97-pcm.c
parent9905ed35fdec0ebb3be8a724021ff3b104571667 (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.c80
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) 46static 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)
47static void bf5xx_mmap_copy(struct snd_pcm_substream *substream, 56static 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,
71static void bf5xx_dma_irq(void *data) 81static 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)
94static const struct snd_pcm_hardware bf5xx_pcm_hardware = { 104static 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
124static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) 134static 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)
268static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, 288static 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, \