summaryrefslogtreecommitdiff
path: root/sound/soc/davinci
diff options
context:
space:
mode:
authorNaresh Medisetty <naresh@ti.com>2008-11-12 10:26:31 +0530
committerMark Brown <broonie@opensource.wolfsonmicro.com>2008-11-12 11:50:29 +0000
commitfb0ef645f2c546f8297b2fbf9b2b8fff4a7455e8 (patch)
tree462841d826305be529cea4ae75c4d0fa2da042fa /sound/soc/davinci
parentb402dff8739cd82c58b632ba472caf26ae8741ed (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>
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r--sound/soc/davinci/davinci-i2s.c49
1 files changed, 46 insertions, 3 deletions
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c
index d814ec8947e5..8c1bf876031d 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);