aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/blackfin
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
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')
-rw-r--r--sound/soc/blackfin/Kconfig14
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c80
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c156
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.h35
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h2
5 files changed, 184 insertions, 103 deletions
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 3fce18788b77..43d89fc253ae 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -47,7 +47,7 @@ config SND_BF5XX_AC97
47 properly with this driver. This driver is known to work with the 47 properly with this driver. This driver is known to work with the
48 Analog Devices line of AC97 codecs. 48 Analog Devices line of AC97 codecs.
49 49
50config SND_MMAP_SUPPORT 50config SND_BF5XX_MMAP_SUPPORT
51 bool "Enable MMAP Support" 51 bool "Enable MMAP Support"
52 depends on SND_BF5XX_AC97 52 depends on SND_BF5XX_AC97
53 default y 53 default y
@@ -55,9 +55,17 @@ config SND_MMAP_SUPPORT
55 Say y if you want AC97 driver to support mmap mode. 55 Say y if you want AC97 driver to support mmap mode.
56 We introduce an intermediate buffer to simulate mmap. 56 We introduce an intermediate buffer to simulate mmap.
57 57
58config SND_BF5XX_MULTICHAN_SUPPORT
59 bool "Enable Multichannel Support"
60 depends on SND_BF5XX_AC97
61 default n
62 help
63 Say y if you want AC97 driver to support up to 5.1 channel audio.
64 this mode will consume much more memory for DMA.
65
58config SND_BF5XX_SOC_SPORT 66config SND_BF5XX_SOC_SPORT
59 tristate 67 tristate
60 68
61config SND_BF5XX_SOC_I2S 69config SND_BF5XX_SOC_I2S
62 tristate 70 tristate
63 select SND_BF5XX_SOC_SPORT 71 select SND_BF5XX_SOC_SPORT
@@ -90,7 +98,7 @@ config SND_BF5XX_HAVE_COLD_RESET
90 depends on SND_BF5XX_AC97 98 depends on SND_BF5XX_AC97
91 default y if BFIN548_EZKIT 99 default y if BFIN548_EZKIT
92 default n if !BFIN548_EZKIT 100 default n if !BFIN548_EZKIT
93 101
94config SND_BF5XX_RESET_GPIO_NUM 102config SND_BF5XX_RESET_GPIO_NUM
95 int "Set a GPIO for cold reset" 103 int "Set a GPIO for cold reset"
96 depends on SND_BF5XX_HAVE_COLD_RESET 104 depends on SND_BF5XX_HAVE_COLD_RESET
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, \
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 5e5aafb6485f..65c162c4bfad 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -54,71 +54,103 @@
54static int *cmd_count; 54static int *cmd_count;
55static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; 55static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
56 56
57#if defined(CONFIG_BF54x) 57static u16 sport_req[][7] = {
58 PIN_REQ_SPORT_0,
59#ifdef PIN_REQ_SPORT_1
60 PIN_REQ_SPORT_1,
61#endif
62#ifdef PIN_REQ_SPORT_2
63 PIN_REQ_SPORT_2,
64#endif
65#ifdef PIN_REQ_SPORT_3
66 PIN_REQ_SPORT_3,
67#endif
68 };
69
58static struct sport_param sport_params[4] = { 70static struct sport_param sport_params[4] = {
59 { 71 {
60 .dma_rx_chan = CH_SPORT0_RX, 72 .dma_rx_chan = CH_SPORT0_RX,
61 .dma_tx_chan = CH_SPORT0_TX, 73 .dma_tx_chan = CH_SPORT0_TX,
62 .err_irq = IRQ_SPORT0_ERR, 74 .err_irq = IRQ_SPORT0_ERROR,
63 .regs = (struct sport_register *)SPORT0_TCR1, 75 .regs = (struct sport_register *)SPORT0_TCR1,
64 }, 76 },
77#ifdef PIN_REQ_SPORT_1
65 { 78 {
66 .dma_rx_chan = CH_SPORT1_RX, 79 .dma_rx_chan = CH_SPORT1_RX,
67 .dma_tx_chan = CH_SPORT1_TX, 80 .dma_tx_chan = CH_SPORT1_TX,
68 .err_irq = IRQ_SPORT1_ERR, 81 .err_irq = IRQ_SPORT1_ERROR,
69 .regs = (struct sport_register *)SPORT1_TCR1, 82 .regs = (struct sport_register *)SPORT1_TCR1,
70 }, 83 },
84#endif
85#ifdef PIN_REQ_SPORT_2
71 { 86 {
72 .dma_rx_chan = CH_SPORT2_RX, 87 .dma_rx_chan = CH_SPORT2_RX,
73 .dma_tx_chan = CH_SPORT2_TX, 88 .dma_tx_chan = CH_SPORT2_TX,
74 .err_irq = IRQ_SPORT2_ERR, 89 .err_irq = IRQ_SPORT2_ERROR,
75 .regs = (struct sport_register *)SPORT2_TCR1, 90 .regs = (struct sport_register *)SPORT2_TCR1,
76 }, 91 },
92#endif
93#ifdef PIN_REQ_SPORT_3
77 { 94 {
78 .dma_rx_chan = CH_SPORT3_RX, 95 .dma_rx_chan = CH_SPORT3_RX,
79 .dma_tx_chan = CH_SPORT3_TX, 96 .dma_tx_chan = CH_SPORT3_TX,
80 .err_irq = IRQ_SPORT3_ERR, 97 .err_irq = IRQ_SPORT3_ERROR,
81 .regs = (struct sport_register *)SPORT3_TCR1, 98 .regs = (struct sport_register *)SPORT3_TCR1,
82 } 99 }
83};
84#else
85static struct sport_param sport_params[2] = {
86 {
87 .dma_rx_chan = CH_SPORT0_RX,
88 .dma_tx_chan = CH_SPORT0_TX,
89 .err_irq = IRQ_SPORT0_ERROR,
90 .regs = (struct sport_register *)SPORT0_TCR1,
91 },
92 {
93 .dma_rx_chan = CH_SPORT1_RX,
94 .dma_tx_chan = CH_SPORT1_TX,
95 .err_irq = IRQ_SPORT1_ERROR,
96 .regs = (struct sport_register *)SPORT1_TCR1,
97 }
98};
99#endif 100#endif
101};
100 102
101void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ 103void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src,
102 size_t count) 104 size_t count, unsigned int chan_mask)
103{ 105{
104 while (count--) { 106 while (count--) {
105 dst->ac97_tag = TAG_VALID | TAG_PCM; 107 dst->ac97_tag = TAG_VALID;
106 (dst++)->ac97_pcm = *src++; 108 if (chan_mask & SP_FL) {
109 dst->ac97_pcm_r = *src++;
110 dst->ac97_tag |= TAG_PCM_RIGHT;
111 }
112 if (chan_mask & SP_FR) {
113 dst->ac97_pcm_l = *src++;
114 dst->ac97_tag |= TAG_PCM_LEFT;
115
116 }
117#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
118 if (chan_mask & SP_SR) {
119 dst->ac97_sl = *src++;
120 dst->ac97_tag |= TAG_PCM_SL;
121 }
122 if (chan_mask & SP_SL) {
123 dst->ac97_sr = *src++;
124 dst->ac97_tag |= TAG_PCM_SR;
125 }
126 if (chan_mask & SP_LFE) {
127 dst->ac97_lfe = *src++;
128 dst->ac97_tag |= TAG_PCM_LFE;
129 }
130 if (chan_mask & SP_FC) {
131 dst->ac97_center = *src++;
132 dst->ac97_tag |= TAG_PCM_CENTER;
133 }
134#endif
135 dst++;
107 } 136 }
108} 137}
109EXPORT_SYMBOL(bf5xx_pcm_to_ac97); 138EXPORT_SYMBOL(bf5xx_pcm_to_ac97);
110 139
111void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ 140void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst,
112 size_t count) 141 size_t count)
113{ 142{
114 while (count--) 143 while (count--) {
115 *(dst++) = (src++)->ac97_pcm; 144 *(dst++) = src->ac97_pcm_l;
145 *(dst++) = src->ac97_pcm_r;
146 src++;
147 }
116} 148}
117EXPORT_SYMBOL(bf5xx_ac97_to_pcm); 149EXPORT_SYMBOL(bf5xx_ac97_to_pcm);
118 150
119static unsigned int sport_tx_curr_frag(struct sport_device *sport) 151static unsigned int sport_tx_curr_frag(struct sport_device *sport)
120{ 152{
121 return sport->tx_curr_frag = sport_curr_offset_tx(sport) / \ 153 return sport->tx_curr_frag = sport_curr_offset_tx(sport) /
122 sport->tx_fragsize; 154 sport->tx_fragsize;
123} 155}
124 156
@@ -130,7 +162,7 @@ static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data)
130 162
131 sport_incfrag(sport, &nextfrag, 1); 163 sport_incfrag(sport, &nextfrag, 1);
132 164
133 nextwrite = (struct ac97_frame *)(sport->tx_buf + \ 165 nextwrite = (struct ac97_frame *)(sport->tx_buf +
134 nextfrag * sport->tx_fragsize); 166 nextfrag * sport->tx_fragsize);
135 pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", 167 pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n",
136 sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); 168 sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]);
@@ -297,20 +329,15 @@ static int bf5xx_ac97_resume(struct platform_device *pdev,
297static int bf5xx_ac97_probe(struct platform_device *pdev, 329static int bf5xx_ac97_probe(struct platform_device *pdev,
298 struct snd_soc_dai *dai) 330 struct snd_soc_dai *dai)
299{ 331{
300 int ret; 332 int ret = 0;
301#if defined(CONFIG_BF54x)
302 u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1,
303 PIN_REQ_SPORT_2, PIN_REQ_SPORT_3};
304#else
305 u16 sport_req[][7] = {PIN_REQ_SPORT_0, PIN_REQ_SPORT_1};
306#endif
307 cmd_count = (int *)get_zeroed_page(GFP_KERNEL); 333 cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
308 if (cmd_count == NULL) 334 if (cmd_count == NULL)
309 return -ENOMEM; 335 return -ENOMEM;
310 336
311 if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { 337 if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
312 pr_err("Requesting Peripherals failed\n"); 338 pr_err("Requesting Peripherals failed\n");
313 return -EFAULT; 339 ret = -EFAULT;
340 goto peripheral_err;
314 } 341 }
315 342
316#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 343#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
@@ -318,54 +345,52 @@ static int bf5xx_ac97_probe(struct platform_device *pdev,
318 if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { 345 if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) {
319 pr_err("Failed to request GPIO_%d for reset\n", 346 pr_err("Failed to request GPIO_%d for reset\n",
320 CONFIG_SND_BF5XX_RESET_GPIO_NUM); 347 CONFIG_SND_BF5XX_RESET_GPIO_NUM);
321 peripheral_free_list(&sport_req[sport_num][0]); 348 ret = -1;
322 return -1; 349 goto gpio_err;
323 } 350 }
324 gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); 351 gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
325#endif 352#endif
326 sport_handle = sport_init(&sport_params[sport_num], 2, \ 353 sport_handle = sport_init(&sport_params[sport_num], 2, \
327 sizeof(struct ac97_frame), NULL); 354 sizeof(struct ac97_frame), NULL);
328 if (!sport_handle) { 355 if (!sport_handle) {
329 peripheral_free_list(&sport_req[sport_num][0]); 356 ret = -ENODEV;
330#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 357 goto sport_err;
331 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
332#endif
333 return -ENODEV;
334 } 358 }
335 /*SPORT works in TDM mode to simulate AC97 transfers*/ 359 /*SPORT works in TDM mode to simulate AC97 transfers*/
336 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); 360 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1);
337 if (ret) { 361 if (ret) {
338 pr_err("SPORT is busy!\n"); 362 pr_err("SPORT is busy!\n");
339 kfree(sport_handle); 363 ret = -EBUSY;
340 peripheral_free_list(&sport_req[sport_num][0]); 364 goto sport_config_err;
341#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
342 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
343#endif
344 return -EBUSY;
345 } 365 }
346 366
347 ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); 367 ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1));
348 if (ret) { 368 if (ret) {
349 pr_err("SPORT is busy!\n"); 369 pr_err("SPORT is busy!\n");
350 kfree(sport_handle); 370 ret = -EBUSY;
351 peripheral_free_list(&sport_req[sport_num][0]); 371 goto sport_config_err;
352#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
353 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
354#endif
355 return -EBUSY;
356 } 372 }
357 373
358 ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); 374 ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1));
359 if (ret) { 375 if (ret) {
360 pr_err("SPORT is busy!\n"); 376 pr_err("SPORT is busy!\n");
361 kfree(sport_handle); 377 ret = -EBUSY;
362 peripheral_free_list(&sport_req[sport_num][0]); 378 goto sport_config_err;
379 }
380
381sport_config_err:
382 kfree(sport_handle);
383sport_err:
363#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 384#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
364 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); 385 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
365#endif 386#endif
366 return -EBUSY; 387gpio_err:
367 } 388 peripheral_free_list(&sport_req[sport_num][0]);
368 return 0; 389peripheral_err:
390 free_page((unsigned long)cmd_count);
391 cmd_count = NULL;
392
393 return ret;
369} 394}
370 395
371static void bf5xx_ac97_remove(struct platform_device *pdev, 396static void bf5xx_ac97_remove(struct platform_device *pdev,
@@ -373,6 +398,7 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
373{ 398{
374 free_page((unsigned long)cmd_count); 399 free_page((unsigned long)cmd_count);
375 cmd_count = NULL; 400 cmd_count = NULL;
401 peripheral_free_list(&sport_req[sport_num][0]);
376#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 402#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
377 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); 403 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
378#endif 404#endif
@@ -389,7 +415,11 @@ struct snd_soc_dai bfin_ac97_dai = {
389 .playback = { 415 .playback = {
390 .stream_name = "AC97 Playback", 416 .stream_name = "AC97 Playback",
391 .channels_min = 2, 417 .channels_min = 2,
418#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
419 .channels_max = 6,
420#else
392 .channels_max = 2, 421 .channels_max = 2,
422#endif
393 .rates = SNDRV_PCM_RATE_48000, 423 .rates = SNDRV_PCM_RATE_48000,
394 .formats = SNDRV_PCM_FMTBIT_S16_LE, }, 424 .formats = SNDRV_PCM_FMTBIT_S16_LE, },
395 .capture = { 425 .capture = {
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h
index 3f77cc558dc0..3f2a911fe0cb 100644
--- a/sound/soc/blackfin/bf5xx-ac97.h
+++ b/sound/soc/blackfin/bf5xx-ac97.h
@@ -16,21 +16,46 @@ struct ac97_frame {
16 u16 ac97_tag; /* slot 0 */ 16 u16 ac97_tag; /* slot 0 */
17 u16 ac97_addr; /* slot 1 */ 17 u16 ac97_addr; /* slot 1 */
18 u16 ac97_data; /* slot 2 */ 18 u16 ac97_data; /* slot 2 */
19 u32 ac97_pcm; /* slot 3 and 4: left and right pcm data */ 19 u16 ac97_pcm_l; /*slot 3:front left*/
20 u16 ac97_pcm_r; /*slot 4:front left*/
21#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
22 u16 ac97_mdm_l1;
23 u16 ac97_center; /*slot 6:center*/
24 u16 ac97_sl; /*slot 7:surround left*/
25 u16 ac97_sr; /*slot 8:surround right*/
26 u16 ac97_lfe; /*slot 9:lfe*/
27#endif
20} __attribute__ ((packed)); 28} __attribute__ ((packed));
21 29
30/* Speaker location */
31#define SP_FL 0x0001
32#define SP_FR 0x0010
33#define SP_FC 0x0002
34#define SP_LFE 0x0020
35#define SP_SL 0x0004
36#define SP_SR 0x0040
37
38#define SP_STEREO (SP_FL | SP_FR)
39#define SP_2DOT1 (SP_FL | SP_FR | SP_LFE)
40#define SP_QUAD (SP_FL | SP_FR | SP_SL | SP_SR)
41#define SP_5DOT1 (SP_FL | SP_FR | SP_FC | SP_LFE | SP_SL | SP_SR)
42
22#define TAG_VALID 0x8000 43#define TAG_VALID 0x8000
23#define TAG_CMD 0x6000 44#define TAG_CMD 0x6000
24#define TAG_PCM_LEFT 0x1000 45#define TAG_PCM_LEFT 0x1000
25#define TAG_PCM_RIGHT 0x0800 46#define TAG_PCM_RIGHT 0x0800
26#define TAG_PCM (TAG_PCM_LEFT | TAG_PCM_RIGHT) 47#define TAG_PCM_MDM_L1 0x0400
48#define TAG_PCM_CENTER 0x0200
49#define TAG_PCM_SL 0x0100
50#define TAG_PCM_SR 0x0080
51#define TAG_PCM_LFE 0x0040
27 52
28extern struct snd_soc_dai bfin_ac97_dai; 53extern struct snd_soc_dai bfin_ac97_dai;
29 54
30void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ 55void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
31 size_t count); 56 size_t count, unsigned int chan_mask);
32 57
33void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ 58void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, \
34 size_t count); 59 size_t count);
35 60
36#endif 61#endif
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index fcadcc081f7f..2e63dea73e9c 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -116,7 +116,7 @@ struct sport_device {
116 void *err_data; 116 void *err_data;
117 unsigned char *tx_dma_buf; 117 unsigned char *tx_dma_buf;
118 unsigned char *rx_dma_buf; 118 unsigned char *rx_dma_buf;
119#ifdef CONFIG_SND_MMAP_SUPPORT 119#ifdef CONFIG_SND_BF5XX_MMAP_SUPPORT
120 dma_addr_t tx_dma_phy; 120 dma_addr_t tx_dma_phy;
121 dma_addr_t rx_dma_phy; 121 dma_addr_t rx_dma_phy;
122 int tx_pos;/*pcm sample count*/ 122 int tx_pos;/*pcm sample count*/