summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShengjiu Wang <b02247@freescale.com>2013-08-12 14:12:36 +0800
committerJason Liu <r64343@freescale.com>2013-10-30 09:54:37 +0800
commitb596015e75a79ff4ebfd513acf20b9735acb17f6 (patch)
tree3c79ca70517f3e65fa5ef7fbf877970fd52eb412
parentf2ac678211d5ec3966b33aa82ea59e965fa31379 (diff)
ENGR00274585-4 ASoC: fsl: add esai driver
add esai driver. add bindings documentation of esai Signed-off-by: Shengjiu Wang <b02247@freescale.com>
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-easi.txt26
-rw-r--r--sound/soc/fsl/Kconfig3
-rw-r--r--sound/soc/fsl/Makefile4
-rw-r--r--sound/soc/fsl/fsl_esai.c700
-rw-r--r--sound/soc/fsl/fsl_esai.h334
5 files changed, 1066 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl-easi.txt b/Documentation/devicetree/bindings/sound/fsl-easi.txt
new file mode 100644
index 000000000000..b6196622accd
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/fsl-easi.txt
@@ -0,0 +1,26 @@
+* Freescale Enhanced Serial Audio Interface (ESAI)
+
+Required properties:
+ - compatible: Should be "fsl,<chip>-esai".
+ - reg: Offset and length of the register set for the device.
+ - interrupts: Contains ESAI interrupt.
+ - clocks: Contains an entry for each entry in clock-names.
+ - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
+ This number is the maximum allowed value for TFCR[TFWM].
+ - fsl,esai-dma-events: The dma event of the esai, <a b>, a is the tx dma.
+ b is the rx dma.
+ - fsl,flags: <1> is for ESAI network mode, <2> is for ESAI SYNC mode.
+ <3> is for network and SYNC mode.
+
+Example:
+
+esai: esai@02024000 {
+ compatible = "fsl,imx6q-esai";
+ reg = <0x02024000 0x4000>;
+ interrupts = <0 51 0x04>;
+ clocks = <&clks 118>;
+ fsl,fifo-depth = <128>;
+ fsl,esai-dma-events = <24 23>;
+ fsl,flags = <1>;
+ status = "disabled";
+};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 50077f6fb0d7..bb60c367928e 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -4,6 +4,9 @@ config SND_SOC_FSL_SSI
config SND_SOC_FSL_ASRC
tristate
+config SND_SOC_FSL_ESAI
+ tristate
+
config SND_SOC_FSL_UTILS
tristate
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 5ae538040036..d5250d8f3d85 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -10,15 +10,17 @@ obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
snd-soc-p1022-rdk-objs := p1022_rdk.o
obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
-# Freescale PowerPC SSI/DMA/ASRC Platform Support
+# Freescale PowerPC SSI/DMA/ASRC/ESAI Platform Support
snd-soc-fsl-ssi-objs := fsl_ssi.o
snd-soc-fsl-asrc-pcm-objs := fsl_asrc_pcm.o
snd-soc-fsl-asrc-objs := fsl_asrc.o
+snd-soc-fsl-esai-objs := fsl_esai.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc-pcm.o
obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o
+obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644
index 000000000000..f2687ef1ffb5
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.c
@@ -0,0 +1,700 @@
+/*
+ * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+ /*!
+ * @file fsl-esai.c
+ * @brief this file implements the esai interface
+ * in according to ASoC architeture
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "fsl_esai.h"
+#include "imx-pcm.h"
+
+#define IMX_ESAI_NET (1 << 0)
+#define IMX_ESAI_SYN (1 << 1)
+
+static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 ecr, tccr, rccr;
+
+ ecr = readl(esai->base + ESAI_ECR);
+ tccr = readl(esai->base + ESAI_TCCR);
+ rccr = readl(esai->base + ESAI_RCCR);
+
+ if (dir == SND_SOC_CLOCK_IN) {
+ tccr &= ~(ESAI_TCCR_THCKD | ESAI_TCCR_TCKD | ESAI_TCCR_TFSD);
+ rccr &= ~(ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD);
+ } else {
+ tccr |= ESAI_TCCR_THCKD | ESAI_TCCR_TCKD | ESAI_TCCR_TFSD;
+ rccr |= ESAI_RCCR_RHCKD | ESAI_RCCR_RCKD | ESAI_RCCR_RFSD;
+
+ if (clk_id == ESAI_CLK_FSYS) {
+ ecr &= ~(ESAI_ECR_ETI | ESAI_ECR_ETO);
+ ecr &= ~(ESAI_ECR_ERI | ESAI_ECR_ERO);
+ } else if (clk_id == ESAI_CLK_EXTAL) {
+ ecr |= ESAI_ECR_ETI;
+ ecr |= ESAI_ECR_ETO;
+ ecr |= ESAI_ECR_ERI;
+ ecr |= ESAI_ECR_ERO;
+ } else if (clk_id == ESAI_CLK_EXTAL_DIV) {
+ ecr |= ESAI_ECR_ETI;
+ ecr &= ~ESAI_ECR_ETO;
+ ecr |= ESAI_ECR_ERI;
+ ecr &= ~ESAI_ECR_ERO;
+ }
+ }
+
+ writel(ecr, esai->base + ESAI_ECR);
+ writel(tccr, esai->base + ESAI_TCCR);
+ writel(rccr, esai->base + ESAI_RCCR);
+
+ ESAI_DUMP();
+ return 0;
+}
+
+static int fsl_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 tccr, rccr;
+
+ tccr = readl(esai->base + ESAI_TCCR);
+ rccr = readl(esai->base + ESAI_RCCR);
+
+ switch (div_id) {
+ case ESAI_TX_DIV_PSR:
+ if ((div << ESAI_TCCR_TPSR_SHIFT) & ESAI_TCCR_TPSR_MASK)
+ return -EINVAL;
+ tccr &= ESAI_TCCR_TPSR_MASK;
+ if (div)
+ tccr |= ESAI_TCCR_TPSR_BYPASS;
+ else
+ tccr &= ~ESAI_TCCR_TPSR_DIV8;
+ break;
+ case ESAI_TX_DIV_PM:
+ if ((div << ESAI_TCCR_TPM_SHIFT) & ESAI_TCCR_TPM_MASK)
+ return -EINVAL;
+ tccr &= ESAI_TCCR_TPM_MASK;
+ tccr |= ESAI_TCCR_TPM(div);
+ break;
+ case ESAI_TX_DIV_FP:
+ if ((div << ESAI_TCCR_TFP_SHIFT) & ESAI_TCCR_TFP_MASK)
+ return -EINVAL;
+ tccr &= ESAI_TCCR_TFP_MASK;
+ tccr |= ESAI_TCCR_TFP(div);
+ break;
+ case ESAI_RX_DIV_PSR:
+ if ((div << ESAI_RCCR_RPSR_SHIFT) & ESAI_RCCR_RPSR_MASK)
+ return -EINVAL;
+ rccr &= ESAI_RCCR_RPSR_MASK;
+ if (div)
+ rccr |= ESAI_RCCR_RPSR_BYPASS;
+ else
+ rccr &= ~ESAI_RCCR_RPSR_DIV8;
+ break;
+ case ESAI_RX_DIV_PM:
+ if ((div << ESAI_RCCR_RPM_SHIFT) & ESAI_RCCR_RPM_MASK)
+ return -EINVAL;
+ rccr &= ESAI_RCCR_RPM_MASK;
+ rccr |= ESAI_RCCR_RPM(div);
+ break;
+ case ESAI_RX_DIV_FP:
+ if ((div << ESAI_RCCR_RFP_SHIFT) & ESAI_RCCR_RFP_MASK)
+ return -EINVAL;
+ rccr &= ESAI_RCCR_RFP_MASK;
+ rccr |= ESAI_RCCR_RFP(div);
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(tccr, esai->base + ESAI_TCCR);
+ writel(rccr, esai->base + ESAI_RCCR);
+ return 0;
+}
+
+/*
+ * ESAI Network Mode or TDM slots configuration.
+ */
+static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 tccr, rccr;
+
+ tccr = readl(esai->base + ESAI_TCCR);
+
+ tccr &= ESAI_TCCR_TDC_MASK;
+ tccr |= ESAI_TCCR_TDC(slots - 1);
+
+ writel(tccr, esai->base + ESAI_TCCR);
+ writel((tx_mask & 0xffff), esai->base + ESAI_TSMA);
+ writel(((tx_mask >> 16) & 0xffff), esai->base + ESAI_TSMB);
+
+ rccr = readl(esai->base + ESAI_RCCR);
+
+ rccr &= ESAI_RCCR_RDC_MASK;
+ rccr |= ESAI_RCCR_RDC(slots - 1);
+
+ writel(rccr, esai->base + ESAI_RCCR);
+ writel((rx_mask & 0xffff), esai->base + ESAI_RSMA);
+ writel(((rx_mask >> 16) & 0xffff), esai->base + ESAI_RSMB);
+
+ ESAI_DUMP();
+ return 0;
+}
+
+/*
+ * ESAI DAI format configuration.
+ */
+static int fsl_esai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 tcr, tccr, rcr, rccr, saicr;
+
+ tcr = readl(esai->base + ESAI_TCR);
+ tccr = readl(esai->base + ESAI_TCCR);
+ rcr = readl(esai->base + ESAI_RCR);
+ rccr = readl(esai->base + ESAI_RCCR);
+ saicr = readl(esai->base + ESAI_SAICR);
+
+ /* DAI mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* data on rising edge of bclk, frame low 1clk before data */
+ tcr &= ~ESAI_TCR_TFSL;
+ tcr |= ESAI_TCR_TFSR;
+ rcr &= ~ESAI_RCR_RFSL;
+ rcr |= ESAI_RCR_RFSR;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* data on rising edge of bclk, frame high with data */
+ tcr &= ~(ESAI_TCR_TFSL | ESAI_TCR_TFSR);
+ rcr &= ~(ESAI_RCR_RFSL | ESAI_RCR_RFSR);
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ /* data on rising edge of bclk, frame high with data */
+ tcr |= ESAI_TCR_TFSL;
+ rcr |= ESAI_RCR_RFSL;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ /* data on rising edge of bclk, frame high 1clk before data */
+ tcr |= ESAI_TCR_TFSL;
+ rcr |= ESAI_RCR_RFSL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_IF:
+ tccr |= ESAI_TCCR_TFSP;
+ tccr &= ~(ESAI_TCCR_TCKP | ESAI_TCCR_THCKP);
+ rccr &= ~(ESAI_RCCR_RCKP | ESAI_RCCR_RHCKP);
+ rccr |= ESAI_RCCR_RFSP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ tccr &= ~(ESAI_TCCR_TCKP | ESAI_TCCR_THCKP | ESAI_TCCR_TFSP);
+ rccr &= ~(ESAI_RCCR_RCKP | ESAI_RCCR_RHCKP | ESAI_RCCR_RFSP);
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ tccr |= ESAI_TCCR_TCKP | ESAI_TCCR_THCKP | ESAI_TCCR_TFSP;
+ rccr |= ESAI_RCCR_RCKP | ESAI_RCCR_RHCKP | ESAI_RCCR_RFSP;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ tccr &= ~ESAI_TCCR_TFSP;
+ tccr |= ESAI_TCCR_TCKP | ESAI_TCCR_THCKP;
+ rccr &= ~ESAI_RCCR_RFSP;
+ rccr |= ESAI_RCCR_RCKP | ESAI_RCCR_RHCKP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ tccr &= ~(ESAI_TCCR_TFSD | ESAI_TCCR_TCKD);
+ rccr &= ~(ESAI_RCCR_RFSD | ESAI_RCCR_RCKD);
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ tccr &= ~ESAI_TCCR_TFSD;
+ tccr |= ESAI_TCCR_TCKD;
+ rccr &= ~ESAI_RCCR_RFSD;
+ rccr |= ESAI_RCCR_RCKD;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ tccr &= ~ESAI_TCCR_TCKD;
+ tccr |= ESAI_TCCR_TFSD;
+ rccr &= ~ESAI_RCCR_RCKD;
+ rccr |= ESAI_RCCR_RFSD;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ tccr |= (ESAI_TCCR_TFSD | ESAI_TCCR_TCKD);
+ rccr |= (ESAI_RCCR_RFSD | ESAI_RCCR_RCKD);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* sync */
+ if (esai->flags & IMX_ESAI_SYN)
+ saicr |= ESAI_SAICR_SYNC;
+ else
+ saicr &= ~ESAI_SAICR_SYNC;
+
+ tcr &= ESAI_TCR_TMOD_MASK;
+ rcr &= ESAI_RCR_RMOD_MASK;
+ if (esai->flags & IMX_ESAI_NET) {
+ tcr |= ESAI_TCR_TMOD_NETWORK;
+ rcr |= ESAI_RCR_RMOD_NETWORK;
+ } else {
+ tcr |= ESAI_TCR_TMOD_NORMAL;
+ rcr |= ESAI_RCR_RMOD_NORMAL;
+ }
+
+ writel(tcr, esai->base + ESAI_TCR);
+ writel(tccr, esai->base + ESAI_TCCR);
+ writel(rcr, esai->base + ESAI_RCR);
+ writel(rccr, esai->base + ESAI_RCCR);
+
+ writel(saicr, esai->base + ESAI_SAICR);
+
+ ESAI_DUMP();
+ return 0;
+}
+
+static int fsl_esai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ clk_enable(esai->clk);
+ if (!cpu_dai->active) {
+ writel(ESAI_GPIO_ESAI, esai->base + ESAI_PRRC);
+ writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC);
+ }
+ ESAI_DUMP();
+ return 0;
+}
+
+/*
+ * This function is called to initialize the TX port before enable
+ * the tx port.
+ */
+static int fsl_esai_hw_tx_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 tcr, tfcr;
+ unsigned int channels;
+
+ tcr = readl(esai->base + ESAI_TCR);
+ tfcr = readl(esai->base + ESAI_TFCR);
+
+ tfcr |= ESAI_TFCR_TFR;
+ writel(tfcr, esai->base + ESAI_TFCR);
+ tfcr &= ~ESAI_TFCR_TFR;
+ /* DAI data (word) size */
+ tfcr &= ESAI_TFCR_TWA_MASK;
+ tcr &= ESAI_TCR_TSWS_MASK;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ tfcr |= ESAI_WORD_LEN_16;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ tfcr |= ESAI_WORD_LEN_20;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ tfcr |= ESAI_WORD_LEN_24;
+ tcr |= ESAI_TCR_TSHFD_MSB | ESAI_TCR_TSWS_STL32_WDL24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ channels = params_channels(params);
+ tfcr &= ESAI_TFCR_TE_MASK;
+ tfcr |= ESAI_TFCR_TE(channels);
+
+ tfcr |= ESAI_TFCR_TFWM(esai->fifo_depth);
+
+ /* Left aligned, Zero padding */
+ tcr |= ESAI_TCR_PADC;
+ /* TDR initialized from the FIFO */
+ tfcr |= ESAI_TFCR_TIEN;
+
+ writel(tcr, esai->base + ESAI_TCR);
+ writel(tfcr, esai->base + ESAI_TFCR);
+
+ ESAI_DUMP();
+ return 0;
+}
+
+/*
+ * This function is called to initialize the RX port before enable
+ * the rx port.
+ */
+static int fsl_esai_hw_rx_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 rcr, rfcr;
+ unsigned int channels;
+
+ rcr = readl(esai->base + ESAI_RCR);
+ rfcr = readl(esai->base + ESAI_RFCR);
+
+ rfcr |= ESAI_RFCR_RFR;
+ writel(rfcr, esai->base + ESAI_RFCR);
+ rfcr &= ~ESAI_RFCR_RFR;
+
+ rfcr &= ESAI_RFCR_RWA_MASK;
+ rcr &= ESAI_RCR_RSWS_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ rfcr |= ESAI_WORD_LEN_16;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL16;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ rfcr |= ESAI_WORD_LEN_20;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ rfcr |= ESAI_WORD_LEN_24;
+ rcr |= ESAI_RCR_RSHFD_MSB | ESAI_RCR_RSWS_STL32_WDL24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ channels = params_channels(params);
+ rfcr &= ESAI_RFCR_RE_MASK;
+ rfcr |= ESAI_RFCR_RE(channels);
+
+ rfcr |= ESAI_RFCR_RFWM(esai->fifo_depth);
+
+ writel(rcr, esai->base + ESAI_RCR);
+ writel(rfcr, esai->base + ESAI_RFCR);
+
+ ESAI_DUMP();
+ return 0;
+}
+
+/*
+ * This function is called to initialize the TX or RX port,
+ */
+static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ /* Tx/Rx config */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ if (readl(esai->base + ESAI_TCR) & ESAI_TCR_TE0)
+ return 0;
+
+ return fsl_esai_hw_tx_params(substream, params, cpu_dai);
+ } else {
+ if (readl(esai->base + ESAI_RCR) & ESAI_RCR_RE1)
+ return 0;
+
+ return fsl_esai_hw_rx_params(substream, params, cpu_dai);
+ }
+}
+
+static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+
+ clk_disable(esai->clk);
+}
+
+static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 reg, tfcr = 0, rfcr = 0;
+ int i;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tfcr = readl(esai->base + ESAI_TFCR);
+ reg = readl(esai->base + ESAI_TCR);
+ } else {
+ rfcr = readl(esai->base + ESAI_RFCR);
+ reg = readl(esai->base + ESAI_RCR);
+ }
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tfcr |= ESAI_TFCR_TFEN;
+ writel(tfcr, esai->base + ESAI_TFCR);
+ /* write initial words to ETDR register */
+ for (i = 0; i < substream->runtime->channels; i++)
+ writel(0x0, esai->base + ESAI_ETDR);
+ reg |= ESAI_TCR_TE(substream->runtime->channels);
+ writel(reg, esai->base + ESAI_TCR);
+ } else {
+ rfcr |= ESAI_RFCR_RFEN;
+ writel(rfcr, esai->base + ESAI_RFCR);
+ reg |= ESAI_RCR_RE(substream->runtime->channels);
+ writel(reg, esai->base + ESAI_RCR);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ reg &= ~ESAI_TCR_TE(substream->runtime->channels);
+ writel(reg, esai->base + ESAI_TCR);
+ tfcr |= ESAI_TFCR_TFR;
+ tfcr &= ~ESAI_TFCR_TFEN;
+ writel(tfcr, esai->base + ESAI_TFCR);
+ tfcr &= ~ESAI_TFCR_TFR;
+ writel(tfcr, esai->base + ESAI_TFCR);
+ } else {
+ reg &= ~ESAI_RCR_RE(substream->runtime->channels);
+ writel(reg, esai->base + ESAI_RCR);
+ rfcr |= ESAI_RFCR_RFR;
+ rfcr &= ~ESAI_RFCR_RFEN;
+ writel(rfcr, esai->base + ESAI_RFCR);
+ rfcr &= ~ESAI_RFCR_RFR;
+ writel(rfcr, esai->base + ESAI_RFCR);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ESAI_DUMP();
+ return 0;
+}
+
+#define IMX_ESAI_RATES SNDRV_PCM_RATE_8000_192000
+
+#define IMX_ESAI_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops fsl_esai_dai_ops = {
+ .startup = fsl_esai_startup,
+ .shutdown = fsl_esai_shutdown,
+ .trigger = fsl_esai_trigger,
+ .hw_params = fsl_esai_hw_params,
+ .set_sysclk = fsl_esai_set_dai_sysclk,
+ .set_clkdiv = fsl_esai_set_dai_clkdiv,
+ .set_fmt = fsl_esai_set_dai_fmt,
+ .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
+};
+
+static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
+{
+ struct fsl_esai *esai = snd_soc_dai_get_drvdata(dai);
+
+ dai->playback_dma_data = &esai->dma_params_tx;
+ dai->capture_dma_data = &esai->dma_params_rx;
+ return 0;
+}
+
+static struct snd_soc_dai_driver fsl_esai_dai = {
+ .probe = fsl_esai_dai_probe,
+ .playback = {
+ .stream_name = "esai-Playback",
+ .channels_min = 1,
+ .channels_max = 12,
+ .rates = IMX_ESAI_RATES,
+ .formats = IMX_ESAI_FORMATS,
+ },
+ .capture = {
+ .stream_name = "esai-Capture",
+ .channels_min = 1,
+ .channels_max = 8,
+ .rates = IMX_ESAI_RATES,
+ .formats = IMX_ESAI_FORMATS,
+ },
+ .ops = &fsl_esai_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_esai_component = {
+ .name = "fsl-esai",
+};
+
+static int fsl_esai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource res;
+ struct fsl_esai *esai;
+ const uint32_t *iprop;
+ uint32_t flag;
+ const char *p;
+ u32 dma_events[2];
+ int ret = 0;
+
+ esai = devm_kzalloc(&pdev->dev, sizeof(*esai), GFP_KERNEL);
+ if (!esai) {
+ dev_err(&pdev->dev, "mem allocation failed\n");
+ return -ENOMEM;
+ }
+
+ ret = of_property_read_u32(np, "fsl,flags", &flag);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "There is no flag for esai\n");
+ return -EINVAL;
+ }
+ esai->flags = flag;
+
+ esai->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(esai->clk)) {
+ ret = PTR_ERR(esai->clk);
+ dev_err(&pdev->dev, "Cannot get the clock: %d\n", ret);
+ return ret;
+ }
+ clk_prepare(esai->clk);
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ dev_err(&pdev->dev, "could not determine device resources\n");
+ goto failed_get_resource;
+ }
+
+ esai->base = of_iomap(np, 0);
+ if (!esai->base) {
+ dev_err(&pdev->dev, "could not map device resources\n");
+ ret = -ENOMEM;
+ goto failed_iomap;
+ }
+
+ esai->irq = irq_of_parse_and_map(np, 0);
+
+ /* Determine the FIFO depth. */
+ iprop = of_get_property(np, "fsl,fifo-depth", NULL);
+ if (iprop)
+ esai->fifo_depth = be32_to_cpup(iprop);
+ else
+ esai->fifo_depth = 64;
+
+ esai->dma_params_tx.maxburst = 16;
+ esai->dma_params_rx.maxburst = 16;
+
+ esai->dma_params_tx.addr = res.start + ESAI_ETDR;
+ esai->dma_params_rx.addr = res.start + ESAI_ERDR;
+
+ esai->dma_params_tx.filter_data = &esai->filter_data_tx;
+ esai->dma_params_rx.filter_data = &esai->filter_data_rx;
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "fsl,esai-dma-events", dma_events, 2);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get dma events\n");
+ goto failed_get_dma;
+ }
+
+ esai->filter_data_tx.dma_request0 = dma_events[0];
+ esai->filter_data_rx.dma_request0 = dma_events[1];
+ esai->filter_data_tx.peripheral_type = IMX_DMATYPE_ESAI;
+ esai->filter_data_rx.peripheral_type = IMX_DMATYPE_ESAI;
+
+ platform_set_drvdata(pdev, esai);
+
+ p = strrchr(np->full_name, '/') + 1;
+ strcpy(esai->name, p);
+ fsl_esai_dai.name = esai->name;
+
+ ret = snd_soc_register_component(&pdev->dev, &fsl_esai_component,
+ &fsl_esai_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "register DAI failed\n");
+ goto failed_register;
+ }
+
+ ret = imx_pcm_dma_init(pdev, SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
+ SND_DMAENGINE_PCM_FLAG_NO_DT |
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
+ if (ret) {
+ dev_err(&pdev->dev, "init pcm dma failed\n");
+ goto failed_pcm_init;
+ }
+
+ writel(ESAI_ECR_ERST, esai->base + ESAI_ECR);
+ writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR);
+ return 0;
+
+failed_pcm_init:
+ snd_soc_unregister_component(&pdev->dev);
+failed_register:
+failed_get_dma:
+ irq_dispose_mapping(esai->irq);
+ iounmap(esai->base);
+failed_iomap:
+failed_get_resource:
+ clk_unprepare(esai->clk);
+ return ret;
+}
+
+static int fsl_esai_remove(struct platform_device *pdev)
+{
+ struct fsl_esai *esai = platform_get_drvdata(pdev);
+
+ imx_pcm_dma_exit(pdev);
+ snd_soc_unregister_component(&pdev->dev);
+
+ irq_dispose_mapping(esai->irq);
+ iounmap(esai->base);
+ clk_unprepare(esai->clk);
+ return 0;
+}
+
+static const struct of_device_id fsl_esai_ids[] = {
+ { .compatible = "fsl,imx6q-esai", },
+ {}
+};
+
+static struct platform_driver fsl_esai_driver = {
+ .probe = fsl_esai_probe,
+ .remove = fsl_esai_remove,
+ .driver = {
+ .name = "fsl-esai-dai",
+ .owner = THIS_MODULE,
+ .of_match_table = fsl_esai_ids,
+ },
+};
+
+module_platform_driver(fsl_esai_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX ASoC ESAI driver");
+MODULE_ALIAS("platform:fsl-esai-dai");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644
index 000000000000..32ff624af860
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.h
@@ -0,0 +1,334 @@
+/*
+ * imx-esai.h -- ESAI driver header file for Freescale IMX
+ *
+ * Copyright 2008-2013 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _MXC_ESAI_H
+#define _MXC_ESAI_H
+
+#ifdef IMX_ESAI_DUMP
+#define ESAI_DUMP() \
+ do {pr_info("dump @ %s\n", __func__); \
+ pr_info("ESAI_ECR 0x%08x\n", readl(esai->base + ESAI_ECR)); \
+ pr_info("ESAI_ESR 0x%08x\n", readl(esai->base + ESAI_ESR)); \
+ pr_info("ESAI_TFCR 0x%08x\n", readl(esai->base + ESAI_TFCR)); \
+ pr_info("ESAI_TFSR 0x%08x\n", readl(esai->base + ESAI_TFSR)); \
+ pr_info("ESAI_RFCR 0x%08x\n", readl(esai->base + ESAI_RFCR)); \
+ pr_info("ESAI_RFSR 0x%08x\n", readl(esai->base + ESAI_RFSR)); \
+ pr_info("ESAI_TSR 0x%08x\n", readl(esai->base + ESAI_TSR)); \
+ pr_info("ESAI_SAISR 0x%08x\n", readl(esai->base + ESAI_SAISR)); \
+ pr_info("ESAI_SAICR 0x%08x\n", readl(esai->base + ESAI_SAICR)); \
+ pr_info("ESAI_TCR 0x%08x\n", readl(esai->base + ESAI_TCR)); \
+ pr_info("ESAI_TCCR 0x%08x\n", readl(esai->base + ESAI_TCCR)); \
+ pr_info("ESAI_RCR 0x%08x\n", readl(esai->base + ESAI_RCR)); \
+ pr_info("ESAI_RCCR 0x%08x\n", readl(esai->base + ESAI_RCCR)); \
+ pr_info("ESAI_TSMA 0x%08x\n", readl(esai->base + ESAI_TSMA)); \
+ pr_info("ESAI_TSMB 0x%08x\n", readl(esai->base + ESAI_TSMB)); \
+ pr_info("ESAI_RSMA 0x%08x\n", readl(esai->base + ESAI_RSMA)); \
+ pr_info("ESAI_RSMB 0x%08x\n", readl(esai->base + ESAI_RSMB)); \
+ pr_info("ESAI_PRRC 0x%08x\n", readl(esai->base + ESAI_PRRC)); \
+ pr_info("ESAI_PCRC 0x%08x\n", readl(esai->base + ESAI_PCRC)); \
+ } while (0);
+#else
+#define ESAI_DUMP()
+#endif
+
+#define ESAI_ETDR 0x00
+#define ESAI_ERDR 0x04
+#define ESAI_ECR 0x08
+#define ESAI_ESR 0x0C
+#define ESAI_TFCR 0x10
+#define ESAI_TFSR 0x14
+#define ESAI_RFCR 0x18
+#define ESAI_RFSR 0x1C
+#define ESAI_TX0 0x80
+#define ESAI_TX1 0x84
+#define ESAI_TX2 0x88
+#define ESAI_TX3 0x8C
+#define ESAI_TX4 0x90
+#define ESAI_TX5 0x94
+#define ESAI_TSR 0x98
+#define ESAI_RX0 0xA0
+#define ESAI_RX1 0xA4
+#define ESAI_RX2 0xA8
+#define ESAI_RX3 0xAC
+#define ESAI_SAISR 0xCC
+#define ESAI_SAICR 0xD0
+#define ESAI_TCR 0xD4
+#define ESAI_TCCR 0xD8
+#define ESAI_RCR 0xDC
+#define ESAI_RCCR 0xE0
+#define ESAI_TSMA 0xE4
+#define ESAI_TSMB 0xE8
+#define ESAI_RSMA 0xEC
+#define ESAI_RSMB 0xF0
+#define ESAI_PRRC 0xF8
+#define ESAI_PCRC 0xFC
+
+#define ESAI_ECR_ETI (1 << 19)
+#define ESAI_ECR_ETO (1 << 18)
+#define ESAI_ECR_ERI (1 << 17)
+#define ESAI_ECR_ERO (1 << 16)
+#define ESAI_ECR_ERST (1 << 1)
+#define ESAI_ECR_ESAIEN (1 << 0)
+
+#define ESAI_ESR_TINIT (1 << 10)
+#define ESAI_ESR_RFF (1 << 9)
+#define ESAI_ESR_TFE (1 << 8)
+#define ESAI_ESR_TLS (1 << 7)
+#define ESAI_ESR_TDE (1 << 6)
+#define ESAI_ESR_TED (1 << 5)
+#define ESAI_ESR_TD (1 << 4)
+#define ESAI_ESR_RLS (1 << 3)
+#define ESAI_ESR_RDE (1 << 2)
+#define ESAI_ESR_RED (1 << 1)
+#define ESAI_ESR_RD (1 << 0)
+
+#define ESAI_TFCR_TIEN (1 << 19)
+#define ESAI_TFCR_TE5 (1 << 7)
+#define ESAI_TFCR_TE4 (1 << 6)
+#define ESAI_TFCR_TE3 (1 << 5)
+#define ESAI_TFCR_TE2 (1 << 4)
+#define ESAI_TFCR_TE1 (1 << 3)
+#define ESAI_TFCR_TE0 (1 << 2)
+#define ESAI_TFCR_TFR (1 << 1)
+#define ESAI_TFCR_TFEN (1 << 0)
+#define ESAI_TFCR_TE(x) ((0x3f >> (6 - ((x + 1) >> 1))) << 2)
+#define ESAI_TFCR_TE_MASK 0xfff03
+#define ESAI_TFCR_TFWM(x) ((x - 1) << 8)
+#define ESAI_TFCR_TWA_MASK 0xf8ffff
+
+#define ESAI_RFCR_REXT (1 << 19)
+#define ESAI_RFCR_RE3 (1 << 5)
+#define ESAI_RFCR_RE2 (1 << 4)
+#define ESAI_RFCR_RE1 (1 << 3)
+#define ESAI_RFCR_RE0 (1 << 2)
+#define ESAI_RFCR_RFR (1 << 1)
+#define ESAI_RFCR_RFEN (1 << 0)
+#define ESAI_RFCR_RE(x) ((0xf >> (4 - ((x + 1) >> 1))) << 2)
+#define ESAI_RFCR_RE_MASK 0xfffc3
+#define ESAI_RFCR_RFWM(x) ((x-1) << 8)
+#define ESAI_RFCR_RWA_MASK 0xf8ffff
+
+#define ESAI_WORD_LEN_32 (0x00 << 16)
+#define ESAI_WORD_LEN_28 (0x01 << 16)
+#define ESAI_WORD_LEN_24 (0x02 << 16)
+#define ESAI_WORD_LEN_20 (0x03 << 16)
+#define ESAI_WORD_LEN_16 (0x04 << 16)
+#define ESAI_WORD_LEN_12 (0x05 << 16)
+#define ESAI_WORD_LEN_8 (0x06 << 16)
+#define ESAI_WORD_LEN_4 (0x07 << 16)
+
+#define ESAI_SAISR_TODFE (1 << 17)
+#define ESAI_SAISR_TEDE (1 << 16)
+#define ESAI_SAISR_TDE (1 << 15)
+#define ESAI_SAISR_TUE (1 << 14)
+#define ESAI_SAISR_TFS (1 << 13)
+#define ESAI_SAISR_RODF (1 << 10)
+#define ESAI_SAISR_REDF (1 << 9)
+#define ESAI_SAISR_RDF (1 << 8)
+#define ESAI_SAISR_ROE (1 << 7)
+#define ESAI_SAISR_RFS (1 << 6)
+#define ESAI_SAISR_IF2 (1 << 2)
+#define ESAI_SAISR_IF1 (1 << 1)
+#define ESAI_SAISR_IF0 (1 << 0)
+
+#define ESAI_SAICR_ALC (1 << 8)
+#define ESAI_SAICR_TEBE (1 << 7)
+#define ESAI_SAICR_SYNC (1 << 6)
+#define ESAI_SAICR_OF2 (1 << 2)
+#define ESAI_SAICR_OF1 (1 << 1)
+#define ESAI_SAICR_OF0 (1 << 0)
+
+#define ESAI_TCR_TLIE (1 << 23)
+#define ESAI_TCR_TIE (1 << 22)
+#define ESAI_TCR_TEDIE (1 << 21)
+#define ESAI_TCR_TEIE (1 << 20)
+#define ESAI_TCR_TPR (1 << 19)
+#define ESAI_TCR_PADC (1 << 17)
+#define ESAI_TCR_TFSR (1 << 16)
+#define ESAI_TCR_TFSL (1 << 15)
+#define ESAI_TCR_TWA (1 << 7)
+#define ESAI_TCR_TSHFD_MSB (0 << 6)
+#define ESAI_TCR_TSHFD_LSB (1 << 6)
+#define ESAI_TCR_TE5 (1 << 5)
+#define ESAI_TCR_TE4 (1 << 4)
+#define ESAI_TCR_TE3 (1 << 3)
+#define ESAI_TCR_TE2 (1 << 2)
+#define ESAI_TCR_TE1 (1 << 1)
+#define ESAI_TCR_TE0 (1 << 0)
+#define ESAI_TCR_TE(x) (0x3f >> (6 - ((x + 1) >> 1)))
+
+#define ESAI_TCR_TSWS_MASK 0xff83ff
+#define ESAI_TCR_TSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_TCR_TSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_TCR_TSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_TCR_TSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_TCR_TSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_TCR_TSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_TCR_TSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_TCR_TSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_TCR_TSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_TCR_TSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_TCR_TSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_TCR_TMOD_MASK 0xfffcff
+#define ESAI_TCR_TMOD_NORMAL (0x00 << 8)
+#define ESAI_TCR_TMOD_ONDEMAND (0x01 << 8)
+#define ESAI_TCR_TMOD_NETWORK (0x01 << 8)
+#define ESAI_TCR_TMOD_RESERVED (0x02 << 8)
+#define ESAI_TCR_TMOD_AC97 (0x03 << 8)
+
+#define ESAI_TCCR_THCKD (1 << 23)
+#define ESAI_TCCR_TFSD (1 << 22)
+#define ESAI_TCCR_TCKD (1 << 21)
+#define ESAI_TCCR_THCKP (1 << 20)
+#define ESAI_TCCR_TFSP (1 << 19)
+#define ESAI_TCCR_TCKP (1 << 18)
+
+#define ESAI_TCCR_TPSR_MASK 0xfffeff
+#define ESAI_TCCR_TPSR_SHIFT 8
+#define ESAI_TCCR_TPSR_BYPASS (1 << 8)
+#define ESAI_TCCR_TPSR_DIV8 (0 << 8)
+
+#define ESAI_TCCR_TFP_MASK 0xfc3fff
+#define ESAI_TCCR_TFP_SHIFT 14
+#define ESAI_TCCR_TFP(x) ((x & 0xf) << 14)
+
+#define ESAI_TCCR_TDC_MASK 0xffc1ff
+#define ESAI_TCCR_TDC_SHIFT 9
+#define ESAI_TCCR_TDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_TCCR_TPM_MASK 0xffff00
+#define ESAI_TCCR_TPM_SHIFT 0
+#define ESAI_TCCR_TPM(x) (x & 0xff)
+
+#define ESAI_RCR_RLIE (1 << 23)
+#define ESAI_RCR_RIE (1 << 22)
+#define ESAI_RCR_REDIE (1 << 21)
+#define ESAI_RCR_REIE (1 << 20)
+#define ESAI_RCR_RPR (1 << 19)
+#define ESAI_RCR_RFSR (1 << 16)
+#define ESAI_RCR_RFSL (1 << 15)
+#define ESAI_RCR_RWA (1 << 7)
+#define ESAI_RCR_RSHFD_MSB (0 << 6)
+#define ESAI_RCR_RSHFD_LSB (1 << 6)
+#define ESAI_RCR_RE3 (1 << 3)
+#define ESAI_RCR_RE2 (1 << 2)
+#define ESAI_RCR_RE1 (1 << 1)
+#define ESAI_RCR_RE0 (1 << 0)
+#define ESAI_RCR_RE(x) (0xf >> (4 - ((x + 1) >> 1)))
+
+#define ESAI_RCR_RSWS_MASK 0xff83ff
+#define ESAI_RCR_RSWS_STL8_WDL8 (0x00 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL8 (0x04 << 10)
+#define ESAI_RCR_RSWS_STL12_WDL12 (0x01 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL8 (0x08 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL12 (0x05 << 10)
+#define ESAI_RCR_RSWS_STL16_WDL16 (0x02 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL8 (0x0c << 10)
+#define ESAI_RCR_RSWS_STL20_WDL12 (0x09 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL16 (0x06 << 10)
+#define ESAI_RCR_RSWS_STL20_WDL20 (0x03 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL8 (0x10 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL12 (0x0d << 10)
+#define ESAI_RCR_RSWS_STL24_WDL16 (0x0a << 10)
+#define ESAI_RCR_RSWS_STL24_WDL20 (0x07 << 10)
+#define ESAI_RCR_RSWS_STL24_WDL24 (0x1e << 10)
+#define ESAI_RCR_RSWS_STL32_WDL8 (0x18 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL12 (0x15 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL16 (0x12 << 10)
+#define ESAI_RCR_RSWS_STL32_WDL20 (0x0f << 10)
+#define ESAI_RCR_RSWS_STL32_WDL24 (0x1f << 10)
+
+#define ESAI_RCR_RMOD_MASK 0xfffcff
+#define ESAI_RCR_RMOD_NORMAL (0x00 << 8)
+#define ESAI_RCR_RMOD_ONDEMAND (0x01 << 8)
+#define ESAI_RCR_RMOD_NETWORK (0x01 << 8)
+#define ESAI_RCR_RMOD_RESERVED (0x02 << 8)
+#define ESAI_RCR_RMOD_AC97 (0x03 << 8)
+
+#define ESAI_RCCR_RHCKD (1 << 23)
+#define ESAI_RCCR_RFSD (1 << 22)
+#define ESAI_RCCR_RCKD (1 << 21)
+#define ESAI_RCCR_RHCKP (1 << 20)
+#define ESAI_RCCR_RFSP (1 << 19)
+#define ESAI_RCCR_RCKP (1 << 18)
+
+#define ESAI_RCCR_RPSR_MASK 0xfffeff
+#define ESAI_RCCR_RPSR_SHIFT 8
+#define ESAI_RCCR_RPSR_BYPASS (1 << 8)
+#define ESAI_RCCR_RPSR_DIV8 (0 << 8)
+
+#define ESAI_RCCR_RFP_MASK 0xfc3fff
+#define ESAI_RCCR_RFP_SHIFT 14
+#define ESAI_RCCR_RFP(x) ((x & 0xf) << 14)
+
+#define ESAI_RCCR_RDC_MASK 0xffc1ff
+#define ESAI_RCCR_RDC_SHIFT 9
+#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9)
+
+#define ESAI_RCCR_RPM_MASK 0xffff00
+#define ESAI_RCCR_RPM_SHIFT 0
+#define ESAI_RCCR_RPM(x) (x & 0xff)
+
+#define ESAI_GPIO_ESAI 0xfff
+
+/* ESAI clock source */
+#define ESAI_CLK_FSYS 0
+#define ESAI_CLK_EXTAL 1
+#define ESAI_CLK_EXTAL_DIV 2
+
+/* ESAI clock divider */
+#define ESAI_TX_DIV_PSR 0
+#define ESAI_TX_DIV_PM 1
+#define ESAI_TX_DIV_FP 2
+#define ESAI_RX_DIV_PSR 3
+#define ESAI_RX_DIV_PM 4
+#define ESAI_RX_DIV_FP 5
+
+#define DRV_NAME "imx-esai"
+
+#include <linux/dmaengine.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/platform_data/dma-imx.h>
+
+#define IMX_DAI_ESAI_TX 0x04
+#define IMX_DAI_ESAI_RX 0x08
+#define IMX_DAI_ESAI_TXRX (IMX_DAI_ESAI_TX | IMX_DAI_ESAI_RX)
+
+struct fsl_esai {
+ struct clk *clk;
+ void __iomem *base;
+ int irq;
+ unsigned int flags;
+ unsigned int fifo_depth;
+
+ struct snd_dmaengine_dai_dma_data dma_params_rx;
+ struct snd_dmaengine_dai_dma_data dma_params_tx;
+ struct imx_dma_data filter_data_tx;
+ struct imx_dma_data filter_data_rx;
+
+ char name[32];
+};
+
+#endif