diff options
author | Nicolin Chen <b42378@freescale.com> | 2013-12-02 10:29:03 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-12-02 12:37:07 -0500 |
commit | 2924a9981006ad01efb46c754689fa7d03e3eb4f (patch) | |
tree | dcb22cfad1b4fae314c9e64a8a1538b970520666 /sound/soc/fsl | |
parent | 3621dbbc27ff347f2e4476013054bab18ebd906c (diff) |
ASoC: fsl_ssi: Add monaural audio support for non-ac97 interface
The normal mode of SSI allows it to send/receive data to/from the first
slot of each period. So we can use this normal mode to trick I2S signal
by puting/getting data to/from the first slot only (the left channel)
so as to support monaural audio playback and recording.
Signed-off-by: Nicolin Chen <b42378@freescale.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 3df0318e71df..90ff1071e29c 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -143,6 +143,7 @@ struct fsl_ssi_private { | |||
143 | bool ssi_on_imx; | 143 | bool ssi_on_imx; |
144 | bool imx_ac97; | 144 | bool imx_ac97; |
145 | bool use_dma; | 145 | bool use_dma; |
146 | u8 i2s_mode; | ||
146 | struct clk *clk; | 147 | struct clk *clk; |
147 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 148 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
148 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 149 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
@@ -354,14 +355,13 @@ static void fsl_ssi_setup_ac97(struct fsl_ssi_private *ssi_private) | |||
354 | static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) | 355 | static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) |
355 | { | 356 | { |
356 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 357 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
357 | u8 i2s_mode; | ||
358 | u8 wm; | 358 | u8 wm; |
359 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; | 359 | int synchronous = ssi_private->cpu_dai_drv.symmetric_rates; |
360 | 360 | ||
361 | if (ssi_private->imx_ac97) | 361 | if (ssi_private->imx_ac97) |
362 | i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; | 362 | ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET; |
363 | else | 363 | else |
364 | i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; | 364 | ssi_private->i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE; |
365 | 365 | ||
366 | /* | 366 | /* |
367 | * Section 16.5 of the MPC8610 reference manual says that the SSI needs | 367 | * Section 16.5 of the MPC8610 reference manual says that the SSI needs |
@@ -378,7 +378,7 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private) | |||
378 | write_ssi_mask(&ssi->scr, | 378 | write_ssi_mask(&ssi->scr, |
379 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, | 379 | CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN, |
380 | CCSR_SSI_SCR_TFR_CLK_DIS | | 380 | CCSR_SSI_SCR_TFR_CLK_DIS | |
381 | i2s_mode | | 381 | ssi_private->i2s_mode | |
382 | (synchronous ? CCSR_SSI_SCR_SYN : 0)); | 382 | (synchronous ? CCSR_SSI_SCR_SYN : 0)); |
383 | 383 | ||
384 | write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | | 384 | write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 | |
@@ -508,6 +508,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | |||
508 | { | 508 | { |
509 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); | 509 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); |
510 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; | 510 | struct ccsr_ssi __iomem *ssi = ssi_private->ssi; |
511 | unsigned int channels = params_channels(hw_params); | ||
511 | unsigned int sample_size = | 512 | unsigned int sample_size = |
512 | snd_pcm_format_width(params_format(hw_params)); | 513 | snd_pcm_format_width(params_format(hw_params)); |
513 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); | 514 | u32 wl = CCSR_SSI_SxCCR_WL(sample_size); |
@@ -537,6 +538,11 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | |||
537 | else | 538 | else |
538 | write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl); | 539 | write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl); |
539 | 540 | ||
541 | if (!ssi_private->imx_ac97) | ||
542 | write_ssi_mask(&ssi->scr, | ||
543 | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, | ||
544 | channels == 1 ? 0 : ssi_private->i2s_mode); | ||
545 | |||
540 | return 0; | 546 | return 0; |
541 | } | 547 | } |
542 | 548 | ||
@@ -649,14 +655,13 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { | |||
649 | static struct snd_soc_dai_driver fsl_ssi_dai_template = { | 655 | static struct snd_soc_dai_driver fsl_ssi_dai_template = { |
650 | .probe = fsl_ssi_dai_probe, | 656 | .probe = fsl_ssi_dai_probe, |
651 | .playback = { | 657 | .playback = { |
652 | /* The SSI does not support monaural audio. */ | 658 | .channels_min = 1, |
653 | .channels_min = 2, | ||
654 | .channels_max = 2, | 659 | .channels_max = 2, |
655 | .rates = FSLSSI_I2S_RATES, | 660 | .rates = FSLSSI_I2S_RATES, |
656 | .formats = FSLSSI_I2S_FORMATS, | 661 | .formats = FSLSSI_I2S_FORMATS, |
657 | }, | 662 | }, |
658 | .capture = { | 663 | .capture = { |
659 | .channels_min = 2, | 664 | .channels_min = 1, |
660 | .channels_max = 2, | 665 | .channels_max = 2, |
661 | .rates = FSLSSI_I2S_RATES, | 666 | .rates = FSLSSI_I2S_RATES, |
662 | .formats = FSLSSI_I2S_FORMATS, | 667 | .formats = FSLSSI_I2S_FORMATS, |