From: Sugar Zhang Date: Thu, 2 Jul 2015 11:53:06 +0000 (+0800) Subject: ASoC: rockchip: refactor i2s driver. X-Git-Tag: firefly_0821_release~3952 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b1ce30ae22975dcc81decf728312b2d776d6428b;p=firefly-linux-kernel-4.4.55.git ASoC: rockchip: refactor i2s driver. Signed-off-by: Sugar Zhang --- diff --git a/sound/soc/rockchip/rk30_i2s.c b/sound/soc/rockchip/rk30_i2s.c old mode 100755 new mode 100644 index 4f8b1c9eaf93..d551860c4acb --- a/sound/soc/rockchip/rk30_i2s.c +++ b/sound/soc/rockchip/rk30_i2s.c @@ -1,13 +1,16 @@ /* - * rk30_i2s.c -- ALSA SoC ROCKCHIP IIS Audio Layer Platform driver + * Rockchip I2S ALSA SoC Digital Audio Interface(DAI) driver * - * Driver for rockchip iis audio + * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * */ @@ -20,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -36,375 +38,304 @@ #include #include #include -#include #include #include -#define CLK_SET_lATER - #include "rk_pcm.h" #include "rk_i2s.h" -#include "../../../drivers/video/rockchip/hdmi/rockchip-hdmi.h" - -#if 0 -#define I2S_DBG(x...) printk(KERN_INFO x) -#else -#define I2S_DBG(x...) do { } while (0) -#endif - -#define pheadi2s ((pI2S_REG)(i2s->regs)) - -#define MAX_I2S 3 +#define CLK_SET_LATER +#define I2S_DEFAULT_FREQ (11289600) +#define I2S_DMA_BURST_SIZE (16) /* size * width: 16*4 = 64 bytes */ static DEFINE_SPINLOCK(lock); -struct rk30_i2s_info { - void __iomem *regs; +#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_RK_SOC_HDMI_I2S) +extern int snd_config_hdmi_audio(struct snd_pcm_hw_params *params); +#endif - struct clk *i2s_clk;// i2s clk ,is bclk lrck - struct clk *i2s_mclk;//i2s mclk,rk32xx can different i2s clk. - struct clk *i2s_hclk; +struct rk_i2s_dev { + struct device *dev; + struct clk *clk; /* bclk */ + struct clk *mclk; /*mclk output only */ + struct clk *hclk; /*ahb clk */ struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; - - bool i2s_tx_status;//active = true; - bool i2s_rx_status; -#ifdef CLK_SET_lATER + struct regmap *regmap; + bool tx_start; + bool rx_start; +#ifdef CLK_SET_LATER struct delayed_work clk_delayed_work; -#endif -}; - -#define I2S_CLR_ERROR_COUNT 10// check I2S_CLR reg -static struct rk30_i2s_info *rk30_i2s; - -#if 0 /*defined (CONFIG_RK_HDMI) && defined (CONFIG_SND_RK_SOC_HDMI_I2S)*/ -extern int hdmi_get_hotplug(void); -#else -#define hdmi_get_hotplug() 0 #endif +}; - - -static inline struct rk30_i2s_info *to_info(struct snd_soc_dai *dai) +static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai) { return snd_soc_dai_get_drvdata(dai); } -/* - *Turn on or off the transmission path. - */ -static void rockchip_snd_txctrl(struct rk30_i2s_info *i2s, int on) +static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) { - u32 opr, xfer, clr; unsigned long flags; - bool is_need_delay = false; - int clr_error_count = I2S_CLR_ERROR_COUNT; + unsigned int val = 0; + int retry = 10; spin_lock_irqsave(&lock, flags); - opr = readl(&(pheadi2s->I2S_DMACR)); - xfer = readl(&(pheadi2s->I2S_XFER)); - clr = readl(&(pheadi2s->I2S_CLR)); - - I2S_DBG("rockchip_snd_txctrl: %s\n", on ? "on" : "off"); + dev_dbg(i2s->dev, "%s: %d: on: %d\n", __func__, __LINE__, on); if (on) { - if ((opr & I2S_TRAN_DMA_ENABLE) == 0) { - 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)); - } - - i2s->i2s_tx_status = 1; + regmap_update_bits(i2s->regmap, I2S_DMACR, + I2S_DMACR_TDE_MASK, I2S_DMACR_TDE_ENABLE); - } else { //stop tx - i2s->i2s_tx_status = 0; - opr &= ~I2S_TRAN_DMA_ENABLE; - writel(opr, &(pheadi2s->I2S_DMACR)); + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK, + I2S_XFER_TXS_START | I2S_XFER_RXS_START); - if (i2s->i2s_rx_status == 0 && hdmi_get_hotplug() == 0) { - xfer &= ~I2S_TX_TRAN_START; - xfer &= ~I2S_RX_TRAN_START; - writel(xfer, &(pheadi2s->I2S_XFER)); - - clr |= I2S_TX_CLEAR; - clr |= I2S_RX_CLEAR; - writel(clr, &(pheadi2s->I2S_CLR)); - - is_need_delay = true; - - I2S_DBG("rockchip_snd_txctrl: stop xfer\n"); + i2s->tx_start = true; + } else { + i2s->tx_start = false; + + regmap_update_bits(i2s->regmap, I2S_DMACR, + I2S_DMACR_TDE_MASK, I2S_DMACR_TDE_DISABLE); + + + if (!i2s->rx_start) { + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_MASK | + I2S_XFER_RXS_MASK, + I2S_XFER_TXS_STOP | + I2S_XFER_RXS_STOP); + + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK, + I2S_CLR_TXC | I2S_CLR_RXC); + + regmap_read(i2s->regmap, I2S_CLR, &val); + + /* Should wait for clear operation to finish */ + while (val) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; + } + } + dev_dbg(i2s->dev, "%s: %d: stop xfer\n", + __func__, __LINE__); } } spin_unlock_irqrestore(&lock, flags); - - if (is_need_delay){ - while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){ - udelay(1); - clr_error_count --; - if(clr_error_count == 0) - printk("%s: i2s clr reg warning =%d\n",__FUNCTION__,readl(&(pheadi2s->I2S_CLR))); - } - } } -static void rockchip_snd_rxctrl(struct rk30_i2s_info *i2s, int on) +static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) { - u32 opr, xfer, clr; unsigned long flags; - bool is_need_delay = false; - int clr_error_count = I2S_CLR_ERROR_COUNT; + unsigned int val = 0; + int retry = 10; spin_lock_irqsave(&lock, flags); - opr = readl(&(pheadi2s->I2S_DMACR)); - xfer = readl(&(pheadi2s->I2S_XFER)); - clr = readl(&(pheadi2s->I2S_CLR)); - - I2S_DBG("rockchip_snd_rxctrl: %s\n", on ? "on" : "off"); + dev_dbg(i2s->dev, "%s: %d: on: %d\n", __func__, __LINE__, on); if (on) { - if ((opr & I2S_RECE_DMA_ENABLE) == 0) { - opr |= I2S_RECE_DMA_ENABLE; - writel(opr, &(pheadi2s->I2S_DMACR)); - } + regmap_update_bits(i2s->regmap, I2S_DMACR, + I2S_DMACR_RDE_MASK, I2S_DMACR_RDE_ENABLE); - 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)); - } + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_MASK | I2S_XFER_RXS_MASK, + I2S_XFER_TXS_START | I2S_XFER_RXS_START); - i2s->i2s_rx_status = 1; + i2s->rx_start = true; } else { - i2s->i2s_rx_status = 0; - - opr &= ~I2S_RECE_DMA_ENABLE; - writel(opr, &(pheadi2s->I2S_DMACR)); - - if (i2s->i2s_tx_status == 0 && hdmi_get_hotplug() == 0) { - xfer &= ~I2S_RX_TRAN_START; - xfer &= ~I2S_TX_TRAN_START; - writel(xfer, &(pheadi2s->I2S_XFER)); - - clr |= I2S_RX_CLEAR; - clr |= I2S_TX_CLEAR; - writel(clr, &(pheadi2s->I2S_CLR)); - - is_need_delay = true; - - I2S_DBG("rockchip_snd_rxctrl: stop xfer\n"); + i2s->rx_start = false; + + regmap_update_bits(i2s->regmap, I2S_DMACR, + I2S_DMACR_RDE_MASK, I2S_DMACR_RDE_DISABLE); + + if (!i2s->tx_start) { + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_MASK | + I2S_XFER_RXS_MASK, + I2S_XFER_TXS_STOP | + I2S_XFER_RXS_STOP); + + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_TXC_MASK | I2S_CLR_RXC_MASK, + I2S_CLR_TXC | I2S_CLR_RXC); + + regmap_read(i2s->regmap, I2S_CLR, &val); + + /* Should wait for clear operation to finish */ + while (val) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; + } + } + dev_dbg(i2s->dev, "%s: %d: stop xfer\n", + __func__, __LINE__); } } spin_unlock_irqrestore(&lock, flags); - - if (is_need_delay){ - while(readl(&(pheadi2s->I2S_CLR)) && clr_error_count){ - udelay(1); - clr_error_count --; - if(clr_error_count == 0) - printk("%s: i2s clr reg warning =%d\n",__FUNCTION__,readl(&(pheadi2s->I2S_CLR))); - } - } } -/* - * Set Rockchip I2S DAI format - */ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, - unsigned int fmt) + unsigned int fmt) { - struct rk30_i2s_info *i2s = to_info(cpu_dai); - u32 tx_ctl,rx_ctl; - u32 iis_ckr_value;//clock generation register - unsigned long flags; + struct rk_i2s_dev *i2s = to_info(cpu_dai); + unsigned int mask = 0, val = 0; int ret = 0; - - I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); + unsigned long flags; spin_lock_irqsave(&lock, flags); - tx_ctl = readl(&(pheadi2s->I2S_TXCR)); - iis_ckr_value = readl(&(pheadi2s->I2S_CKR)); - + mask = I2S_CKR_MSS_MASK; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - //Codec is master, so set cpu slave. - iis_ckr_value &= ~I2S_MODE_MASK; - iis_ckr_value |= I2S_SLAVE_MODE; - break; case SND_SOC_DAIFMT_CBS_CFS: - //Codec is slave, so set cpu master. - iis_ckr_value &= ~I2S_MODE_MASK; - iis_ckr_value |= I2S_MASTER_MODE; + /* Codec is slave, so set cpu master */ + val = I2S_CKR_MSS_MASTER; + break; + case SND_SOC_DAIFMT_CBM_CFM: + /* Codec is master, so set cpu slave */ + val = I2S_CKR_MSS_SLAVE; break; default: - I2S_DBG("unknwon master/slave format\n"); ret = -EINVAL; - goto out_; + goto err_fmt; } - writel(iis_ckr_value, &(pheadi2s->I2S_CKR)); + regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); + mask = I2S_TXCR_IBM_MASK; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_RIGHT_J: - tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode - tx_ctl |= I2S_BUS_MODE_RSJM; + val = I2S_TXCR_IBM_RSJM; break; case SND_SOC_DAIFMT_LEFT_J: - tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode - tx_ctl |= I2S_BUS_MODE_LSJM; + val = I2S_TXCR_IBM_LSJM; break; case SND_SOC_DAIFMT_I2S: - tx_ctl &= ~I2S_BUS_MODE_MASK; //I2S Bus Mode - tx_ctl |= I2S_BUS_MODE_NOR; + val = I2S_TXCR_IBM_NORMAL; break; default: - I2S_DBG("Unknown data format\n"); ret = -EINVAL; - goto out_; + goto err_fmt; } - I2S_DBG("Enter::%s----%d, I2S_TXCR=0x%X\n",__FUNCTION__,__LINE__,tx_ctl); + regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val); - writel(tx_ctl, &(pheadi2s->I2S_TXCR)); + mask = I2S_RXCR_IBM_MASK; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + val = I2S_RXCR_IBM_RSJM; + break; + case SND_SOC_DAIFMT_LEFT_J: + val = I2S_RXCR_IBM_LSJM; + break; + case SND_SOC_DAIFMT_I2S: + val = I2S_RXCR_IBM_NORMAL; + break; + default: + ret = -EINVAL; + goto err_fmt; + } - rx_ctl = tx_ctl & 0x00007FFF; - writel(rx_ctl, &(pheadi2s->I2S_RXCR)); + regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val); -out_: +err_fmt: spin_unlock_irqrestore(&lock, flags); - return ret; } -static int SR2FS(int samplerate) -{ - switch (samplerate) { - case 32000: - return HDMI_AUDIO_FS_32000; - case 44100: - return HDMI_AUDIO_FS_44100; - case 48000: - return HDMI_AUDIO_FS_48000; - case 88200: - return HDMI_AUDIO_FS_88200; - case 96000: - return HDMI_AUDIO_FS_96000; - case 176400: - return HDMI_AUDIO_FS_176400; - case 192000: - return HDMI_AUDIO_FS_192000; - default: - I2S_DBG("SR2FS %d unsupport.", samplerate); - return HDMI_AUDIO_FS_44100; - } -} - static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { - struct rk30_i2s_info *i2s = to_info(dai); - u32 iismod; - u32 dmarc; + struct rk_i2s_dev *i2s = to_info(dai); + unsigned int val = 0; unsigned long flags; - struct hdmi_audio hdmi_audio_cfg; - - I2S_DBG("Enter %s, %d \n", __func__, __LINE__); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dai->playback_dma_data = &i2s->playback_dma_data; - else - dai->capture_dma_data = &i2s->capture_dma_data; spin_lock_irqsave(&lock, flags); - /* Working copies of register */ - iismod = readl(&(pheadi2s->I2S_TXCR)); + dev_dbg(i2s->dev, "%s: %d\n", __func__, __LINE__); - iismod &= (~((1<<5)-1)); switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: - iismod |= SAMPLE_DATA_8bit; + val |= I2S_TXCR_VDW(8); break; case SNDRV_PCM_FORMAT_S16_LE: - iismod |= I2S_DATA_WIDTH(15); + val |= I2S_TXCR_VDW(16); break; case SNDRV_PCM_FORMAT_S20_3LE: - iismod |= I2S_DATA_WIDTH(19); + val |= I2S_TXCR_VDW(20); break; case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_3LE: - iismod |= I2S_DATA_WIDTH(23); + val |= I2S_TXCR_VDW(24); break; case SNDRV_PCM_FORMAT_S32_LE: - iismod |= I2S_DATA_WIDTH(31); + val |= I2S_TXCR_VDW(32); break; + default: + dev_err(i2s->dev, "invalid fmt: %d\n", params_format(params)); + spin_unlock_irqrestore(&lock, flags); + return -EINVAL; } - iismod &= ~CHANNLE_4_EN; + switch (params_channels(params)) { - case 8: - iismod |= CHANNLE_4_EN; + case I2S_CHANNEL_8: + val |= I2S_TXCR_CHN_8; break; - case 6: - iismod |= CHANNEL_3_EN; + case I2S_CHANNEL_6: + val |= I2S_TXCR_CHN_6; break; - case 4: - iismod |= CHANNEL_2_EN; + case I2S_CHANNEL_4: + val |= I2S_TXCR_CHN_4; break; - case 2: - iismod |= CHANNEL_1_EN; + case I2S_CHANNEL_2: + val |= I2S_TXCR_CHN_2; break; default: - I2S_DBG("%d channels not supported\n", + dev_err(i2s->dev, "invalid channel: %d\n", params_channels(params)); + spin_unlock_irqrestore(&lock, flags); return -EINVAL; } - /* set hdmi codec params */ - if (HW_PARAMS_FLAG_NLPCM == params->flags) - hdmi_audio_cfg.type = HDMI_AUDIO_NLPCM; - else - hdmi_audio_cfg.type = HDMI_AUDIO_LPCM; - hdmi_audio_cfg.channel = params_channels(params); - hdmi_audio_cfg.rate = SR2FS(params_rate(params)); - hdmi_audio_cfg.word_length = HDMI_AUDIO_WORD_LENGTH_16bit; - hdmi_config_audio(&hdmi_audio_cfg); - - dmarc = readl(&(pheadi2s->I2S_DMACR)); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - dmarc = ((dmarc & 0xFFFFFE00) | 16); - else - dmarc = ((dmarc & 0xFE00FFFF) | 16<<16); - - writel(dmarc, &(pheadi2s->I2S_DMACR)); - - I2S_DBG("Enter %s, %d I2S_TXCR=0x%08X\n", __func__, __LINE__, iismod); - - writel(iismod, &(pheadi2s->I2S_TXCR)); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(i2s->regmap, I2S_TXCR, + I2S_TXCR_VDW_MASK | + I2S_TXCR_CSR_MASK, + val); + } else { + regmap_update_bits(i2s->regmap, I2S_RXCR, + I2S_RXCR_VDW_MASK, val); + } - iismod = iismod & 0x00007FFF; - writel(iismod, &(pheadi2s->I2S_RXCR)); + regmap_update_bits(i2s->regmap, I2S_DMACR, + I2S_DMACR_TDL_MASK | I2S_DMACR_RDL_MASK, + I2S_DMACR_TDL(16) | I2S_DMACR_RDL(16)); +#if defined(CONFIG_RK_HDMI) && defined(CONFIG_SND_RK_SOC_HDMI_I2S) + snd_config_hdmi_audio(params); +#endif spin_unlock_irqrestore(&lock, flags); return 0; } -static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { - struct rk30_i2s_info *i2s = to_info(dai); + struct rk_i2s_dev *i2s = to_info(dai); int ret = 0; - I2S_DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -430,65 +361,61 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, int cmd, st return ret; } -/* - * Set Rockchip I2S MCLK source - */ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { - struct rk30_i2s_info *i2s = to_info(cpu_dai); + struct rk_i2s_dev *i2s = to_info(cpu_dai); + int ret; - I2S_DBG("Enter:%s, %d, i2s=0x%p, freq=%d\n", __FUNCTION__, __LINE__, i2s, freq); + ret = clk_set_rate(i2s->clk, freq); + if (ret) + dev_err(i2s->dev, "fail set clk: freq: %d\n", freq); - /*add scu clk source and enable clk*/ - clk_set_rate(i2s->i2s_clk, freq); - return 0; + return ret; } -/* - * Set Rockchip Clock dividers - */ static int rockchip_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) + int div_id, int div) { - struct rk30_i2s_info *i2s; - u32 reg; + struct rk_i2s_dev *i2s = to_info(cpu_dai); + unsigned int val = 0; unsigned long flags; - int ret = 0; - - i2s = to_info(cpu_dai); spin_lock_irqsave(&lock, flags); - //stereo mode MCLK/SCK=4 - reg = readl(&(pheadi2s->I2S_CKR)); + dev_dbg(i2s->dev, "%s: div_id=%d, div=%d\n", __func__, div_id, div); - I2S_DBG("Enter:%s, %d, div_id=0x%08X, div=0x%08X\n", __FUNCTION__, __LINE__, div_id, div); - - //when i2s in master mode ,must set codec pll div switch (div_id) { case ROCKCHIP_DIV_BCLK: - reg &= ~I2S_TX_SCLK_DIV_MASK; - reg |= I2S_TX_SCLK_DIV(div); - reg &= ~I2S_RX_SCLK_DIV_MASK; - reg |= I2S_RX_SCLK_DIV(div); + val |= I2S_CKR_TSD(div); + val |= I2S_CKR_RSD(div); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK, + val); break; case ROCKCHIP_DIV_MCLK: - reg &= ~I2S_MCLK_DIV_MASK; - reg |= I2S_MCLK_DIV(div); - break; - case ROCKCHIP_DIV_PRESCALER: + val |= I2S_CKR_MDIV(div); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_MDIV_MASK, val); break; default: - ret = -EINVAL; - goto out_; + spin_unlock_irqrestore(&lock, flags); + return -EINVAL; } - writel(reg, &(pheadi2s->I2S_CKR)); -out_: spin_unlock_irqrestore(&lock, flags); - return ret; + return 0; +} + +static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct rk_i2s_dev *i2s = to_info(dai); + + dai->capture_dma_data = &i2s->capture_dma_data; + dai->playback_dma_data = &i2s->playback_dma_data; + + return 0; } static struct snd_soc_dai_ops rockchip_i2s_dai_ops = { @@ -499,42 +426,46 @@ static struct snd_soc_dai_ops rockchip_i2s_dai_ops = { .set_sysclk = rockchip_i2s_set_sysclk, }; -#define ROCKCHIP_I2S_STEREO_RATES SNDRV_PCM_RATE_8000_192000 -#define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) +#define ROCKCHIP_I2S_RATES SNDRV_PCM_RATE_8000_192000 +#define ROCKCHIP_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FORMAT_S32_LE) struct snd_soc_dai_driver rockchip_i2s_dai[] = { { + .probe = rockchip_i2s_dai_probe, .name = "rockchip-i2s.0", .id = 0, .playback = { .channels_min = 2, .channels_max = 8, - .rates = ROCKCHIP_I2S_STEREO_RATES, + .rates = ROCKCHIP_I2S_RATES, .formats = ROCKCHIP_I2S_FORMATS, }, .capture = { .channels_min = 2, .channels_max = 2, - .rates = ROCKCHIP_I2S_STEREO_RATES, + .rates = ROCKCHIP_I2S_RATES, .formats = ROCKCHIP_I2S_FORMATS, }, .ops = &rockchip_i2s_dai_ops, .symmetric_rates = 1, }, { + .probe = rockchip_i2s_dai_probe, .name = "rockchip-i2s.1", .id = 1, .playback = { .channels_min = 2, .channels_max = 2, - .rates = ROCKCHIP_I2S_STEREO_RATES, + .rates = ROCKCHIP_I2S_RATES, .formats = ROCKCHIP_I2S_FORMATS, }, .capture = { .channels_min = 2, .channels_max = 2, - .rates = ROCKCHIP_I2S_STEREO_RATES, + .rates = ROCKCHIP_I2S_RATES, .formats = ROCKCHIP_I2S_FORMATS, }, .ops = &rockchip_i2s_dai_ops, @@ -543,54 +474,121 @@ struct snd_soc_dai_driver rockchip_i2s_dai[] = { }; static const struct snd_soc_component_driver rockchip_i2s_component = { - .name = "rockchip-i2s", + .name = "rockchip-i2s", }; #ifdef CONFIG_PM -static int rockchip_i2s_suspend_noirq(struct device *dev) +static int i2s_runtime_suspend(struct device *dev) { - I2S_DBG("Enter %s, %d\n", __func__, __LINE__); + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); + dev_dbg(i2s->dev, "%s\n", __func__); return pinctrl_pm_select_sleep_state(dev); } -static int rockchip_i2s_resume_noirq(struct device *dev) +static int i2s_runtime_resume(struct device *dev) { - I2S_DBG("Enter %s, %d\n", __func__, __LINE__); + struct rk_i2s_dev *i2s = dev_get_drvdata(dev); + dev_dbg(i2s->dev, "%s\n", __func__); return pinctrl_pm_select_default_state(dev); } #else -#define rockchip_i2s_suspend_noirq NULL -#define rockchip_i2s_resume_noirq NULL +#define i2s_runtime_suspend NULL +#define i2s_runtime_resume NULL #endif -#ifdef CLK_SET_lATER +#ifdef CLK_SET_LATER static void set_clk_later_work(struct work_struct *work) { - struct rk30_i2s_info *i2s = container_of(work, struct rk30_i2s_info, + struct rk_i2s_dev *i2s = container_of(work, struct rk_i2s_dev, clk_delayed_work.work); - clk_set_rate(i2s->i2s_clk, 11289600); - if(!IS_ERR(i2s->i2s_mclk) ) - clk_set_rate(i2s->i2s_mclk, 11289600); + clk_set_rate(i2s->clk, I2S_DEFAULT_FREQ); + if (!IS_ERR(i2s->mclk)) + clk_set_rate(i2s->mclk, I2S_DEFAULT_FREQ); } #endif +static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case I2S_TXCR: + case I2S_RXCR: + case I2S_CKR: + case I2S_DMACR: + case I2S_INTCR: + case I2S_XFER: + case I2S_CLR: + case I2S_TXDR: + return true; + default: + return false; + } +} + +static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case I2S_TXCR: + case I2S_RXCR: + case I2S_CKR: + case I2S_DMACR: + case I2S_INTCR: + case I2S_XFER: + case I2S_CLR: + case I2S_RXDR: + case I2S_FIFOLR: + case I2S_INTSR: + return true; + default: + return false; + } +} + +static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case I2S_INTSR: + case I2S_CLR: + return true; + default: + return false; + } +} + +static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + default: + return false; + } +} + +static const struct regmap_config rockchip_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = I2S_RXDR, + .writeable_reg = rockchip_i2s_wr_reg, + .readable_reg = rockchip_i2s_rd_reg, + .volatile_reg = rockchip_i2s_volatile_reg, + .precious_reg = rockchip_i2s_precious_reg, + .cache_type = REGCACHE_FLAT, +}; + static int rockchip_i2s_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; - struct rk30_i2s_info *i2s; - struct resource *mem, *memregion; - u32 regs_base; + struct rk_i2s_dev *i2s; + struct resource *res; + void __iomem *regs; int ret; - I2S_DBG("%s()\n", __FUNCTION__); - ret = of_property_read_u32(node, "i2s-id", &pdev->id); if (ret < 0) { - dev_err(&pdev->dev, "%s() Can not read property: id\n", __FUNCTION__); - ret = -ENOMEM; + dev_err(&pdev->dev, "Property 'i2s-id' missing or invalid\n"); + ret = -EINVAL; goto err; } @@ -619,101 +617,85 @@ static int rockchip_i2s_probe(struct platform_device *pdev) } } - if(pdev->id >= MAX_I2S) { - dev_err(&pdev->dev, "id %d out of range\n", pdev->id); - ret = -ENOMEM; - goto err; - } - - i2s = devm_kzalloc(&pdev->dev, sizeof(struct rk30_i2s_info), GFP_KERNEL); + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); if (!i2s) { - dev_err(&pdev->dev, "Can't allocate i2s info\n"); + dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n"); ret = -ENOMEM; goto err; } - rk30_i2s = i2s; - - i2s->i2s_hclk = clk_get(&pdev->dev, "i2s_hclk"); - if(IS_ERR(i2s->i2s_hclk) ) { - dev_err(&pdev->dev, "get i2s_hclk failed.\n"); - } else{ - clk_prepare_enable(i2s->i2s_hclk); + i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk"); + if (IS_ERR(i2s->hclk)) { + dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); + ret = PTR_ERR(i2s->hclk); + goto err; + } else { + clk_prepare_enable(i2s->hclk); } - i2s->i2s_clk= clk_get(&pdev->dev, "i2s_clk"); - if (IS_ERR(i2s->i2s_clk)) { + i2s->clk = devm_clk_get(&pdev->dev, "i2s_clk"); + if (IS_ERR(i2s->clk)) { dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); - ret = PTR_ERR(i2s->i2s_clk); + ret = PTR_ERR(i2s->clk); goto err; } -#ifdef CLK_SET_lATER +#ifdef CLK_SET_LATER INIT_DELAYED_WORK(&i2s->clk_delayed_work, set_clk_later_work); schedule_delayed_work(&i2s->clk_delayed_work, msecs_to_jiffies(10)); #else - clk_set_rate(i2s->iis_clk, 11289600); -#endif - clk_prepare_enable(i2s->i2s_clk); - - i2s->i2s_mclk= clk_get(&pdev->dev, "i2s_mclk"); - if(IS_ERR(i2s->i2s_mclk) ) { - printk("This platfrom have not i2s_mclk,no need to set i2s_mclk.\n"); - }else{ - #ifdef CLK_SET_lATER - - #else - clk_set_rate(i2s->i2s_mclk, 11289600); - #endif - clk_prepare_enable(i2s->i2s_mclk); - } + clk_set_rate(i2s->clk, I2S_DEFAULT_FREQ); +#endif + clk_prepare_enable(i2s->clk); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; + i2s->mclk = devm_clk_get(&pdev->dev, "i2s_mclk"); + if (IS_ERR(i2s->mclk)) { + dev_info(&pdev->dev, "i2s%d has no mclk\n", pdev->id); + } else { + #ifndef CLK_SET_LATER + clk_set_rate(i2s->mclk, I2S_DEFAULT_FREQ); + #endif + clk_prepare_enable(i2s->mclk); } - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), "rockchip-i2s"); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); + goto err; } - i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!i2s->regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_clk_put; + i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, + &rockchip_i2s_regmap_config); + if (IS_ERR(i2s->regmap)) { + dev_err(&pdev->dev, + "Failed to initialise managed register map\n"); + ret = PTR_ERR(i2s->regmap); + goto err; } - regs_base = mem->start; + i2s->playback_dma_data.addr = res->start + I2S_TXDR; + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->playback_dma_data.maxburst = I2S_DMA_BURST_SIZE; - i2s->playback_dma_data.addr = regs_base + I2S_TXR_BUFF; - i2s->playback_dma_data.addr_width = 4; - i2s->playback_dma_data.maxburst = 16; + i2s->capture_dma_data.addr = res->start + I2S_RXDR; + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->capture_dma_data.maxburst = I2S_DMA_BURST_SIZE; - i2s->capture_dma_data.addr = regs_base + I2S_RXR_BUFF; - i2s->capture_dma_data.addr_width = 4; - i2s->capture_dma_data.maxburst = 16; + i2s->tx_start = false; + i2s->rx_start = false; - i2s->i2s_tx_status = false; - i2s->i2s_rx_status = false; + i2s->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, i2s); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { - ret = rockchip_i2s_resume_noirq(&pdev->dev); + ret = i2s_runtime_resume(&pdev->dev); if (ret) goto err_pm_disable; } - //set dev name to driver->name.id for sound card register - dev_set_name(&pdev->dev, "%s.%d", pdev->dev.driver->name, pdev->id); - ret = snd_soc_register_component(&pdev->dev, &rockchip_i2s_component, - &rockchip_i2s_dai[pdev->id], 1); + &rockchip_i2s_dai[pdev->id], 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); @@ -727,30 +709,35 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_unregister_component; } - /* 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); - dev_set_drvdata(&pdev->dev, i2s); return 0; err_unregister_component: snd_soc_unregister_component(&pdev->dev); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) - rockchip_i2s_suspend_noirq(&pdev->dev); + i2s_runtime_suspend(&pdev->dev); err_pm_disable: pm_runtime_disable(&pdev->dev); -err_clk_put: - clk_put(i2s->i2s_clk); err: return ret; - } static int rockchip_i2s_remove(struct platform_device *pdev) { + struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + i2s_runtime_suspend(&pdev->dev); + + if (!IS_ERR(i2s->mclk)) + clk_disable_unprepare(i2s->mclk); + + clk_disable_unprepare(i2s->clk); + clk_disable_unprepare(i2s->hclk); rockchip_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); @@ -758,16 +745,16 @@ static int rockchip_i2s_remove(struct platform_device *pdev) } #ifdef CONFIG_OF -static const struct of_device_id exynos_i2s_match[] = { - { .compatible = "rockchip-i2s"}, - {}, +static const struct of_device_id rockchip_i2s_match[] = { + { .compatible = "rockchip-i2s", }, + {}, }; -MODULE_DEVICE_TABLE(of, exynos_i2s_match); +MODULE_DEVICE_TABLE(of, rockchip_i2s_match); #endif static const struct dev_pm_ops rockchip_i2s_pm_ops = { - .suspend_noirq = rockchip_i2s_suspend_noirq, - .resume_noirq = rockchip_i2s_resume_noirq, + SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, + NULL) }; static struct platform_driver rockchip_i2s_driver = { @@ -776,7 +763,7 @@ static struct platform_driver rockchip_i2s_driver = { .driver = { .name = "rockchip-i2s", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(exynos_i2s_match), + .of_match_table = of_match_ptr(rockchip_i2s_match), .pm = &rockchip_i2s_pm_ops, }, }; @@ -793,86 +780,6 @@ static void __exit rockchip_i2s_exit(void) } module_exit(rockchip_i2s_exit); -/* Module information */ -MODULE_AUTHOR("rockchip"); -MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface"); -MODULE_LICENSE("GPL"); - - -#ifdef CONFIG_PROC_FS -#include -#include -static int proc_i2s_show(struct seq_file *s, void *v) -{ - - struct rk30_i2s_info *i2s = rk30_i2s; - - printk("========Show I2S reg========\n"); - - printk("I2S_TXCR = 0x%08X\n", readl(&(pheadi2s->I2S_TXCR))); - printk("I2S_RXCR = 0x%08X\n", readl(&(pheadi2s->I2S_RXCR))); - printk("I2S_CKR = 0x%08X\n", readl(&(pheadi2s->I2S_CKR))); - printk("I2S_DMACR = 0x%08X\n", readl(&(pheadi2s->I2S_DMACR))); - printk("I2S_INTCR = 0x%08X\n", readl(&(pheadi2s->I2S_INTCR))); - printk("I2S_INTSR = 0x%08X\n", readl(&(pheadi2s->I2S_INTSR))); - printk("I2S_XFER = 0x%08X\n", readl(&(pheadi2s->I2S_XFER))); - - printk("========Show I2S reg========\n"); -#if 0 - writel(0x0000000F, &(pheadi2s->I2S_TXCR)); - writel(0x0000000F, &(pheadi2s->I2S_RXCR)); - writel(0x00071f1F, &(pheadi2s->I2S_CKR)); - writel(0x001F0110, &(pheadi2s->I2S_DMACR)); - writel(0x00000003, &(pheadi2s->I2S_XFER)); - while(1) - { - writel(0x5555aaaa, &(pheadi2s->I2S_TXDR)); - } -#endif - return 0; -} - -static ssize_t i2s_reg_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct rk30_i2s_info *i2s=rk30_i2s; - - char buf[32]; - size_t buf_size; - char *start = buf; - unsigned long value; - - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - while (*start == ' ') - start++; - value = simple_strtoul(start, &start, 10); - - printk("test --- freq = %ld ret=%d\n",value,clk_set_rate(i2s->i2s_clk, value)); - return buf_size; -} - -static int proc_i2s_open(struct inode *inode, struct file *file) -{ - return single_open(file, proc_i2s_show, NULL); -} - -static const struct file_operations proc_i2s_fops = { - .open = proc_i2s_open, - .read = seq_read, - .write = i2s_reg_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init i2s_proc_init(void) -{ - proc_create("i2s_reg", 0, NULL, &proc_i2s_fops); - return 0; -} -late_initcall(i2s_proc_init); -#endif /* CONFIG_PROC_FS */ - +MODULE_AUTHOR("Sugar "); +MODULE_DESCRIPTION("Rockchip I2S Controller Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/rockchip/rk_i2s.h b/sound/soc/rockchip/rk_i2s.h index c2bed5638920..9cec8821274a 100644 --- a/sound/soc/rockchip/rk_i2s.h +++ b/sound/soc/rockchip/rk_i2s.h @@ -1,255 +1,226 @@ /* - * rockchip-iis.h - ALSA IIS interface for the Rockchip rk28 SoC + * Rockchip I2S ALSA SoC Digital Audio Interface(DAI) driver * - * Driver for rockchip iis audio + * Copyright (C) 2015 Fuzhou Rockchip Electronics Co., Ltd + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ -#include -#ifndef _ROCKCHIP_IIS_H -#define _ROCKCHIP_IIS_H +#ifndef __RK_I2S_H__ +#define __RK_I2S_H__ + +/* + * TXCR + * transmit operation control register +*/ +#define I2S_TXCR_RCNT_SHIFT 17 +#define I2S_TXCR_RCNT_MASK (0x3f << I2S_TXCR_RCNT_SHIFT) +#define I2S_TXCR_CSR_SHIFT 15 +#define I2S_TXCR_CSR(x) (x << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CHN_2 (0 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CHN_4 (1 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CHN_6 (2 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CHN_8 (3 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_CSR_MASK (3 << I2S_TXCR_CSR_SHIFT) +#define I2S_TXCR_HWT BIT(14) +#define I2S_TXCR_SJM_SHIFT 12 +#define I2S_TXCR_SJM_R (0 << I2S_TXCR_SJM_SHIFT) +#define I2S_TXCR_SJM_L (1 << I2S_TXCR_SJM_SHIFT) +#define I2S_TXCR_FBM_SHIFT 11 +#define I2S_TXCR_FBM_MSB (0 << I2S_TXCR_FBM_SHIFT) +#define I2S_TXCR_FBM_LSB (1 << I2S_TXCR_FBM_SHIFT) +#define I2S_TXCR_IBM_SHIFT 9 +#define I2S_TXCR_IBM_NORMAL (0 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_LSJM (1 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_RSJM (2 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_IBM_MASK (3 << I2S_TXCR_IBM_SHIFT) +#define I2S_TXCR_PBM_SHIFT 7 +#define I2S_TXCR_PBM_MODE(x) (x << I2S_TXCR_PBM_SHIFT) +#define I2S_TXCR_PBM_MASK (3 << I2S_TXCR_PBM_SHIFT) +#define I2S_TXCR_TFS_SHIFT 5 +#define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT) +#define I2S_TXCR_VDW_SHIFT 0 +#define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT) +#define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT) + +/* + * RXCR + * receive operation control register +*/ +#define I2S_RXCR_HWT BIT(14) +#define I2S_RXCR_SJM_SHIFT 12 +#define I2S_RXCR_SJM_R (0 << I2S_RXCR_SJM_SHIFT) +#define I2S_RXCR_SJM_L (1 << I2S_RXCR_SJM_SHIFT) +#define I2S_RXCR_FBM_SHIFT 11 +#define I2S_RXCR_FBM_MSB (0 << I2S_RXCR_FBM_SHIFT) +#define I2S_RXCR_FBM_LSB (1 << I2S_RXCR_FBM_SHIFT) +#define I2S_RXCR_IBM_SHIFT 9 +#define I2S_RXCR_IBM_NORMAL (0 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_LSJM (1 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_RSJM (2 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_IBM_MASK (3 << I2S_RXCR_IBM_SHIFT) +#define I2S_RXCR_PBM_SHIFT 7 +#define I2S_RXCR_PBM_MODE(x) (x << I2S_RXCR_PBM_SHIFT) +#define I2S_RXCR_PBM_MASK (3 << I2S_RXCR_PBM_SHIFT) +#define I2S_RXCR_TFS_SHIFT 5 +#define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT) +#define I2S_RXCR_VDW_SHIFT 0 +#define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT) +#define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT) -//I2S_TXCR +/* + * CKR + * clock generation register +*/ +#define I2S_CKR_MSS_SHIFT 27 +#define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_MSS_SLAVE (1 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_MSS_MASK (1 << I2S_CKR_MSS_SHIFT) +#define I2S_CKR_CKP_SHIFT 26 +#define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT) +#define I2S_CKR_RLP_SHIFT 25 +#define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT) +#define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT) +#define I2S_CKR_TLP_SHIFT 24 +#define I2S_CKR_TLP_NORMAL (0 << I2S_CKR_TLP_SHIFT) +#define I2S_CKR_TLP_OPPSITE (1 << I2S_CKR_TLP_SHIFT) +#define I2S_CKR_MDIV_SHIFT 16 +#define I2S_CKR_MDIV(x) ((x) << I2S_CKR_MDIV_SHIFT) +#define I2S_CKR_MDIV_MASK (0xff << I2S_CKR_MDIV_SHIFT) +#define I2S_CKR_RSD_SHIFT 8 +#define I2S_CKR_RSD(x) ((x) << I2S_CKR_RSD_SHIFT) +#define I2S_CKR_RSD_MASK (0xff << I2S_CKR_RSD_SHIFT) +#define I2S_CKR_TSD_SHIFT 0 +#define I2S_CKR_TSD(x) ((x) << I2S_CKR_TSD_SHIFT) +#define I2S_CKR_TSD_MASK (0xff << I2S_CKR_TSD_SHIFT) -#define PCM_2DATA (0<<18) -#define PCM_4DATA (1<<18) -#define PCM_6DATA (2<<18) -#define PCM_8DATA (3<<18) +/* + * FIFOLR + * FIFO level register +*/ +#define I2S_FIFOLR_RFL_SHIFT 24 +#define I2S_FIFOLR_RFL_MASK (0x3f << I2S_FIFOLR_RFL_SHIFT) +#define I2S_FIFOLR_TFL3_SHIFT 18 +#define I2S_FIFOLR_TFL3_MASK (0x3f << I2S_FIFOLR_TFL3_SHIFT) +#define I2S_FIFOLR_TFL2_SHIFT 12 +#define I2S_FIFOLR_TFL2_MASK (0x3f << I2S_FIFOLR_TFL2_SHIFT) +#define I2S_FIFOLR_TFL1_SHIFT 6 +#define I2S_FIFOLR_TFL1_MASK (0x3f << I2S_FIFOLR_TFL1_SHIFT) +#define I2S_FIFOLR_TFL0_SHIFT 0 +#define I2S_FIFOLR_TFL0_MASK (0x3f << I2S_FIFOLR_TFL0_SHIFT) -#define CHANNEL_1_EN (0<<15) -#define CHANNEL_2_EN (1<<15) -#define CHANNEL_3_EN (2<<15) -#define CHANNLE_4_EN (3<<15) -#define TX_MODE_MASTER (0<<13) -#define TX_MODE_SLAVE (1<<13) -#define RESET_TX (1<<17) -#define RESET_RX (1<<16) -#define I2S_DMA_REQ1_DISABLE (1<<6) -#define I2S_DMA_REQ1_ENABLE (0) -#define I2S_DMA_REQ2_DISABLE (1<<5) -#define I2S_DMA_REQ2_ENABLE (0) -#define I2S_DMA_REQ1_TX_ENABLE (0) -#define I2S_DMA_REQ1_RX_ENABLE (1<<4) -#define I2S_DMA_REQ2_TX_ENABLE (0) -#define I2S_DMA_REQ2_RX_ENABLE (1<<3) -#define TX_START (1<<1) -#define RX_START (1) +/* + * DMACR + * DMA control register +*/ +#define I2S_DMACR_RDE_SHIFT 24 +#define I2S_DMACR_RDE_DISABLE (0 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDE_ENABLE (1 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDE_MASK (1 << I2S_DMACR_RDE_SHIFT) +#define I2S_DMACR_RDL_SHIFT 16 +#define I2S_DMACR_RDL(x) ((x - 1) << I2S_DMACR_RDL_SHIFT) +#define I2S_DMACR_RDL_MASK (0x1f << I2S_DMACR_RDL_SHIFT) +#define I2S_DMACR_TDE_SHIFT 8 +#define I2S_DMACR_TDE_DISABLE (0 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDE_ENABLE (1 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDE_MASK (1 << I2S_DMACR_TDE_SHIFT) +#define I2S_DMACR_TDL_SHIFT 0 +#define I2S_DMACR_TDL(x) ((x) << I2S_DMACR_TDL_SHIFT) +#define I2S_DMACR_TDL_MASK (0x1f << I2S_DMACR_TDL_SHIFT) +/* + * INTCR + * interrupt control register +*/ +#define I2S_INTCR_RFT_SHIFT 20 +#define I2S_INTCR_RFT(x) ((x - 1) << I2S_INTCR_RFT_SHIFT) +#define I2S_INTCR_RXOIC BIT(18) +#define I2S_INTCR_RXOIE_SHIFT 17 +#define I2S_INTCR_RXOIE_DISABLE (0 << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXOIE_ENABLE (1 << I2S_INTCR_RXOIE_SHIFT) +#define I2S_INTCR_RXFIE_SHIFT 16 +#define I2S_INTCR_RXFIE_DISABLE (0 << I2S_INTCR_RXFIE_SHIFT) +#define I2S_INTCR_RXFIE_ENABLE (1 << I2S_INTCR_RXFIE_SHIFT) +#define I2S_INTCR_TFT_SHIFT 4 +#define I2S_INTCR_TFT(x) ((x - 1) << I2S_INTCR_TFT_SHIFT) +#define I2S_INTCR_TFT_MASK (0x1f << I2S_INTCR_TFT_SHIFT) +#define I2S_INTCR_TXUIC BIT(2) +#define I2S_INTCR_TXUIE_SHIFT 1 +#define I2S_INTCR_TXUIE_DISABLE (0 << I2S_INTCR_TXUIE_SHIFT) +#define I2S_INTCR_TXUIE_ENABLE (1 << I2S_INTCR_TXUIE_SHIFT) +/* + * INTSR + * interrupt status register +*/ +#define I2S_INTSR_RXOI_SHIFT 17 +#define I2S_INTSR_RXOI_INA (0 << I2S_INTSR_RXOI_SHIFT) +#define I2S_INTSR_RXOI_ACT (1 << I2S_INTSR_RXOI_SHIFT) +#define I2S_INTSR_RXFI_SHIFT 16 +#define I2S_INTSR_RXFI_INA (0 << I2S_INTSR_RXFI_SHIFT) +#define I2S_INTSR_RXFI_ACT (1 << I2S_INTSR_RXFI_SHIFT) +#define I2S_INTSR_TXUI_SHIFT 1 +#define I2S_INTSR_TXUI_INA (0 << I2S_INTSR_TXUI_SHIFT) +#define I2S_INTSR_TXUI_ACT (1 << I2S_INTSR_TXUI_SHIFT) +#define I2S_INTSR_TXEI_SHIFT 0 +#define I2S_INTSR_TXEI_INA (0 << I2S_INTSR_TXEI_SHIFT) +#define I2S_INTSR_TXEI_ACT (1 << I2S_INTSR_TXEI_SHIFT) -//I2S_TXCTL I2S_RXCTL -#define CLEAR_RXFIFO (1<<24) -#define TRAN_DEVICES0 (0) -#define TRAN_DEVICES1 (1<<18) -#define TRAN_DEVICES2 (2<<18) -#define TRAN_DEVICES3 (3<<18) -#define OVERSAMPLING_RATE_32FS (0) -#define OVERSAMPLING_RATE_64FS (1<<16) -#define OVERSAMPLING_RATE_128FS (2<<16) -#define SCK_RATE2 (0x02<<8) -#define SCK_RATE4 (0x04<<8) -#define SCK_RATE8 (0x08<<8) -#define SAMPLE_DATA_8bit (0) -#define SAMPLE_DATA_16bit (1<<4) -#define SAMPLE_DATA_MASK (3<<4) -#define MONO_MODE (1<<3) -#define STEREO_MODE (0) -#define I2S_MODE (0) -#define LEFT_JUSTIFIED (1<<1) -#define RIGHT_JUSTIFIED (2<<1) -#define IISMOD_SDF_MASK (3<<1) -#define MASTER_MODE (1) -#define SLAVE_MODE (0) +/* + * XFER + * Transfer start register +*/ +#define I2S_XFER_RXS_SHIFT 1 +#define I2S_XFER_RXS_STOP (0 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_RXS_START (1 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_RXS_MASK (1 << I2S_XFER_RXS_SHIFT) +#define I2S_XFER_TXS_SHIFT 0 +#define I2S_XFER_TXS_STOP (0 << I2S_XFER_TXS_SHIFT) +#define I2S_XFER_TXS_START (1 << I2S_XFER_TXS_SHIFT) +#define I2S_XFER_TXS_MASK (1 << I2S_XFER_TXS_SHIFT) -//I2S_FIFOSTS -#define TX_HALF_FULL (1<<18) -#define RX_HALF_FULL (1<<16) +/* + * CLR + * clear SCLK domain logic register +*/ +#define I2S_CLR_RXC BIT(1) +#define I2S_CLR_RXC_MASK BIT(1) +#define I2S_CLR_TXC BIT(0) +#define I2S_CLR_TXC_MASK BIT(0) + +/* I2S REGS */ +#define I2S_TXCR (0x0000) +#define I2S_RXCR (0x0004) +#define I2S_CKR (0x0008) +#define I2S_FIFOLR (0x000c) +#define I2S_DMACR (0x0010) +#define I2S_INTCR (0x0014) +#define I2S_INTSR (0x0018) +#define I2S_XFER (0x001c) +#define I2S_CLR (0x0020) +#define I2S_TXDR (0x0024) +#define I2S_RXDR (0x0028) /* Clock dividers */ #define ROCKCHIP_DIV_MCLK 0 #define ROCKCHIP_DIV_BCLK 1 #define ROCKCHIP_DIV_PRESCALER 2 +/* channel */ +#define I2S_CHANNEL_8 8 +#define I2S_CHANNEL_6 6 +#define I2S_CHANNEL_4 4 +#define I2S_CHANNEL_2 2 -/* I2S_TXCR */ -#define I2S_RSTL_SCLK(c) ((c&0x3F)<<26) -#define I2S_RSTR_SCLK(c) ((c&0x3F)<<20) - -#define I2S_PCM_2DATA (0<<18) -#define I2S_PCM_4DATA (1<<18) -#define I2S_PCM_6DATA (2<<18) -#define I2S_PCM_8DATA (3<<18) -#define I2S_PCM_DATA_MASK (3<<18) - -#define I2S_CSR_CH2 (0<<15) -#define I2S_CSR_CH4 (1<<15) -#define I2S_CRS_CH6 (2<<15) -#define I2S_CRS_CH8 (3<<15) -#define I2S_CRS_CH_MASK (3<<15) - -#define I2S_HWT_16BIT (0<<14) -#define I2S_HWT_32BIT (1<<14) - -#ifdef CONFIG_ARCH_RK29 - #define I2S_MASTER_MODE (0<<13) - #define I2S_SLAVE_MODE (1<<13) - #define I2S_MODE_MASK (1<<13) -#endif - -#define I2S_JUSTIFIED_RIGHT (0<<12) -#define I2S_JUSTIFIED_LEFT (1<<12) - -#define I2S_FIRST_BIT_MSB (0<<11) -#define I2S_FIRST_BIT_LSB (1<<11) - -#define I2S_BUS_MODE_NOR (0<<9) -#define I2S_BUS_MODE_LSJM (1<<9) -#define I2S_BUS_MODE_RSJM (2<<9) -#define I2S_BUS_MODE_MASK (3<<9) - -#define I2S_PCM_NO_DELAY (0<<7) -#define I2S_PCM_DELAY_1MODE (1<<7) -#define I2S_PCM_DELAY_2MODE (2<<7) -#define I2S_PCM_DELAY_3MODE (3<<7) -#define I2S_PCM_DELAY_MASK (3<<7) - -#define I2S_TX_LRCK_OUT_BT_DISABLE (0<<6) -#define I2S_TX_LRCK_OUT_BT_ENABLE (1<<6) - -#define I2S_TX_LRCK_OUT_I2S (0<<5) -#define I2S_TX_LRCK_OUT_PCM (1<<5) - -#define I2S_DATA_WIDTH(w) ((w&0x1F)<<0) - -/* */ - - -/* I2S_TXCKR */ -#ifdef CONFIG_ARCH_RK29 - #define I2S_TSP_POSEDGE (0<<25) - #define I2S_TSP_NEGEDGE (1<<25) - #define I2S_TLP_NORMAL (0<<24) - #define I2S_TLP_OPPSITE (1<<24) - - #define I2S_MCLK_DIV(x) ((0xFF&x)<<16) - #define I2S_MCLK_DIV_MASK ((0xFF)<<16) - - #define I2S_TSD_FIXED (0<<12) - #define I2S_TSD_CHANGED (1<<12) - - #define I2S_TX_LRCK_NO_DELAY (0<<10) - #define I2S_TX_LRCK_DELAY_ONE (1<<10) - #define I2S_TX_LRCK_DELAY_TWO (2<<10) - #define I2S_TX_LRCK_DELAY_THREE (3<<10) - #define I2S_TX_LRCK_DELAY_MASK (3<<10) - - #define I2S_TX_SCLK_DIV(x) (x&0x3FF) - #define I2S_TX_SCLK_DIV_MASK (0x3FF); -#else -//I2S_CKR - #define I2S_MASTER_MODE (0<<27) - #define I2S_SLAVE_MODE (1<<27) - #define I2S_MODE_MASK (1<<27) - - #define I2S_BCLK_POSEDGE (0<<26)//sclk polarity invert?? - #define I2S_BCLK_NEGEDGE (1<<26) - - #define I2S_RX_LRCK_POSEDGE (0<<25)//LRCK polarity invert?? - #define I2S_RX_LRCK_NEGEDGE (1<<25) - - #define I2S_TX_LRCK_POSEDGE (0<<24) - #define I2S_TX_LRCK_NEGEDGE (1<<24) - - #define I2S_MCLK_DIV(x) ((0xFF&x)<<16) - #define I2S_MCLK_DIV_MASK ((0xFF)<<16) - - #define I2S_RX_SCLK_DIV(x) ((x&0xFF)<<8) - #define I2S_RX_SCLK_DIV_MASK ((0xFF)<<8) - - #define I2S_TX_SCLK_DIV(x) (x&0xFF) - #define I2S_TX_SCLK_DIV_MASK (0xFF) -#endif - -/* I2S_DMACR */ -#define I2S_RECE_DMA_DISABLE (0<<24) -#define I2S_RECE_DMA_ENABLE (1<<24) -#define I2S_DMARDL(x) ((x&0x1f)<<16) - -#define I2S_TRAN_DMA_DISABLE (0<<8) -#define I2S_TRAN_DMA_ENABLE (1<<8) -#define I2S_DMATDL(x) ((x&0x1f)<<0) - -/* I2S_INTCR */ -#define I2S_RXOV_INT_DISABLE (0<<17) -#define I2S_RXOV_INT_ENABLE (1<<17) -#define I2S_RXFU_INT_DISABLE (0<<16) -#define I2S_RXFU_INT_ENABLE (1<<16) - -#define I2S_TXUND_INT_DISABLE (0<<1) -#define I2S_TXUND_INT_ENABLE (1<<1) -#define I2S_TXEMP_INT_DISABLE (0<<0) -#define I2S_TXEMP_INT_ENABLE (1<<0) - -/* I2S_XFER */ -#define I2S_RX_TRAN_STOP (0<<1) -#define I2S_RX_TRAN_START (1<<1) -#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 -//I2S Registers -typedef volatile struct tagIIS_STRUCT -{ - unsigned int I2S_TXCR; - unsigned int I2S_RXCR; - unsigned int I2S_TXCKR; - unsigned int I2S_RXCKR; - unsigned int I2S_FIFOLR; - unsigned int I2S_DMACR; - unsigned int I2S_INTCR; - unsigned int I2S_INTSR; - unsigned int I2S_TXDR; - unsigned int I2S_RXDR; - unsigned int I2S_XFER; - unsigned int I2S_TXRST; - unsigned int I2S_RXRST; -}I2S_REG,*pI2S_REG; -#else -#define I2S_TXR_BUFF 0x24 -#define I2S_RXR_BUFF 0x28 -typedef volatile struct tagIIS_STRUCT -{ - unsigned int I2S_TXCR;//0xF 0 - unsigned int I2S_RXCR;//0xF 4 - unsigned int I2S_CKR;//0x3F 8 - unsigned int I2S_FIFOLR;//c - unsigned int I2S_DMACR;//0x001F0110 10 - unsigned int I2S_INTCR;//0x01F00000 14 - unsigned int I2S_INTSR;//0x00 18 - unsigned int I2S_XFER;//0x00000003 1c - unsigned int I2S_CLR;//20 - unsigned int I2S_TXDR;//24 - unsigned int I2S_RXDR; -}I2S_REG,*pI2S_REG; -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)) -extern struct snd_soc_dai_driver rk29_i2s_dai[]; -#else -extern struct snd_soc_dai rk29_i2s_dai[]; -#endif - -#ifdef CONFIG_SND_SOC_RT5631 -extern struct delayed_work rt5631_delay_cap; //bard 7-16 -#endif - -#endif /* _ROCKCHIP_IIS_H */ +#endif /* __RK_I2S_H__ */