ASoC: davinci-mcasp: Fix synchronous master receive mode
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Thu, 14 Nov 2013 09:35:33 +0000 (11:35 +0200)
committerMark Brown <broonie@linaro.org>
Tue, 10 Dec 2013 11:22:16 +0000 (11:22 +0000)
In synchronous mode both transmit and receive sections are using the TX
clocks. In setup like this the TX clocks need to be enabled when capture
is running.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
sound/soc/davinci/davinci-mcasp.c

index 35a6292889a59b7777c8844311d1cbe41bde06e7..93f2e294d649e1dec2c0057b7a2fb451f6cd0fb8 100644 (file)
@@ -48,6 +48,7 @@ struct davinci_mcasp {
        u8      *serial_dir;
        u8      version;
        u16     bclk_lrclk_ratio;
+       int     streams;
 
        /* McASP FIFO related */
        u8      txnumevt;
@@ -110,10 +111,31 @@ static void mcasp_set_ctl_reg(void __iomem *regs, u32 val)
                printk(KERN_ERR "GBLCTL write error\n");
 }
 
+static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
+{
+       u32 rxfmctl = mcasp_get_reg(mcasp->base + DAVINCI_MCASP_RXFMCTL_REG);
+       u32 aclkxctl = mcasp_get_reg(mcasp->base + DAVINCI_MCASP_ACLKXCTL_REG);
+
+       return !(aclkxctl & TX_ASYNC) && rxfmctl & AFSRE;
+}
+
 static void mcasp_start_rx(struct davinci_mcasp *mcasp)
 {
        mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
        mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
+
+       /*
+        * When ASYNC == 0 the transmit and receive sections operate
+        * synchronously from the transmit clock and frame sync. We need to make
+        * sure that the TX signlas are enabled when starting reception.
+        */
+       if (mcasp_is_synchronous(mcasp)) {
+               mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
+                                 TXHCLKRST);
+               mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
+                                 TXCLKRST);
+       }
+
        mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
        mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXBUF_REG, 0);
 
@@ -123,6 +145,10 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
 
        mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
        mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
+
+       if (mcasp_is_synchronous(mcasp))
+               mcasp_set_ctl_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG,
+                                 TXFSRST);
 }
 
 static void mcasp_start_tx(struct davinci_mcasp *mcasp)
@@ -158,6 +184,8 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
 {
        u32 reg;
 
+       mcasp->streams++;
+
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (mcasp->txnumevt) {  /* enable FIFO */
                        reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
@@ -177,13 +205,29 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
 
 static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
 {
+       /*
+        * In synchronous mode stop the TX clocks if no other stream is
+        * running
+        */
+       if (mcasp_is_synchronous(mcasp) && !mcasp->streams)
+               mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
+
        mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLR_REG, 0);
        mcasp_set_reg(mcasp->base + DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
 }
 
 static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
 {
-       mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, 0);
+       u32 val = 0;
+
+       /*
+        * In synchronous mode keep TX clocks running if the capture stream is
+        * still running.
+        */
+       if (mcasp_is_synchronous(mcasp) && mcasp->streams)
+               val =  TXHCLKRST | TXCLKRST | TXFSRST;
+
+       mcasp_set_reg(mcasp->base + DAVINCI_MCASP_GBLCTLX_REG, val);
        mcasp_set_reg(mcasp->base + DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
 }
 
@@ -191,6 +235,8 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
 {
        u32 reg;
 
+       mcasp->streams--;
+
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (mcasp->txnumevt) {  /* disable FIFO */
                        reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;