aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);