aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/omap-mcbsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r--sound/soc/omap/omap-mcbsp.c70
1 files changed, 64 insertions, 6 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index e814a9591f78..6f44cb4d30b8 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -256,6 +256,31 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd,
256 return err; 256 return err;
257} 257}
258 258
259static snd_pcm_sframes_t omap_mcbsp_dai_delay(
260 struct snd_pcm_substream *substream,
261 struct snd_soc_dai *dai)
262{
263 struct snd_soc_pcm_runtime *rtd = substream->private_data;
264 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
265 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
266 u16 fifo_use;
267 snd_pcm_sframes_t delay;
268
269 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
270 fifo_use = omap_mcbsp_get_tx_delay(mcbsp_data->bus_id);
271 else
272 fifo_use = omap_mcbsp_get_rx_delay(mcbsp_data->bus_id);
273
274 /*
275 * Divide the used locations with the channel count to get the
276 * FIFO usage in samples (don't care about partial samples in the
277 * buffer).
278 */
279 delay = fifo_use / substream->runtime->channels;
280
281 return delay;
282}
283
259static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, 284static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
260 struct snd_pcm_hw_params *params, 285 struct snd_pcm_hw_params *params,
261 struct snd_soc_dai *dai) 286 struct snd_soc_dai *dai)
@@ -295,9 +320,21 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
295 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; 320 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
296 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; 321 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
297 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; 322 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
298 omap_mcbsp_dai_dma_params[id][substream->stream].data_type = 323 switch (params_format(params)) {
299 OMAP_DMA_DATA_TYPE_S16; 324 case SNDRV_PCM_FORMAT_S16_LE:
300 cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; 325 omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
326 OMAP_DMA_DATA_TYPE_S16;
327 break;
328 case SNDRV_PCM_FORMAT_S32_LE:
329 omap_mcbsp_dai_dma_params[id][substream->stream].data_type =
330 OMAP_DMA_DATA_TYPE_S32;
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 snd_soc_dai_set_dma_data(cpu_dai, substream,
337 &omap_mcbsp_dai_dma_params[id][substream->stream]);
301 338
302 if (mcbsp_data->configured) { 339 if (mcbsp_data->configured) {
303 /* McBSP already configured by another stream */ 340 /* McBSP already configured by another stream */
@@ -306,7 +343,8 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
306 343
307 format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK; 344 format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
308 wpf = channels = params_channels(params); 345 wpf = channels = params_channels(params);
309 if (channels == 2 && format == SND_SOC_DAIFMT_I2S) { 346 if (channels == 2 && (format == SND_SOC_DAIFMT_I2S ||
347 format == SND_SOC_DAIFMT_LEFT_J)) {
310 /* Use dual-phase frames */ 348 /* Use dual-phase frames */
311 regs->rcr2 |= RPHASE; 349 regs->rcr2 |= RPHASE;
312 regs->xcr2 |= XPHASE; 350 regs->xcr2 |= XPHASE;
@@ -328,6 +366,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
328 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); 366 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
329 regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); 367 regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16);
330 break; 368 break;
369 case SNDRV_PCM_FORMAT_S32_LE:
370 /* Set word lengths */
371 wlen = 32;
372 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32);
373 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
374 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32);
375 regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32);
376 break;
331 default: 377 default:
332 /* Unsupported PCM format */ 378 /* Unsupported PCM format */
333 return -EINVAL; 379 return -EINVAL;
@@ -351,6 +397,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
351 /* Set FS period and length in terms of bit clock periods */ 397 /* Set FS period and length in terms of bit clock periods */
352 switch (format) { 398 switch (format) {
353 case SND_SOC_DAIFMT_I2S: 399 case SND_SOC_DAIFMT_I2S:
400 case SND_SOC_DAIFMT_LEFT_J:
354 regs->srgr2 |= FPER(framesize - 1); 401 regs->srgr2 |= FPER(framesize - 1);
355 regs->srgr1 |= FWID((framesize >> 1) - 1); 402 regs->srgr1 |= FWID((framesize >> 1) - 1);
356 break; 403 break;
@@ -402,6 +449,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
402 regs->rcr2 |= RDATDLY(1); 449 regs->rcr2 |= RDATDLY(1);
403 regs->xcr2 |= XDATDLY(1); 450 regs->xcr2 |= XDATDLY(1);
404 break; 451 break;
452 case SND_SOC_DAIFMT_LEFT_J:
453 /* 0-bit data delay */
454 regs->rcr2 |= RDATDLY(0);
455 regs->xcr2 |= XDATDLY(0);
456 regs->spcr1 |= RJUST(2);
457 /* Invert FS polarity configuration */
458 temp_fmt ^= SND_SOC_DAIFMT_NB_IF;
459 break;
405 case SND_SOC_DAIFMT_DSP_A: 460 case SND_SOC_DAIFMT_DSP_A:
406 /* 1-bit data delay */ 461 /* 1-bit data delay */
407 regs->rcr2 |= RDATDLY(1); 462 regs->rcr2 |= RDATDLY(1);
@@ -607,6 +662,7 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
607 .startup = omap_mcbsp_dai_startup, 662 .startup = omap_mcbsp_dai_startup,
608 .shutdown = omap_mcbsp_dai_shutdown, 663 .shutdown = omap_mcbsp_dai_shutdown,
609 .trigger = omap_mcbsp_dai_trigger, 664 .trigger = omap_mcbsp_dai_trigger,
665 .delay = omap_mcbsp_dai_delay,
610 .hw_params = omap_mcbsp_dai_hw_params, 666 .hw_params = omap_mcbsp_dai_hw_params,
611 .set_fmt = omap_mcbsp_dai_set_dai_fmt, 667 .set_fmt = omap_mcbsp_dai_set_dai_fmt,
612 .set_clkdiv = omap_mcbsp_dai_set_clkdiv, 668 .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
@@ -621,13 +677,15 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
621 .channels_min = 1, \ 677 .channels_min = 1, \
622 .channels_max = 16, \ 678 .channels_max = 16, \
623 .rates = OMAP_MCBSP_RATES, \ 679 .rates = OMAP_MCBSP_RATES, \
624 .formats = SNDRV_PCM_FMTBIT_S16_LE, \ 680 .formats = SNDRV_PCM_FMTBIT_S16_LE | \
681 SNDRV_PCM_FMTBIT_S32_LE, \
625 }, \ 682 }, \
626 .capture = { \ 683 .capture = { \
627 .channels_min = 1, \ 684 .channels_min = 1, \
628 .channels_max = 16, \ 685 .channels_max = 16, \
629 .rates = OMAP_MCBSP_RATES, \ 686 .rates = OMAP_MCBSP_RATES, \
630 .formats = SNDRV_PCM_FMTBIT_S16_LE, \ 687 .formats = SNDRV_PCM_FMTBIT_S16_LE | \
688 SNDRV_PCM_FMTBIT_S32_LE, \
631 }, \ 689 }, \
632 .ops = &omap_mcbsp_dai_ops, \ 690 .ops = &omap_mcbsp_dai_ops, \
633 .private_data = &mcbsp_data[(link_id)].bus_id, \ 691 .private_data = &mcbsp_data[(link_id)].bus_id, \