ASoC: davinci-mcasp: Fix synchronous master receive mode

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>
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 35a6292..93f2e29 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -48,6 +48,7 @@
 	u8	*serial_dir;
 	u8	version;
 	u16	bclk_lrclk_ratio;
+	int	streams;
 
 	/* McASP FIFO related */
 	u8	txnumevt;
@@ -110,10 +111,31 @@
 		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 @@
 
 	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 @@
 {
 	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 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 @@
 {
 	u32 reg;
 
+	mcasp->streams--;
+
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		if (mcasp->txnumevt) {	/* disable FIFO */
 			reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;