ASoC: DaVinci: i2s toggle clock to complete reset
authorTroy Kisky <troy.kisky@boundarydevices.com>
Sun, 5 Jul 2009 02:29:52 +0000 (19:29 -0700)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 5 Jul 2009 11:59:06 +0000 (12:59 +0100)
Add toggle_clock function to complete i2s reset earlier.

Signed-off-by: Troy Kisky <troy.kisky@boundarydevices.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
sound/soc/davinci/davinci-i2s.c

index bf5ec4b2f7f5f55804f841983350344668f79a99..dd44167a90f07c9d06f75d47d074ec0e7b6e1938 100644 (file)
@@ -104,6 +104,7 @@ static struct davinci_pcm_dma_params davinci_i2s_pcm_in = {
 
 struct davinci_mcbsp_dev {
        void __iomem                    *base;
+       u32                             pcr;
        struct clk                      *clk;
        struct davinci_pcm_dma_params   *dma_params[2];
 };
@@ -119,17 +120,34 @@ static inline u32 davinci_mcbsp_read_reg(struct davinci_mcbsp_dev *dev, int reg)
        return __raw_readl(dev->base + reg);
 }
 
+static void toggle_clock(struct davinci_mcbsp_dev *dev, int playback)
+{
+       u32 m = playback ? DAVINCI_MCBSP_PCR_CLKXP : DAVINCI_MCBSP_PCR_CLKRP;
+       /* The clock needs to toggle to complete reset.
+        * So, fake it by toggling the clk polarity.
+        */
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr ^ m);
+       davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, dev->pcr);
+}
+
 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->card->platform;
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
        u32 spcr;
        int ret;
-
-       /* Start the sample generator and enable transmitter/receiver */
+       u32 mask = playback ? DAVINCI_MCBSP_SPCR_XRST : DAVINCI_MCBSP_SPCR_RRST;
        spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
+       if (spcr & mask) {
+               /* start off disabled */
+               davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG,
+                               spcr & ~mask);
+               toggle_clock(dev, playback);
+       }
+       /* Start the sample generator and enable transmitter/receiver */
        spcr |= DAVINCI_MCBSP_SPCR_GRST;
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
 
@@ -155,6 +173,7 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream)
                spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
                spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
                davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+               toggle_clock(dev, playback);
 
                /* Restart the DMA */
                if (platform->pcm_ops->trigger) {
@@ -188,15 +207,14 @@ static void davinci_mcbsp_stop(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;
        u32 spcr;
+       int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
        /* Reset transmitter/receiver and sample rate/frame sync generators */
        spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG);
        spcr &= ~(DAVINCI_MCBSP_SPCR_GRST | DAVINCI_MCBSP_SPCR_FRST);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               spcr &= ~DAVINCI_MCBSP_SPCR_XRST;
-       else
-               spcr &= ~DAVINCI_MCBSP_SPCR_RRST;
+       spcr &= playback ? ~DAVINCI_MCBSP_SPCR_XRST : ~DAVINCI_MCBSP_SPCR_RRST;
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr);
+       toggle_clock(dev, playback);
 }
 
 static int davinci_i2s_startup(struct snd_pcm_substream *substream,
@@ -334,6 +352,7 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                return -EINVAL;
        }
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+       dev->pcr = pcr;
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
        davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);