aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/fsl/fsl_ssi.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/fsl/fsl_ssi.c')
-rw-r--r--sound/soc/fsl/fsl_ssi.c98
1 files changed, 63 insertions, 35 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index c6d6eb71dc1d..169bca295b78 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -72,6 +72,7 @@
72 * @dev: struct device pointer 72 * @dev: struct device pointer
73 * @playback: the number of playback streams opened 73 * @playback: the number of playback streams opened
74 * @capture: the number of capture streams opened 74 * @capture: the number of capture streams opened
75 * @asynchronous: 0=synchronous mode, 1=asynchronous mode
75 * @cpu_dai: the CPU DAI for this device 76 * @cpu_dai: the CPU DAI for this device
76 * @dev_attr: the sysfs device attribute structure 77 * @dev_attr: the sysfs device attribute structure
77 * @stats: SSI statistics 78 * @stats: SSI statistics
@@ -86,6 +87,7 @@ struct fsl_ssi_private {
86 struct device *dev; 87 struct device *dev;
87 unsigned int playback; 88 unsigned int playback;
88 unsigned int capture; 89 unsigned int capture;
90 int asynchronous;
89 struct snd_soc_dai cpu_dai; 91 struct snd_soc_dai cpu_dai;
90 struct device_attribute dev_attr; 92 struct device_attribute dev_attr;
91 93
@@ -301,9 +303,10 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
301 * 303 *
302 * FIXME: Little-endian samples require a different shift dir 304 * FIXME: Little-endian samples require a different shift dir
303 */ 305 */
304 clrsetbits_be32(&ssi->scr, CCSR_SSI_SCR_I2S_MODE_MASK, 306 clrsetbits_be32(&ssi->scr,
305 CCSR_SSI_SCR_TFR_CLK_DIS | 307 CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
306 CCSR_SSI_SCR_I2S_MODE_SLAVE | CCSR_SSI_SCR_SYN); 308 CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
309 | (ssi_private->asynchronous ? 0 : CCSR_SSI_SCR_SYN));
307 310
308 out_be32(&ssi->stcr, 311 out_be32(&ssi->stcr,
309 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | 312 CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
@@ -382,10 +385,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
382 SNDRV_PCM_HW_PARAM_RATE, 385 SNDRV_PCM_HW_PARAM_RATE,
383 first_runtime->rate, first_runtime->rate); 386 first_runtime->rate, first_runtime->rate);
384 387
385 snd_pcm_hw_constraint_minmax(substream->runtime, 388 /* If we're in synchronous mode, then we need to constrain
386 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 389 * the sample size as well. We don't support independent sample
387 first_runtime->sample_bits, 390 * rates in asynchronous mode.
388 first_runtime->sample_bits); 391 */
392 if (!ssi_private->asynchronous)
393 snd_pcm_hw_constraint_minmax(substream->runtime,
394 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
395 first_runtime->sample_bits,
396 first_runtime->sample_bits);
389 397
390 ssi_private->second_stream = substream; 398 ssi_private->second_stream = substream;
391 } 399 }
@@ -400,7 +408,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
400} 408}
401 409
402/** 410/**
403 * fsl_ssi_prepare: prepare the SSI. 411 * fsl_ssi_hw_params - program the sample size
404 * 412 *
405 * Most of the SSI registers have been programmed in the startup function, 413 * Most of the SSI registers have been programmed in the startup function,
406 * but the word length must be programmed here. Unfortunately, programming 414 * but the word length must be programmed here. Unfortunately, programming
@@ -412,23 +420,27 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
412 * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the 420 * Note: The SxCCR.DC and SxCCR.PM bits are only used if the SSI is the
413 * clock master. 421 * clock master.
414 */ 422 */
415static int fsl_ssi_prepare(struct snd_pcm_substream *substream, 423static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
416 struct snd_soc_dai *dai) 424 struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *cpu_dai)
417{ 425{
418 struct snd_pcm_runtime *runtime = substream->runtime; 426 struct fsl_ssi_private *ssi_private = cpu_dai->private_data;
419 struct snd_soc_pcm_runtime *rtd = substream->private_data;
420 struct fsl_ssi_private *ssi_private = rtd->dai->cpu_dai->private_data;
421
422 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
423 427
424 if (substream == ssi_private->first_stream) { 428 if (substream == ssi_private->first_stream) {
425 u32 wl; 429 struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
430 unsigned int sample_size =
431 snd_pcm_format_width(params_format(hw_params));
432 u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
426 433
427 /* The SSI should always be disabled at this points (SSIEN=0) */ 434 /* The SSI should always be disabled at this points (SSIEN=0) */
428 wl = CCSR_SSI_SxCCR_WL(snd_pcm_format_width(runtime->format));
429 435
430 /* In synchronous mode, the SSI uses STCCR for capture */ 436 /* In synchronous mode, the SSI uses STCCR for capture */
431 clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl); 437 if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
438 !ssi_private->asynchronous)
439 clrsetbits_be32(&ssi->stccr,
440 CCSR_SSI_SxCCR_WL_MASK, wl);
441 else
442 clrsetbits_be32(&ssi->srccr,
443 CCSR_SSI_SxCCR_WL_MASK, wl);
432 } 444 }
433 445
434 return 0; 446 return 0;
@@ -452,28 +464,33 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
452 464
453 switch (cmd) { 465 switch (cmd) {
454 case SNDRV_PCM_TRIGGER_START: 466 case SNDRV_PCM_TRIGGER_START:
455 case SNDRV_PCM_TRIGGER_RESUME: 467 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
456 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 468 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
457 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 469 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
458 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
459 setbits32(&ssi->scr, 470 setbits32(&ssi->scr,
460 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE); 471 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
461 } else { 472 } else {
462 clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN); 473 long timeout = jiffies + 10;
474
463 setbits32(&ssi->scr, 475 setbits32(&ssi->scr,
464 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE); 476 CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
465 477
466 /* 478 /* Wait until the SSI has filled its FIFO. Without this
467 * I think we need this delay to allow time for the SSI 479 * delay, ALSA complains about overruns. When the FIFO
468 * to put data into its FIFO. Without it, ALSA starts 480 * is full, the DMA controller initiates its first
469 * to complain about overruns. 481 * transfer. Until then, however, the DMA's DAR
482 * register is zero, which translates to an
483 * out-of-bounds pointer. This makes ALSA think an
484 * overrun has occurred.
470 */ 485 */
471 mdelay(1); 486 while (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0) &&
487 (jiffies < timeout));
488 if (!(in_be32(&ssi->sisr) & CCSR_SSI_SISR_RFF0))
489 return -EIO;
472 } 490 }
473 break; 491 break;
474 492
475 case SNDRV_PCM_TRIGGER_STOP: 493 case SNDRV_PCM_TRIGGER_STOP:
476 case SNDRV_PCM_TRIGGER_SUSPEND:
477 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 494 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
478 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 495 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
479 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE); 496 clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
@@ -563,6 +580,15 @@ static int fsl_ssi_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
563/** 580/**
564 * fsl_ssi_dai_template: template CPU DAI for the SSI 581 * fsl_ssi_dai_template: template CPU DAI for the SSI
565 */ 582 */
583static struct snd_soc_dai_ops fsl_ssi_dai_ops = {
584 .startup = fsl_ssi_startup,
585 .hw_params = fsl_ssi_hw_params,
586 .shutdown = fsl_ssi_shutdown,
587 .trigger = fsl_ssi_trigger,
588 .set_sysclk = fsl_ssi_set_sysclk,
589 .set_fmt = fsl_ssi_set_fmt,
590};
591
566static struct snd_soc_dai fsl_ssi_dai_template = { 592static struct snd_soc_dai fsl_ssi_dai_template = {
567 .playback = { 593 .playback = {
568 /* The SSI does not support monaural audio. */ 594 /* The SSI does not support monaural audio. */
@@ -577,14 +603,7 @@ static struct snd_soc_dai fsl_ssi_dai_template = {
577 .rates = FSLSSI_I2S_RATES, 603 .rates = FSLSSI_I2S_RATES,
578 .formats = FSLSSI_I2S_FORMATS, 604 .formats = FSLSSI_I2S_FORMATS,
579 }, 605 },
580 .ops = { 606 .ops = &fsl_ssi_dai_ops,
581 .startup = fsl_ssi_startup,
582 .prepare = fsl_ssi_prepare,
583 .shutdown = fsl_ssi_shutdown,
584 .trigger = fsl_ssi_trigger,
585 .set_sysclk = fsl_ssi_set_sysclk,
586 .set_fmt = fsl_ssi_set_fmt,
587 },
588}; 607};
589 608
590/** 609/**
@@ -654,6 +673,7 @@ struct snd_soc_dai *fsl_ssi_create_dai(struct fsl_ssi_info *ssi_info)
654 ssi_private->ssi_phys = ssi_info->ssi_phys; 673 ssi_private->ssi_phys = ssi_info->ssi_phys;
655 ssi_private->irq = ssi_info->irq; 674 ssi_private->irq = ssi_info->irq;
656 ssi_private->dev = ssi_info->dev; 675 ssi_private->dev = ssi_info->dev;
676 ssi_private->asynchronous = ssi_info->asynchronous;
657 677
658 ssi_private->dev->driver_data = fsl_ssi_dai; 678 ssi_private->dev->driver_data = fsl_ssi_dai;
659 679
@@ -704,6 +724,14 @@ void fsl_ssi_destroy_dai(struct snd_soc_dai *fsl_ssi_dai)
704} 724}
705EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai); 725EXPORT_SYMBOL_GPL(fsl_ssi_destroy_dai);
706 726
727static int __init fsl_ssi_init(void)
728{
729 printk(KERN_INFO "Freescale Synchronous Serial Interface (SSI) ASoC Driver\n");
730
731 return 0;
732}
733module_init(fsl_ssi_init);
734
707MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); 735MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
708MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver"); 736MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
709MODULE_LICENSE("GPL"); 737MODULE_LICENSE("GPL");