ASoC: DaVinci: Audio: Fix swapping of channels at start of stereo playback
authorNaresh Medisetty <naresh@ti.com>
Wed, 12 Nov 2008 04:56:31 +0000 (10:26 +0530)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 12 Nov 2008 11:50:29 +0000 (11:50 +0000)
Fixes swapping of channels at start of stereo playback.

Channel swap can be observed while playing left-only or right-only audio data. The channel
swap is fixed by handling the XSYNCERR condition.

Signed-off-by: Naresh Medisetty <naresh@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/davinci/davinci-i2s.c

index d814ec8947e5c7e22f45a8b12ef39c08eb9ff962..8c1bf876031d76ab3b9e550642dac073585ff526 100644 (file)
@@ -111,16 +111,59 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+       struct snd_soc_device *socdev = rtd->socdev;
+       struct snd_soc_platform *platform = socdev->platform;
        u32 w;
+       int ret;
 
        /* Start the sample generator and enable transmitter/receiver */
        w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
        MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               /* Stop the DMA to avoid data loss */
+               /* while the transmitter is out of reset to handle XSYNCERR */
+               if (platform->pcm_ops->trigger) {
+                       ret = platform->pcm_ops->trigger(substream,
+                               SNDRV_PCM_TRIGGER_STOP);
+                       if (ret < 0)
+                               printk(KERN_DEBUG "Playback DMA stop failed\n");
+               }
+
+               /* Enable the transmitter */
+               w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
                MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
-       else
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+               /* wait for any unexpected frame sync error to occur */
+               udelay(100);
+
+               /* Disable the transmitter to clear any outstanding XSYNCERR */
+               w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+               MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0);
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+               /* Restart the DMA */
+               if (platform->pcm_ops->trigger) {
+                       ret = platform->pcm_ops->trigger(substream,
+                               SNDRV_PCM_TRIGGER_START);
+                       if (ret < 0)
+                               printk(KERN_DEBUG "Playback DMA start failed\n");
+               }
+               /* Enable the transmitter */
+               w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+               MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1);
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+
+       } else {
+
+               /* Enable the reciever */
+               w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
                MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1);
-       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w);
+       }
+
 
        /* Start frame sync */
        w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);