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 | |
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')
-rw-r--r-- | sound/soc/blackfin/Kconfig | 14 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.c | 80 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97.c | 156 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97.h | 35 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-sport.h | 2 |
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 | ||
50 | config SND_MMAP_SUPPORT | 50 | config 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 | ||
58 | config 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 | |||
58 | config SND_BF5XX_SOC_SPORT | 66 | config SND_BF5XX_SOC_SPORT |
59 | tristate | 67 | tristate |
60 | 68 | ||
61 | config SND_BF5XX_SOC_I2S | 69 | config 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 | ||
94 | config SND_BF5XX_RESET_GPIO_NUM | 102 | config 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) | 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, \ |
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 @@ | |||
54 | static int *cmd_count; | 54 | static int *cmd_count; |
55 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | 55 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; |
56 | 56 | ||
57 | #if defined(CONFIG_BF54x) | 57 | static 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 | |||
58 | static struct sport_param sport_params[4] = { | 70 | static 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 | ||
85 | static 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 | ||
101 | void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ | 103 | void 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 | } |
109 | EXPORT_SYMBOL(bf5xx_pcm_to_ac97); | 138 | EXPORT_SYMBOL(bf5xx_pcm_to_ac97); |
110 | 139 | ||
111 | void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ | 140 | void 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 | } |
117 | EXPORT_SYMBOL(bf5xx_ac97_to_pcm); | 149 | EXPORT_SYMBOL(bf5xx_ac97_to_pcm); |
118 | 150 | ||
119 | static unsigned int sport_tx_curr_frag(struct sport_device *sport) | 151 | static 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, | |||
297 | static int bf5xx_ac97_probe(struct platform_device *pdev, | 329 | static 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 | |||
381 | sport_config_err: | ||
382 | kfree(sport_handle); | ||
383 | sport_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; | 387 | gpio_err: |
367 | } | 388 | peripheral_free_list(&sport_req[sport_num][0]); |
368 | return 0; | 389 | peripheral_err: |
390 | free_page((unsigned long)cmd_count); | ||
391 | cmd_count = NULL; | ||
392 | |||
393 | return ret; | ||
369 | } | 394 | } |
370 | 395 | ||
371 | static void bf5xx_ac97_remove(struct platform_device *pdev, | 396 | static 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 | ||
28 | extern struct snd_soc_dai bfin_ac97_dai; | 53 | extern struct snd_soc_dai bfin_ac97_dai; |
29 | 54 | ||
30 | void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u32 *src, \ | 55 | void 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 | ||
33 | void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u32 *dst, \ | 58 | void 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*/ |