Merge branch 'topic/seq-midi-fix' into for-linus
[pandora-kernel.git] / sound / soc / pxa / pxa2xx-i2s.c
index 2f4b6e4..4743e26 100644 (file)
@@ -106,10 +106,8 @@ static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
        if (IS_ERR(clk_i2s))
                return PTR_ERR(clk_i2s);
 
-       if (!cpu_dai->active) {
-               SACR0 |= SACR0_RST;
+       if (!cpu_dai->active)
                SACR0 = 0;
-       }
 
        return 0;
 }
@@ -178,9 +176,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* is port used by another stream */
        if (!(SACR0 & SACR0_ENB)) {
-
                SACR0 = 0;
-               SACR1 = 0;
                if (pxa_i2s.master)
                        SACR0 |= SACR0_BCKD;
 
@@ -226,6 +222,10 @@ static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       SACR1 &= ~SACR1_DRPL;
+               else
+                       SACR1 &= ~SACR1_DREC;
                SACR0 |= SACR0_ENB;
                break;
        case SNDRV_PCM_TRIGGER_RESUME:
@@ -252,21 +252,16 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
                SAIMR &= ~SAIMR_RFS;
        }
 
-       if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
+       if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
                SACR0 &= ~SACR0_ENB;
                pxa_i2s_wait();
                clk_disable(clk_i2s);
        }
-
-       clk_put(clk_i2s);
 }
 
 #ifdef CONFIG_PM
 static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 {
-       if (!dai->active)
-               return 0;
-
        /* store registers */
        pxa_i2s.sacr0 = SACR0;
        pxa_i2s.sacr1 = SACR1;
@@ -281,16 +276,14 @@ static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
 
 static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
 {
-       if (!dai->active)
-               return 0;
-
        pxa_i2s_wait();
 
-       SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
+       SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
        SACR1 = pxa_i2s.sacr1;
        SAIMR = pxa_i2s.saimr;
        SADIV = pxa_i2s.sadiv;
-       SACR0 |= SACR0_ENB;
+
+       SACR0 = pxa_i2s.sacr0;
 
        return 0;
 }
@@ -329,6 +322,7 @@ struct snd_soc_dai pxa_i2s_dai = {
                .rates = PXA2XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
        .ops = &pxa_i2s_dai_ops,
+       .symmetric_rates = 1,
 };
 
 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
@@ -346,6 +340,19 @@ static int pxa2xx_i2s_probe(struct platform_device *dev)
        if (ret != 0)
                clk_put(clk_i2s);
 
+       /*
+        * PXA Developer's Manual:
+        * If SACR0[ENB] is toggled in the middle of a normal operation,
+        * the SACR0[RST] bit must also be set and cleared to reset all
+        * I2S controller registers.
+        */
+       SACR0 = SACR0_RST;
+       SACR0 = 0;
+       /* Make sure RPL and REC are disabled */
+       SACR1 = SACR1_DRPL | SACR1_DREC;
+       /* Along with FIFO servicing */
+       SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
        return ret;
 }