diff options
author | Naresh Medisetty <naresh@ti.com> | 2008-11-12 10:26:31 +0530 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2008-11-12 11:50:29 +0000 |
commit | fb0ef645f2c546f8297b2fbf9b2b8fff4a7455e8 (patch) | |
tree | 462841d826305be529cea4ae75c4d0fa2da042fa | |
parent | b402dff8739cd82c58b632ba472caf26ae8741ed (diff) |
ASoC: DaVinci: Audio: Fix swapping of channels at start of stereo playback
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>
-rw-r--r-- | sound/soc/davinci/davinci-i2s.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index d814ec8947e..8c1bf876031 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -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); |