diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2013-05-28 13:22:14 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2013-05-30 07:33:40 -0400 |
commit | 8b5e2e396b589119bcc9c6a382a999e0202bae18 (patch) | |
tree | bc5057b3426563cace2ae075bfc2b5fa5ba37c11 /sound/soc/blackfin | |
parent | a3935a29f68c261d31b41c896f95c9333b615abf (diff) |
ASoC: blackfin: bf5xx-i2s: Add support for TDM mode
The bf5xx-i2s{,-pcm} and bf5xx-tdm{-pcm} drivers are nearly identical. Both are
for the same hardware each supporting a slight different subset of the hardware.
The bf5xx-i2s driver supports 2 channel I2S mode while the bf5xx-tdm driver
supports TDM mode and channel remapping. This patch adds support for TDM mode
and channel remapping to the bf5xx-i2s driver so that we'll eventually be able
to retire the bf5xx-tdm driver. Unfortunately the hardware is fixed to using 8
channels in TDM mode. The bf5xx-tdm driver jumps through a few hoops to make it
work well with other channel counts as well:
* Don't support mmap
* Translate between internal frame size (which is always 8 * sample_size)
and ALSA frame size (which depends on the channel count)
* Have special copy and silence callbacks which are aware of the mismatch
between internal and ALSA frame size
* Reduce the maximum buffer size to ensure that there is enough headroom for
dummy data.
The bf5xx-i2s driver is going to use the same mechanisms when being used int
TDM mode.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/blackfin')
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s-pcm.c | 118 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s-pcm.h | 17 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s.c | 105 |
3 files changed, 229 insertions, 11 deletions
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index 9931a18c962e..9cb4a80df98e 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <asm/dma.h> | 40 | #include <asm/dma.h> |
41 | 41 | ||
42 | #include "bf5xx-sport.h" | 42 | #include "bf5xx-sport.h" |
43 | #include "bf5xx-i2s-pcm.h" | ||
43 | 44 | ||
44 | static void bf5xx_dma_irq(void *data) | 45 | static void bf5xx_dma_irq(void *data) |
45 | { | 46 | { |
@@ -49,7 +50,6 @@ static void bf5xx_dma_irq(void *data) | |||
49 | 50 | ||
50 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | 51 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { |
51 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 52 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
52 | SNDRV_PCM_INFO_MMAP | | ||
53 | SNDRV_PCM_INFO_MMAP_VALID | | 53 | SNDRV_PCM_INFO_MMAP_VALID | |
54 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | 54 | SNDRV_PCM_INFO_BLOCK_TRANSFER, |
55 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 55 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
@@ -66,7 +66,16 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | |||
66 | static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | 66 | static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, |
67 | struct snd_pcm_hw_params *params) | 67 | struct snd_pcm_hw_params *params) |
68 | { | 68 | { |
69 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | 69 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
70 | unsigned int buffer_size = params_buffer_bytes(params); | ||
71 | struct bf5xx_i2s_pcm_data *dma_data; | ||
72 | |||
73 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
74 | |||
75 | if (dma_data->tdm_mode) | ||
76 | buffer_size = buffer_size / params_channels(params) * 8; | ||
77 | |||
78 | return snd_pcm_lib_malloc_pages(substream, buffer_size); | ||
70 | } | 79 | } |
71 | 80 | ||
72 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | 81 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) |
@@ -78,9 +87,16 @@ static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | |||
78 | 87 | ||
79 | static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | 88 | static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) |
80 | { | 89 | { |
90 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
81 | struct snd_pcm_runtime *runtime = substream->runtime; | 91 | struct snd_pcm_runtime *runtime = substream->runtime; |
82 | struct sport_device *sport = runtime->private_data; | 92 | struct sport_device *sport = runtime->private_data; |
83 | int period_bytes = frames_to_bytes(runtime, runtime->period_size); | 93 | int period_bytes = frames_to_bytes(runtime, runtime->period_size); |
94 | struct bf5xx_i2s_pcm_data *dma_data; | ||
95 | |||
96 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
97 | |||
98 | if (dma_data->tdm_mode) | ||
99 | period_bytes = period_bytes / runtime->channels * 8; | ||
84 | 100 | ||
85 | pr_debug("%s enter\n", __func__); | 101 | pr_debug("%s enter\n", __func__); |
86 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 102 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
@@ -127,10 +143,15 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
127 | 143 | ||
128 | static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | 144 | static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) |
129 | { | 145 | { |
146 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
130 | struct snd_pcm_runtime *runtime = substream->runtime; | 147 | struct snd_pcm_runtime *runtime = substream->runtime; |
131 | struct sport_device *sport = runtime->private_data; | 148 | struct sport_device *sport = runtime->private_data; |
132 | unsigned int diff; | 149 | unsigned int diff; |
133 | snd_pcm_uframes_t frames; | 150 | snd_pcm_uframes_t frames; |
151 | struct bf5xx_i2s_pcm_data *dma_data; | ||
152 | |||
153 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
154 | |||
134 | pr_debug("%s enter\n", __func__); | 155 | pr_debug("%s enter\n", __func__); |
135 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 156 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
136 | diff = sport_curr_offset_tx(sport); | 157 | diff = sport_curr_offset_tx(sport); |
@@ -147,6 +168,8 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | |||
147 | diff = 0; | 168 | diff = 0; |
148 | 169 | ||
149 | frames = bytes_to_frames(substream->runtime, diff); | 170 | frames = bytes_to_frames(substream->runtime, diff); |
171 | if (dma_data->tdm_mode) | ||
172 | frames = frames * runtime->channels / 8; | ||
150 | 173 | ||
151 | return frames; | 174 | return frames; |
152 | } | 175 | } |
@@ -158,11 +181,18 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | |||
158 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); | 181 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); |
159 | struct snd_pcm_runtime *runtime = substream->runtime; | 182 | struct snd_pcm_runtime *runtime = substream->runtime; |
160 | struct snd_dma_buffer *buf = &substream->dma_buffer; | 183 | struct snd_dma_buffer *buf = &substream->dma_buffer; |
184 | struct bf5xx_i2s_pcm_data *dma_data; | ||
161 | int ret; | 185 | int ret; |
162 | 186 | ||
187 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
188 | |||
163 | pr_debug("%s enter\n", __func__); | 189 | pr_debug("%s enter\n", __func__); |
164 | 190 | ||
165 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); | 191 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); |
192 | if (dma_data->tdm_mode) | ||
193 | runtime->hw.buffer_bytes_max /= 4; | ||
194 | else | ||
195 | runtime->hw.info |= SNDRV_PCM_INFO_MMAP; | ||
166 | 196 | ||
167 | ret = snd_pcm_hw_constraint_integer(runtime, | 197 | ret = snd_pcm_hw_constraint_integer(runtime, |
168 | SNDRV_PCM_HW_PARAM_PERIODS); | 198 | SNDRV_PCM_HW_PARAM_PERIODS); |
@@ -198,6 +228,88 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream, | |||
198 | return 0 ; | 228 | return 0 ; |
199 | } | 229 | } |
200 | 230 | ||
231 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | ||
232 | snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) | ||
233 | { | ||
234 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
235 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
236 | unsigned int sample_size = runtime->sample_bits / 8; | ||
237 | struct bf5xx_i2s_pcm_data *dma_data; | ||
238 | unsigned int i; | ||
239 | void *src, *dst; | ||
240 | |||
241 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
242 | |||
243 | if (dma_data->tdm_mode) { | ||
244 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
245 | src = buf; | ||
246 | dst = runtime->dma_area; | ||
247 | dst += pos * sample_size * 8; | ||
248 | |||
249 | while (count--) { | ||
250 | for (i = 0; i < runtime->channels; i++) { | ||
251 | memcpy(dst + dma_data->map[i] * | ||
252 | sample_size, src, sample_size); | ||
253 | src += sample_size; | ||
254 | } | ||
255 | dst += 8 * sample_size; | ||
256 | } | ||
257 | } else { | ||
258 | src = runtime->dma_area; | ||
259 | src += pos * sample_size * 8; | ||
260 | dst = buf; | ||
261 | |||
262 | while (count--) { | ||
263 | for (i = 0; i < runtime->channels; i++) { | ||
264 | memcpy(dst, src + dma_data->map[i] * | ||
265 | sample_size, sample_size); | ||
266 | dst += sample_size; | ||
267 | } | ||
268 | src += 8 * sample_size; | ||
269 | } | ||
270 | } | ||
271 | } else { | ||
272 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
273 | src = buf; | ||
274 | dst = runtime->dma_area; | ||
275 | dst += frames_to_bytes(runtime, pos); | ||
276 | } else { | ||
277 | src = runtime->dma_area; | ||
278 | src += frames_to_bytes(runtime, pos); | ||
279 | dst = buf; | ||
280 | } | ||
281 | |||
282 | memcpy(dst, src, frames_to_bytes(runtime, count)); | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int bf5xx_pcm_silence(struct snd_pcm_substream *substream, | ||
289 | int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) | ||
290 | { | ||
291 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
292 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
293 | unsigned int sample_size = runtime->sample_bits / 8; | ||
294 | void *buf = runtime->dma_area; | ||
295 | struct bf5xx_i2s_pcm_data *dma_data; | ||
296 | unsigned int offset, size; | ||
297 | |||
298 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
299 | |||
300 | if (dma_data->tdm_mode) { | ||
301 | offset = pos * 8 * sample_size; | ||
302 | size = count * 8 * sample_size; | ||
303 | } else { | ||
304 | offset = frames_to_bytes(runtime, pos); | ||
305 | size = frames_to_bytes(runtime, count); | ||
306 | } | ||
307 | |||
308 | snd_pcm_format_set_silence(runtime->format, buf + offset, size); | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | |||
201 | static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | 313 | static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { |
202 | .open = bf5xx_pcm_open, | 314 | .open = bf5xx_pcm_open, |
203 | .ioctl = snd_pcm_lib_ioctl, | 315 | .ioctl = snd_pcm_lib_ioctl, |
@@ -207,6 +319,8 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | |||
207 | .trigger = bf5xx_pcm_trigger, | 319 | .trigger = bf5xx_pcm_trigger, |
208 | .pointer = bf5xx_pcm_pointer, | 320 | .pointer = bf5xx_pcm_pointer, |
209 | .mmap = bf5xx_pcm_mmap, | 321 | .mmap = bf5xx_pcm_mmap, |
322 | .copy = bf5xx_pcm_copy, | ||
323 | .silence = bf5xx_pcm_silence, | ||
210 | }; | 324 | }; |
211 | 325 | ||
212 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | 326 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h new file mode 100644 index 000000000000..1f0435249f88 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License version 2 as | ||
4 | * published by the Free Software Foundation. | ||
5 | */ | ||
6 | |||
7 | #ifndef _BF5XX_TDM_PCM_H | ||
8 | #define _BF5XX_TDM_PCM_H | ||
9 | |||
10 | #define BFIN_TDM_DAI_MAX_SLOTS 8 | ||
11 | |||
12 | struct bf5xx_i2s_pcm_data { | ||
13 | unsigned int map[BFIN_TDM_DAI_MAX_SLOTS]; | ||
14 | bool tdm_mode; | ||
15 | }; | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 78411f266f60..9a174fc47d39 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/gpio.h> | 42 | #include <linux/gpio.h> |
43 | 43 | ||
44 | #include "bf5xx-sport.h" | 44 | #include "bf5xx-sport.h" |
45 | #include "bf5xx-i2s-pcm.h" | ||
45 | 46 | ||
46 | struct bf5xx_i2s_port { | 47 | struct bf5xx_i2s_port { |
47 | u16 tcr1; | 48 | u16 tcr1; |
@@ -49,6 +50,13 @@ struct bf5xx_i2s_port { | |||
49 | u16 tcr2; | 50 | u16 tcr2; |
50 | u16 rcr2; | 51 | u16 rcr2; |
51 | int configured; | 52 | int configured; |
53 | |||
54 | unsigned int slots; | ||
55 | unsigned int tx_mask; | ||
56 | unsigned int rx_mask; | ||
57 | |||
58 | struct bf5xx_i2s_pcm_data tx_dma_data; | ||
59 | struct bf5xx_i2s_pcm_data rx_dma_data; | ||
52 | }; | 60 | }; |
53 | 61 | ||
54 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 62 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
@@ -170,6 +178,64 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, | |||
170 | bf5xx_i2s->configured = 0; | 178 | bf5xx_i2s->configured = 0; |
171 | } | 179 | } |
172 | 180 | ||
181 | static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai, | ||
182 | unsigned int tx_num, unsigned int *tx_slot, | ||
183 | unsigned int rx_num, unsigned int *rx_slot) | ||
184 | { | ||
185 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
186 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
187 | unsigned int tx_mapped = 0, rx_mapped = 0; | ||
188 | unsigned int slot; | ||
189 | int i; | ||
190 | |||
191 | if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) || | ||
192 | (rx_num > BFIN_TDM_DAI_MAX_SLOTS)) | ||
193 | return -EINVAL; | ||
194 | |||
195 | for (i = 0; i < tx_num; i++) { | ||
196 | slot = tx_slot[i]; | ||
197 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
198 | (!(tx_mapped & (1 << slot)))) { | ||
199 | bf5xx_i2s->tx_dma_data.map[i] = slot; | ||
200 | tx_mapped |= 1 << slot; | ||
201 | } else | ||
202 | return -EINVAL; | ||
203 | } | ||
204 | for (i = 0; i < rx_num; i++) { | ||
205 | slot = rx_slot[i]; | ||
206 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
207 | (!(rx_mapped & (1 << slot)))) { | ||
208 | bf5xx_i2s->rx_dma_data.map[i] = slot; | ||
209 | rx_mapped |= 1 << slot; | ||
210 | } else | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
218 | unsigned int rx_mask, int slots, int width) | ||
219 | { | ||
220 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
221 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
222 | |||
223 | if (slots % 8 != 0 || slots > 8) | ||
224 | return -EINVAL; | ||
225 | |||
226 | if (width != 32) | ||
227 | return -EINVAL; | ||
228 | |||
229 | bf5xx_i2s->slots = slots; | ||
230 | bf5xx_i2s->tx_mask = tx_mask; | ||
231 | bf5xx_i2s->rx_mask = rx_mask; | ||
232 | |||
233 | bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0; | ||
234 | bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0; | ||
235 | |||
236 | return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0); | ||
237 | } | ||
238 | |||
173 | #ifdef CONFIG_PM | 239 | #ifdef CONFIG_PM |
174 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | 240 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) |
175 | { | 241 | { |
@@ -206,7 +272,8 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | |||
206 | return -EBUSY; | 272 | return -EBUSY; |
207 | } | 273 | } |
208 | 274 | ||
209 | return 0; | 275 | return sport_set_multichannel(sport_handle, bf5xx_i2s->slots, |
276 | bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0); | ||
210 | } | 277 | } |
211 | 278 | ||
212 | #else | 279 | #else |
@@ -214,6 +281,23 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | |||
214 | #define bf5xx_i2s_resume NULL | 281 | #define bf5xx_i2s_resume NULL |
215 | #endif | 282 | #endif |
216 | 283 | ||
284 | static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai) | ||
285 | { | ||
286 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
287 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
288 | unsigned int i; | ||
289 | |||
290 | for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) { | ||
291 | bf5xx_i2s->tx_dma_data.map[i] = i; | ||
292 | bf5xx_i2s->rx_dma_data.map[i] = i; | ||
293 | } | ||
294 | |||
295 | dai->playback_dma_data = &bf5xx_i2s->tx_dma_data; | ||
296 | dai->capture_dma_data = &bf5xx_i2s->rx_dma_data; | ||
297 | |||
298 | return 0; | ||
299 | } | ||
300 | |||
217 | #define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 301 | #define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
218 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | 302 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ |
219 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ | 303 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ |
@@ -226,22 +310,25 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | |||
226 | SNDRV_PCM_FMTBIT_S32_LE) | 310 | SNDRV_PCM_FMTBIT_S32_LE) |
227 | 311 | ||
228 | static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | 312 | static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { |
229 | .shutdown = bf5xx_i2s_shutdown, | 313 | .shutdown = bf5xx_i2s_shutdown, |
230 | .hw_params = bf5xx_i2s_hw_params, | 314 | .hw_params = bf5xx_i2s_hw_params, |
231 | .set_fmt = bf5xx_i2s_set_dai_fmt, | 315 | .set_fmt = bf5xx_i2s_set_dai_fmt, |
316 | .set_tdm_slot = bf5xx_i2s_set_tdm_slot, | ||
317 | .set_channel_map = bf5xx_i2s_set_channel_map, | ||
232 | }; | 318 | }; |
233 | 319 | ||
234 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { | 320 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { |
321 | .probe = bf5xx_i2s_dai_probe, | ||
235 | .suspend = bf5xx_i2s_suspend, | 322 | .suspend = bf5xx_i2s_suspend, |
236 | .resume = bf5xx_i2s_resume, | 323 | .resume = bf5xx_i2s_resume, |
237 | .playback = { | 324 | .playback = { |
238 | .channels_min = 1, | 325 | .channels_min = 2, |
239 | .channels_max = 2, | 326 | .channels_max = 8, |
240 | .rates = BF5XX_I2S_RATES, | 327 | .rates = BF5XX_I2S_RATES, |
241 | .formats = BF5XX_I2S_FORMATS,}, | 328 | .formats = BF5XX_I2S_FORMATS,}, |
242 | .capture = { | 329 | .capture = { |
243 | .channels_min = 1, | 330 | .channels_min = 2, |
244 | .channels_max = 2, | 331 | .channels_max = 8, |
245 | .rates = BF5XX_I2S_RATES, | 332 | .rates = BF5XX_I2S_RATES, |
246 | .formats = BF5XX_I2S_FORMATS,}, | 333 | .formats = BF5XX_I2S_FORMATS,}, |
247 | .ops = &bf5xx_i2s_dai_ops, | 334 | .ops = &bf5xx_i2s_dai_ops, |
@@ -257,7 +344,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev) | |||
257 | int ret; | 344 | int ret; |
258 | 345 | ||
259 | /* configure SPORT for I2S */ | 346 | /* configure SPORT for I2S */ |
260 | sport_handle = sport_init(pdev, 4, 2 * sizeof(u32), | 347 | sport_handle = sport_init(pdev, 4, 8 * sizeof(u32), |
261 | sizeof(struct bf5xx_i2s_port)); | 348 | sizeof(struct bf5xx_i2s_port)); |
262 | if (!sport_handle) | 349 | if (!sport_handle) |
263 | return -ENODEV; | 350 | return -ENODEV; |