From: 胡卫国 Date: Sat, 22 Oct 2011 07:35:39 +0000 (+0800) Subject: i2s0针对音频随机性出噪声修改: X-Git-Tag: firefly_0821_release~9766^2~4 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=3dd097b3367c47512921227013fb587c4fc9841a;p=firefly-linux-kernel-4.4.55.git i2s0针对音频随机性出噪声修改:   1) i2s0的rx, tx两者都为master,通过修改i2s0的clk来保证lrck_tx与lrck_rx同步 2) 硬件上针对只有一路LRCK的codec,例如alc5631/5621,可以单独将I2S0_LRCK连接到codec的LRCK, 也可以将I2S0_LRCK与I2S0_LRCK_RX一起连接到codec的LRCK --- diff --git a/sound/soc/rk29/rk29_i2s.c b/sound/soc/rk29/rk29_i2s.c index eb5e7c722c4b..878200992424 100755 --- a/sound/soc/rk29/rk29_i2s.c +++ b/sound/soc/rk29/rk29_i2s.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "rk29_pcm.h" #include "rk29_i2s.h" @@ -117,8 +118,31 @@ static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = { }; */ +#if 1 +static u32 i2s0_clk_enter() +{ + u32 clk = cru_readl(CRU_CLKSEL3_CON); + cru_writel(0x1ffff, CRU_CLKSEL3_CON); + mdelay(1); + return clk; +} +static void i2s0_clk_exit(u32 clk) +{ + mdelay(1); + cru_writel(clk, CRU_CLKSEL3_CON); + mdelay(1); +} +#else +static u32 i2s0_clk_enter() +{ + return 0; +} +static void i2s0_clk_exit(u32 clk) +{ +} +#endif /* *Turn on or off the transmission path. @@ -126,9 +150,10 @@ static struct rockchip_pcm_dma_params rockchip_i2s_pcm_stereo_in[MAX_I2S] = { static int flag_i2s_tx = 0; static int flag_i2s_rx = 0; -static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on) +static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S) { u32 opr,xfer; + u32 clk; opr = readl(&(pheadi2s->I2S_DMACR)); xfer = readl(&(pheadi2s->I2S_XFER)); @@ -138,12 +163,17 @@ static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on) I2S_DBG("rockchip_snd_txctrl: on\n"); //start tx - if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0)) + //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(); + //if start tx & rx clk, need reset i2s 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) @@ -163,23 +193,30 @@ static void rockchip_snd_txctrl(struct rk29_i2s_info *i2s, int on) { opr &= ~I2S_TRAN_DMA_ENABLE; writel(opr, &(pheadi2s->I2S_DMACR)); - - xfer &= ~I2S_RX_TRAN_START; - xfer &= ~I2S_TX_TRAN_START; - writel(xfer, &(pheadi2s->I2S_XFER)); + 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)); + //writel(0x001,&(pheadi2s->I2S_TXRST)); + //writel(0x001,&(pheadi2s->I2S_RXRST)); } I2S_DBG("rockchip_snd_txctrl: off\n"); } } -static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on) +static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on, bool stopI2S) { u32 opr,xfer; + u32 clk; opr = readl(&(pheadi2s->I2S_DMACR)); xfer = readl(&(pheadi2s->I2S_XFER)); @@ -189,40 +226,52 @@ static void rockchip_snd_rxctrl(struct rk29_i2s_info *i2s, int on) I2S_DBG("rockchip_snd_rxctrl: on\n"); //start rx - if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0)) + //if ((flag_i2s_tx == 0) && (flag_i2s_rx == 0)) + 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)); - } + 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) - { + if ((opr & I2S_RECE_DMA_ENABLE) == 0) + { opr |= I2S_RECE_DMA_ENABLE; writel(opr, &(pheadi2s->I2S_DMACR)); } - flag_i2s_rx = 1; + flag_i2s_rx = 1; } else { //stop rx - flag_i2s_rx = 0; - if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0)) - { + flag_i2s_rx = 0; + if ((flag_i2s_rx == 0) && (flag_i2s_tx == 0)) + { opr &= ~I2S_RECE_DMA_ENABLE; writel(opr, &(pheadi2s->I2S_DMACR)); - - xfer &= ~I2S_RX_TRAN_START; - xfer &= ~I2S_TX_TRAN_START; - writel(xfer, &(pheadi2s->I2S_XFER)); + + 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)); - } + //writel(0x001,&(pheadi2s->I2S_TXRST)); + //writel(0x001,&(pheadi2s->I2S_RXRST)); + } - I2S_DBG("rockchip_snd_rxctrl: off\n"); + I2S_DBG("rockchip_snd_rxctrl: off\n"); } } @@ -364,25 +413,27 @@ 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->dai->cpu_dai); + bool stopI2S = false; I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - rockchip_snd_rxctrl(i2s, 1); + rockchip_snd_rxctrl(i2s, 1, stopI2S); else - rockchip_snd_txctrl(i2s, 1); + rockchip_snd_txctrl(i2s, 1, stopI2S); break; - case SNDRV_PCM_TRIGGER_STOP: + 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); + rockchip_snd_rxctrl(i2s, 0, stopI2S); else - rockchip_snd_txctrl(i2s, 0); + rockchip_snd_txctrl(i2s, 0, stopI2S); break; default: ret = -EINVAL; @@ -581,8 +632,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); - rockchip_snd_rxctrl(i2s, 0); + rockchip_snd_txctrl(i2s, 0, true); + rockchip_snd_rxctrl(i2s, 0, true); return 0; }