diff options
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 62 |
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); |