diff options
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 70 |
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 | ||
259 | static 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 | |||
259 | static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | 284 | static 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, \ |