aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Ujfalusi <peter.ujfalusi@nokia.com>2010-07-29 02:51:27 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-02 05:38:16 -0400
commitcf80e15860852be5ce38714979db94ec36c5e288 (patch)
treed2acef3fa3efb715416f6ac3bc0703080e584791
parent15d0143007b68079aec02918d890c26ed4eaf3b9 (diff)
ASoC: omap-mcbsp: Support for sDMA packet mode
Utilize the sDMA controller's packet syncronization mode, when the McBSP FIFO is in use (by extending the THRESHOLD mode). When the sDMA is configured for packet mode, the sDMA frame size does not need to match with the McBSP threshold configuration. Uppon DMA request the sDMA will transfer packet size number of words, and still trigger interrupt on frame boundary. The patch extends the original THRESHOLD mode by doing the following: if (period_words <= max_threshold) Current THRESHOLD mode configuration Otherwise (period_words > max_threshold) McBSP threshold = sDMA packet size sDMA frame size = period size With the extended THRESHOLD mode we can remove the constraint for the maximum period size, since if the period size is bigger than the maximum allowed threshold, than the driver will switch to packet mode, and picks the best (biggest) threshold value, which can divide evenly the period size. Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Acked-by: Jarkko Nikula <jhnikula@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r--sound/soc/omap/omap-mcbsp.c62
1 files changed, 56 insertions, 6 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 4ac8a08db7b5..9fd00b091814 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -155,13 +155,23 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
155 struct snd_soc_pcm_runtime *rtd = substream->private_data; 155 struct snd_soc_pcm_runtime *rtd = substream->private_data;
156 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 156 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
157 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 157 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
158 struct omap_pcm_dma_data *dma_data;
158 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); 159 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
159 int words; 160 int words;
160 161
162 dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
163
161 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 164 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
162 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 165 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
163 /* The FIFO size depends on the McBSP word configuration */ 166 /*
164 words = snd_pcm_lib_period_bytes(substream) / 167 * Configure McBSP threshold based on either:
168 * packet_size, when the sDMA is in packet mode, or
169 * based on the period size.
170 */
171 if (dma_data->packet_size)
172 words = dma_data->packet_size;
173 else
174 words = snd_pcm_lib_period_bytes(substream) /
165 (mcbsp_data->wlen / 8); 175 (mcbsp_data->wlen / 8);
166 else 176 else
167 words = 1; 177 words = 1;
@@ -351,6 +361,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
351 struct omap_pcm_dma_data *dma_data; 361 struct omap_pcm_dma_data *dma_data;
352 int dma, bus_id = mcbsp_data->bus_id; 362 int dma, bus_id = mcbsp_data->bus_id;
353 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; 363 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
364 int pkt_size = 0;
354 unsigned long port; 365 unsigned long port;
355 unsigned int format, div, framesize, master; 366 unsigned int format, div, framesize, master;
356 367
@@ -373,9 +384,11 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
373 switch (params_format(params)) { 384 switch (params_format(params)) {
374 case SNDRV_PCM_FORMAT_S16_LE: 385 case SNDRV_PCM_FORMAT_S16_LE:
375 dma_data->data_type = OMAP_DMA_DATA_TYPE_S16; 386 dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
387 wlen = 16;
376 break; 388 break;
377 case SNDRV_PCM_FORMAT_S32_LE: 389 case SNDRV_PCM_FORMAT_S32_LE:
378 dma_data->data_type = OMAP_DMA_DATA_TYPE_S32; 390 dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
391 wlen = 32;
379 break; 392 break;
380 default: 393 default:
381 return -EINVAL; 394 return -EINVAL;
@@ -384,14 +397,53 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
384 dma_data->set_threshold = omap_mcbsp_set_threshold; 397 dma_data->set_threshold = omap_mcbsp_set_threshold;
385 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 398 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
386 if (omap_mcbsp_get_dma_op_mode(bus_id) == 399 if (omap_mcbsp_get_dma_op_mode(bus_id) ==
387 MCBSP_DMA_MODE_THRESHOLD) 400 MCBSP_DMA_MODE_THRESHOLD) {
388 sync_mode = OMAP_DMA_SYNC_FRAME; 401 int period_words, max_thrsh;
402
403 period_words = params_period_bytes(params) / (wlen / 8);
404 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
405 max_thrsh = omap_mcbsp_get_max_tx_threshold(
406 mcbsp_data->bus_id);
407 else
408 max_thrsh = omap_mcbsp_get_max_rx_threshold(
409 mcbsp_data->bus_id);
410 /*
411 * If the period contains less or equal number of words,
412 * we are using the original threshold mode setup:
413 * McBSP threshold = sDMA frame size = period_size
414 * Otherwise we switch to sDMA packet mode:
415 * McBSP threshold = sDMA packet size
416 * sDMA frame size = period size
417 */
418 if (period_words > max_thrsh) {
419 int divider = 0;
420
421 /*
422 * Look for the biggest threshold value, which
423 * divides the period size evenly.
424 */
425 divider = period_words / max_thrsh;
426 if (period_words % max_thrsh)
427 divider++;
428 while (period_words % divider &&
429 divider < period_words)
430 divider++;
431 if (divider == period_words)
432 return -EINVAL;
433
434 pkt_size = period_words / divider;
435 sync_mode = OMAP_DMA_SYNC_PACKET;
436 } else {
437 sync_mode = OMAP_DMA_SYNC_FRAME;
438 }
439 }
389 } 440 }
390 441
391 dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback"; 442 dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
392 dma_data->dma_req = dma; 443 dma_data->dma_req = dma;
393 dma_data->port_addr = port; 444 dma_data->port_addr = port;
394 dma_data->sync_mode = sync_mode; 445 dma_data->sync_mode = sync_mode;
446 dma_data->packet_size = pkt_size;
395 447
396 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); 448 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
397 449
@@ -419,7 +471,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
419 switch (params_format(params)) { 471 switch (params_format(params)) {
420 case SNDRV_PCM_FORMAT_S16_LE: 472 case SNDRV_PCM_FORMAT_S16_LE:
421 /* Set word lengths */ 473 /* Set word lengths */
422 wlen = 16;
423 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); 474 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
424 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); 475 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
425 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); 476 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
@@ -427,7 +478,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
427 break; 478 break;
428 case SNDRV_PCM_FORMAT_S32_LE: 479 case SNDRV_PCM_FORMAT_S32_LE:
429 /* Set word lengths */ 480 /* Set word lengths */
430 wlen = 32;
431 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); 481 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32);
432 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); 482 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
433 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); 483 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32);