From 21246987b3cfcd2f2b894bc540c2bf1390eab874 Mon Sep 17 00:00:00 2001
From: =?utf8?q?=E9=82=B1=E5=BB=BA=E6=96=8C?= <qjb@rock-chips.com>
Date: Thu, 2 May 2013 11:19:56 +0800
Subject: [PATCH] i2s : fix restart i2s dma cannot read/write data.

---
 sound/soc/rk29/rk29_i2s.h |   5 ++
 sound/soc/rk29/rk30_i2s.c | 153 +++++++++++++-------------------------
 2 files changed, 55 insertions(+), 103 deletions(-)

diff --git a/sound/soc/rk29/rk29_i2s.h b/sound/soc/rk29/rk29_i2s.h
index 116001a99860..91d09ab2c75a 100755
--- a/sound/soc/rk29/rk29_i2s.h
+++ b/sound/soc/rk29/rk29_i2s.h
@@ -199,6 +199,11 @@
 #define I2S_TX_TRAN_STOP        (0<<0)
 #define I2S_TX_TRAN_START       (1<<0)
 
+//I2S_CLR
+#define I2S_RX_CLEAR	(1<<1)
+#define I2S_TX_CLEAR	1
+
+
 #ifdef CONFIG_ARCH_RK29
 #define I2S_TXR_BUFF            0x20
 #define I2S_RXR_BUFF            0x24
diff --git a/sound/soc/rk29/rk30_i2s.c b/sound/soc/rk29/rk30_i2s.c
index 62bb21bd6f98..0ac35544e415 100755
--- a/sound/soc/rk29/rk30_i2s.c
+++ b/sound/soc/rk29/rk30_i2s.c
@@ -87,116 +87,75 @@ static struct rk29_i2s_info rk29_i2s[MAX_I2S];
 struct snd_soc_dai_driver rk29_i2s_dai[MAX_I2S];
 EXPORT_SYMBOL_GPL(rk29_i2s_dai);
 
-static u32 i2s0_clk_enter(void)
-{
-  return 0;
-}
-
-static void i2s0_clk_exit(u32 clk)
-{
-}
-
 /* 
  *Turn on or off the transmission path. 
  */
- 
 static int flag_i2s_tx = 0;
 static int flag_i2s_rx = 0;
-static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
+static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on)
 {
-	u32 opr,xfer;
-	u32 clk;
-
+	u32 opr,xfer,clr;
 	opr  = readl(&(pheadi2s->I2S_DMACR));
 	xfer = readl(&(pheadi2s->I2S_XFER));
-
+	clr  = readl(&(pheadi2s->I2S_CLR));
 	if (on) 
 	{         
 		I2S_DBG("rockchip_snd_txctrl: on\n");
-
-		//start tx
-		//if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
-		if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
+		if ((opr & I2S_TRAN_DMA_ENABLE) == 0)
 		{
-			clk = i2s0_clk_enter();
-			
-			//if start tx & rx clk, need reset i2s
+			opr  |= I2S_TRAN_DMA_ENABLE;
+			writel(opr, &(pheadi2s->I2S_DMACR));	
+		}	
+		if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
+		{		
 			xfer |= I2S_TX_TRAN_START;
 			xfer |= I2S_RX_TRAN_START;
 			writel(xfer, &(pheadi2s->I2S_XFER));
-			
-			i2s0_clk_exit(clk);
-		}
-
-		if ((opr & I2S_TRAN_DMA_ENABLE) == 0)
-		{
-			opr  |= I2S_TRAN_DMA_ENABLE;
-			writel(opr, &(pheadi2s->I2S_DMACR));         
 		}
-
 		flag_i2s_tx = 1;
 	}
 	else
 	{
 		//stop tx
 		flag_i2s_tx = 0;
+		I2S_DBG("rockchip_snd_txctrl: off\n");
+		opr  &= ~I2S_TRAN_DMA_ENABLE;        
+		writel(opr, &(pheadi2s->I2S_DMACR));  		
 		if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
 		{
-			opr  &= ~I2S_TRAN_DMA_ENABLE;        
-			writel(opr, &(pheadi2s->I2S_DMACR));  
-			if(stopI2S)	
-			{
-				clk = i2s0_clk_enter();
-	
-				xfer &= ~I2S_RX_TRAN_START;
-				xfer &= ~I2S_TX_TRAN_START;
-				writel(xfer, &(pheadi2s->I2S_XFER));
-				
-				i2s0_clk_exit(clk);
-			}
-
-			//after stop rx & tx clk, reset i2s
-			//writel(0x001,&(pheadi2s->I2S_TXRST));
-			//writel(0x001,&(pheadi2s->I2S_RXRST));
-		}
-
-		I2S_DBG("rockchip_snd_txctrl: off\n");
-	} 
+			xfer &= ~I2S_TX_TRAN_START;
+			xfer &= ~I2S_RX_TRAN_START;		
+			writel(xfer, &(pheadi2s->I2S_XFER));
+			I2S_DBG("rockchip_snd_txctrl: off clr = %d\n",clr);		
+			clr |= I2S_TX_CLEAR;
+			I2S_DBG("rockchip_snd_txctrl: off clr = %d\n",clr);
+			writel(clr, &(pheadi2s->I2S_CLR));
+			udelay(1);
+		}	
+	}
 }
 
-
-static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
+static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on)
 {
-	u32 opr,xfer;
-	u32 clk;
-
+	u32 opr,xfer,clr;
 	opr  = readl(&(pheadi2s->I2S_DMACR));
 	xfer = readl(&(pheadi2s->I2S_XFER));
-
+	clr  = readl(&(pheadi2s->I2S_CLR));
 	if (on) 
 	{				 
 	    I2S_DBG("rockchip_snd_rxctrl: on\n");
-	    
-		//start rx
-		//if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0))
-		if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
-		{
-			clk = i2s0_clk_enter();
-			
-			xfer |= I2S_TX_TRAN_START;
-			xfer |= I2S_RX_TRAN_START;
-			writel(xfer, &(pheadi2s->I2S_XFER));
-			
-			i2s0_clk_exit(clk);
-		}
-
 		if ((opr & I2S_RECE_DMA_ENABLE) == 0)
 		{
 			opr  |= I2S_RECE_DMA_ENABLE;
-			writel(opr, &(pheadi2s->I2S_DMACR));
+			writel(opr, &(pheadi2s->I2S_DMACR));	
 		}
-
-	  flag_i2s_rx = 1;
+		if ((xfer&I2S_TX_TRAN_START)==0 || (xfer&I2S_RX_TRAN_START)==0)
+		{		
+			xfer |= I2S_RX_TRAN_START;
+			xfer |= I2S_TX_TRAN_START;
+			writel(xfer, &(pheadi2s->I2S_XFER));
+		}
+		flag_i2s_rx = 1;
 #ifdef CONFIG_SND_SOC_RT5631
 //bard 7-16 s
 		schedule_delayed_work(&rt5631_delay_cap,HZ/4);
@@ -207,28 +166,18 @@ static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S)
 	{
 		//stop rx
 		flag_i2s_rx = 0;
-		if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
-		{
-			opr  &= ~I2S_RECE_DMA_ENABLE;
-			writel(opr, &(pheadi2s->I2S_DMACR));
-		
-			if(stopI2S)	
-			{
-				clk = i2s0_clk_enter();
-			
-				xfer &= ~I2S_RX_TRAN_START;
-				xfer &= ~I2S_TX_TRAN_START;
-				writel(xfer, &(pheadi2s->I2S_XFER));
-				
-				i2s0_clk_exit(clk);
-			} 
-
-			//after stop rx & tx clk, reset i2s
-			//writel(0x001,&(pheadi2s->I2S_TXRST));
-			//writel(0x001,&(pheadi2s->I2S_RXRST));
-		}               
-		    
 		I2S_DBG("rockchip_snd_rxctrl: off\n");
+		opr  &= ~I2S_RECE_DMA_ENABLE;
+		writel(opr, &(pheadi2s->I2S_DMACR));		
+		if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0))
+		{		
+			xfer &= ~I2S_RX_TRAN_START;
+			xfer &= ~I2S_TX_TRAN_START;		
+			writel(xfer, &(pheadi2s->I2S_XFER));		
+			clr |= I2S_RX_CLEAR;
+			writel(clr, &(pheadi2s->I2S_CLR));
+			udelay(1);
+		}
 	}
 }
 
@@ -367,7 +316,6 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, st
 	int ret = 0;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct rk29_i2s_info *i2s = to_info(rtd->cpu_dai);
-	bool stopI2S = false;
 
 	I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
 	switch (cmd) {
@@ -375,19 +323,18 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, st
         case SNDRV_PCM_TRIGGER_RESUME:
         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:   
                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-	                rockchip_snd_rxctrl(i2s, 1, stopI2S);
+	                rockchip_snd_rxctrl(i2s, 1);
                 else
-	                rockchip_snd_txctrl(i2s, 1, stopI2S);
+	                rockchip_snd_txctrl(i2s, 1);
                 break;
         
         case SNDRV_PCM_TRIGGER_SUSPEND:
-                stopI2S = true;
         case SNDRV_PCM_TRIGGER_STOP:
         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-	                rockchip_snd_rxctrl(i2s, 0, stopI2S);
+	                rockchip_snd_rxctrl(i2s, 0);
                 else
-	                rockchip_snd_txctrl(i2s, 0, stopI2S);
+	                rockchip_snd_txctrl(i2s, 0);
                 break;
         default:
                 ret = -EINVAL;
@@ -599,8 +546,8 @@ static int rk29_i2s_probe(struct platform_device *pdev,
 
 	/* Mark ourselves as in TXRX mode so we can run through our cleanup
 	 * process without warnings. */
-	rockchip_snd_txctrl(i2s, 0, true);
-	rockchip_snd_rxctrl(i2s, 0, true);
+	rockchip_snd_txctrl(i2s, 0);
+	rockchip_snd_rxctrl(i2s, 0);
 
 	return 0;
 }
-- 
2.34.1