diff options
author | Shengjiu Wang <b02247@freescale.com> | 2014-04-28 10:40:10 +0800 |
---|---|---|
committer | Shengjiu Wang <b02247@freescale.com> | 2014-04-29 12:43:02 +0800 |
commit | 22d1bec44929e5fb6fa8316c4687d493c7d264b4 (patch) | |
tree | 93c47078d636f776b5ef78063fe76f5941b5dcba | |
parent | 0673acf93a40e5b26b667b627dc62b81b377cc70 (diff) |
ENGR00310878-2 ASoC: fsl_esai: cherry-pick from upstream and merge to mainline
cherry-picked commit is 43d24e76b69826ce32292f47060ad78cdd0197fa
Header of this commit is "ASoC: fsl_esai: Add ESAI CPU DAI driver", use upstream
driver to replace current one.
Merged feature is:
1. Move setting of PRRC and PCRC to the end of hw_params, and disable it in
shutdown function.
2. Merged the xrun handler with this commit.
3. Use dma init with NO_RESIDUE|NO_DT|COMPAT.
4. Add spba clock for ESAI
Signed-off-by: Shengjiu Wang <b02247@freescale.com>
-rw-r--r-- | Documentation/devicetree/bindings/sound/fsl,esai.txt | 50 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/sound/fsl-easi.txt | 26 | ||||
-rw-r--r-- | arch/arm/boot/dts/imx6qdl.dtsi | 2 | ||||
-rw-r--r-- | arch/arm/boot/dts/imx6sx.dtsi | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_esai.c | 1278 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_esai.h | 667 | ||||
-rw-r--r-- | sound/soc/fsl/imx-cs42888.c | 75 |
7 files changed, 1080 insertions, 1020 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt new file mode 100644 index 000000000000..d7b99fa637b5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -0,0 +1,50 @@ +Freescale Enhanced Serial Audio Interface (ESAI) Controller + +The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port +for serial communication with a variety of serial devices, including industry +standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and +other DSPs. It has up to six transmitters and four receivers. + +Required properties: + + - compatible : Compatible list, must contain "fsl,imx35-esai". + + - reg : Offset and length of the register set for the device. + + - interrupts : Contains the spdif interrupt. + + - dmas : Generic dma devicetree binding as described in + Documentation/devicetree/bindings/dma/dma.txt. + + - dma-names : Two dmas have to be defined, "tx" and "rx". + + - clocks: Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "core" The core clock used to access registers + "extal" The esai baud clock for esai controller used to derive + HCK, SCK and FS. + "fsys" The system clock derived from ahb clock used to derive + HCK, SCK and FS. + + - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs. + This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM]. + + - fsl,esai-synchronous: This is a boolean property. If present, indicating + that ESAI would work in the synchronous mode, which means all the settings + for Receiving would be duplicated from Transmition related registers. + +Example: + +esai: esai@02024000 { + compatible = "fsl,imx35-esai"; + reg = <0x02024000 0x4000>; + interrupts = <0 51 0x04>; + clocks = <&clks 208>, <&clks 118>, <&clks 208>; + clock-names = "core", "extal", "fsys"; + dmas = <&sdma 23 21 0>, <&sdma 24 21 0>; + dma-names = "rx", "tx"; + fsl,fifo-depth = <128>; + fsl,esai-synchronous; + status = "disabled"; +}; diff --git a/Documentation/devicetree/bindings/sound/fsl-easi.txt b/Documentation/devicetree/bindings/sound/fsl-easi.txt deleted file mode 100644 index b6196622accd..000000000000 --- a/Documentation/devicetree/bindings/sound/fsl-easi.txt +++ /dev/null @@ -1,26 +0,0 @@ -* 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/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index 9cdd0d3710b8..d8a008669e17 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -246,7 +246,7 @@ }; esai: esai@02024000 { - compatible = "fsl,imx6q-esai"; + compatible = "fsl,imx35-esai"; reg = <0x02024000 0x4000>; interrupts = <0 51 0x04>; clocks = <&clks 228>, <&clks 229>, <&clks 118>, <&clks 228>, <&clks 156>; diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi index 9d04725f07d4..134329746b91 100644 --- a/arch/arm/boot/dts/imx6sx.dtsi +++ b/arch/arm/boot/dts/imx6sx.dtsi @@ -244,7 +244,7 @@ }; esai: esai@02024000 { - compatible = "fsl,imx6q-esai"; + compatible = "fsl,imx35-esai"; reg = <0x02024000 0x4000>; interrupts = <0 51 0x04>; clocks = <&clks IMX6SX_CLK_ESAI_IPG>, diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 0f9282cc5acf..5a230707da16 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -1,226 +1,381 @@ /* - * Copyright 2008-2014 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: + * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. */ - /*! - * @file fsl-esai.c - * @brief this file implements the esai interface - * in according to ASoC architeture - */ - +#include <linux/clk.h> +#include <linux/dmaengine.h> #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/dmaengine_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) +#define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000 +#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE) +#define REG_CACHE_NUM 20 + +/** + * fsl_esai: ESAI private data + * + * @dma_params_rx: DMA parameters for receive channel + * @dma_params_tx: DMA parameters for transmit channel + * @pdev: platform device pointer + * @regmap: regmap handler + * @coreclk: clock source to access register + * @extalclk: esai clock source to derive HCK, SCK and FS + * @fsysclk: system clock source to derive HCK, SCK and FS + * @fifo_depth: depth of tx/rx FIFO + * @slot_width: width of each DAI slot + * @hck_rate: clock rate of desired HCKx clock + * @sck_div: if using PSR/PM dividers for SCKx clock + * @slave_mode: if fully using DAI slave mode + * @synchronous: if using tx/rx synchronous mode + * @name: driver name + */ +struct fsl_esai { + 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; + struct snd_pcm_substream *substream[2]; + struct platform_device *pdev; + struct regmap *regmap; + struct clk *coreclk; + struct clk *extalclk; + struct clk *fsysclk; + struct clk *dmaclk; + u32 fifo_depth; + u32 slot_width; + u32 hck_rate[2]; + bool sck_div[2]; + bool slave_mode; + bool synchronous; + char name[32]; + u32 reg_cache[REG_CACHE_NUM]; +}; -static inline void write_esai_mask(u32 __iomem *addr, u32 clear, u32 set) +static irqreturn_t esai_isr(int irq, void *devid) { - u32 val = readl(addr); - val = (val & ~clear) | set; - writel(val, addr); + struct fsl_esai *esai_priv = (struct fsl_esai *)devid; + struct platform_device *pdev = esai_priv->pdev; + u32 esr; + + regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr); + + if (esr & ESAI_ESR_TINIT_MASK) + dev_dbg(&pdev->dev, "isr: Transmition Initialized\n"); + + if (esr & ESAI_ESR_RFF_MASK) + dev_warn(&pdev->dev, "isr: Receiving overrun\n"); + + if (esr & ESAI_ESR_TFE_MASK) + dev_warn(&pdev->dev, "isr: Transmition underrun\n"); + + if (esr & ESAI_ESR_TLS_MASK) + dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n"); + + if (esr & ESAI_ESR_TDE_MASK) + dev_dbg(&pdev->dev, "isr: Transmition data exception\n"); + + if (esr & ESAI_ESR_TED_MASK) + dev_dbg(&pdev->dev, "isr: Transmitting even slots\n"); + + if (esr & ESAI_ESR_TD_MASK) + dev_dbg(&pdev->dev, "isr: Transmitting data\n"); + + if (esr & ESAI_ESR_RLS_MASK) + dev_dbg(&pdev->dev, "isr: Just received the last slot\n"); + + if (esr & ESAI_ESR_RDE_MASK) + dev_dbg(&pdev->dev, "isr: Receiving data exception\n"); + + if (esr & ESAI_ESR_RED_MASK) + dev_dbg(&pdev->dev, "isr: Receiving even slots\n"); + + if (esr & ESAI_ESR_RD_MASK) + dev_dbg(&pdev->dev, "isr: Receiving data\n"); + + return IRQ_HANDLED; } -static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int dir) +/** + * This function is used to calculate the divisors of psr, pm, fp and it is + * supposed to be called in set_dai_sysclk() and set_bclk(). + * + * @ratio: desired overall ratio for the paticipating dividers + * @usefp: for HCK setting, there is no need to set fp divider + * @fp: bypass other dividers by setting fp directly if fp != 0 + * @tx: current setting is for playback or capture + */ +static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio, + bool usefp, u32 fp) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - u32 ecr, tccr, rccr; - - clk_enable(esai->clk); - 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; + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j; + + maxfp = usefp ? 16 : 1; + + if (usefp && fp) + goto out_fp; + + if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) { + dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n", + 2 * 8 * 256 * maxfp); + return -EINVAL; + } else if (ratio % 2) { + dev_err(dai->dev, "the raio must be even if using upper divider\n"); + return -EINVAL; + } + + ratio /= 2; + + psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8; + + /* Set the max fluctuation -- 0.1% of the max devisor */ + savesub = (psr ? 1 : 8) * 256 * maxfp / 1000; + + /* Find the best value for PM */ + for (i = 1; i <= 256; i++) { + for (j = 1; j <= maxfp; j++) { + /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */ + prod = (psr ? 1 : 8) * i * j; + + if (prod == ratio) + sub = 0; + else if (prod / ratio == 1) + sub = prod - ratio; + else if (ratio / prod == 1) + sub = ratio - prod; + else + continue; + + /* Calculate the fraction */ + sub = sub * 1000 / ratio; + if (sub < savesub) { + savesub = sub; + pm = i; + fp = j; + } + + /* We are lucky */ + if (savesub == 0) + goto out; } } - writel(ecr, esai->base + ESAI_ECR); - writel(tccr, esai->base + ESAI_TCCR); - writel(rccr, esai->base + ESAI_RCCR); + if (pm == 999) { + dev_err(dai->dev, "failed to calculate proper divisors\n"); + return -EINVAL; + } + +out: + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx), + ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK, + psr | ESAI_xCCR_xPM(pm)); + +out_fp: + /* Bypass fp if not being required */ + if (maxfp <= 1) + return 0; - ESAI_DUMP(); - clk_disable(esai->clk); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx), + ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp)); return 0; } -static int fsl_esai_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, - int div_id, int div) +/** + * This function mainly configures the clock frequency of MCLK (HCKT/HCKR) + * + * @Parameters: + * clk_id: The clock source of HCKT/HCKR + * (Input from outside; output from inside, FSYS or EXTAL) + * freq: The required clock rate of HCKT/HCKR + * dir: The clock direction of HCKT/HCKR + * + * Note: If the direction is input, we do not care about clk_id. + */ +static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - u32 tccr, rccr; - - clk_enable(esai->clk); - 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); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + struct clk *clksrc = esai_priv->extalclk; + bool tx = clk_id <= ESAI_HCKT_EXTAL; + bool in = dir == SND_SOC_CLOCK_IN; + u32 ret, ratio, ecr = 0; + unsigned long clk_rate; + + /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */ + esai_priv->sck_div[tx] = true; + + /* Set the direction of HCKT/HCKR pins */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx), + ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD); + + if (in) + goto out; + + switch (clk_id) { + case ESAI_HCKT_FSYS: + case ESAI_HCKR_FSYS: + clksrc = esai_priv->fsysclk; 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); + case ESAI_HCKT_EXTAL: + ecr |= ESAI_ECR_ETI; + case ESAI_HCKR_EXTAL: + ecr |= ESAI_ECR_ERI; break; default: return -EINVAL; } - writel(tccr, esai->base + ESAI_TCCR); - writel(rccr, esai->base + ESAI_RCCR); - clk_disable(esai->clk); + + if (IS_ERR(clksrc)) { + dev_err(dai->dev, "no assigned %s clock\n", + clk_id % 2 ? "extal" : "fsys"); + return PTR_ERR(clksrc); + } + clk_rate = clk_get_rate(clksrc); + + ratio = clk_rate / freq; + if (ratio * freq > clk_rate) + ret = ratio * freq - clk_rate; + else if (ratio * freq < clk_rate) + ret = clk_rate - ratio * freq; + else + ret = 0; + + /* Block if clock source can not be divided into the required rate */ + if (ret != 0 && clk_rate / ret < 1000) { + dev_err(dai->dev, "failed to derive required HCK%c rate\n", + tx ? 'T' : 'R'); + return -EINVAL; + } + + if (ratio == 1) { + /* Bypass all the dividers if not being needed */ + ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO; + goto out; + } + + ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0); + if (ret) + return ret; + + esai_priv->sck_div[tx] = false; + +out: + esai_priv->hck_rate[tx] = freq; + + regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR, + tx ? ESAI_ECR_ETI | ESAI_ECR_ETO : + ESAI_ECR_ERI | ESAI_ECR_ERO, ecr); return 0; } -/* - * ESAI Network Mode or TDM slots configuration. +/** + * This function configures the related dividers according to the bclk rate */ -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) +static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - u32 tccr, rccr; + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + u32 hck_rate = esai_priv->hck_rate[tx]; + u32 sub, ratio = hck_rate / freq; + + /* Don't apply for fully slave mode*/ + if (esai_priv->slave_mode) + return 0; + + if (ratio * freq > hck_rate) + sub = ratio * freq - hck_rate; + else if (ratio * freq < hck_rate) + sub = hck_rate - ratio * freq; + else + sub = 0; + + /* Block if clock source can not be divided into the required rate */ + if (sub != 0 && hck_rate / sub < 1000) { + dev_err(dai->dev, "failed to derive required SCK%c rate\n", + tx ? 'T' : 'R'); + return -EINVAL; + } + + if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) { + dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n"); + return -EINVAL; + } - clk_enable(esai->clk); - tccr = readl(esai->base + ESAI_TCCR); + return fsl_esai_divisor_cal(dai, tx, ratio, true, + esai_priv->sck_div[tx] ? 0 : ratio); +} - tccr &= ESAI_TCCR_TDC_MASK; - tccr |= ESAI_TCCR_TDC(slots - 1); +static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); - writel(tccr, esai->base + ESAI_TCCR); - writel((tx_mask & 0xffff), esai->base + ESAI_TSMA); - writel(((tx_mask >> 16) & 0xffff), esai->base + ESAI_TSMB); + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - rccr = readl(esai->base + ESAI_RCCR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, + ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask)); - rccr &= ESAI_RCCR_RDC_MASK; - rccr |= ESAI_RCCR_RDC(slots - 1); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); - writel(rccr, esai->base + ESAI_RCCR); - writel((rx_mask & 0xffff), esai->base + ESAI_RSMA); - writel(((rx_mask >> 16) & 0xffff), esai->base + ESAI_RSMB); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, + ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, + ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask)); - ESAI_DUMP(); - clk_disable(esai->clk); + esai_priv->slot_width = slot_width; return 0; } -/* - * ESAI DAI format configuration. - */ -static int fsl_esai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - u32 tcr, tccr, rcr, rccr, saicr; - - clk_enable(esai->clk); - 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); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + u32 xcr = 0, xccr = 0, mask; /* 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; + /* Data on rising edge of bclk, frame low, 1clk before data */ + xcr |= ESAI_xCR_xFSR; + xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; 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); + /* Data on rising edge of bclk, frame high */ + xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; 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; + case SND_SOC_DAIFMT_RIGHT_J: + /* Data on rising edge of bclk, frame high, right aligned */ + xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA; 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; + /* Data on rising edge of bclk, frame high, 1clk before data */ + xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR; + xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; + break; + case SND_SOC_DAIFMT_DSP_B: + /* Data on rising edge of bclk, frame high */ + xcr |= ESAI_xCR_xFSL; + xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; break; default: return -EINVAL; @@ -228,343 +383,216 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) /* 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; + case SND_SOC_DAIFMT_NB_NF: + /* Nothing to do for both normal cases */ 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); + /* Invert bit clock */ + xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP; 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; + /* Invert frame clock */ + xccr ^= ESAI_xCCR_xFSP; 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; + case SND_SOC_DAIFMT_IB_IF: + /* Invert both clocks */ + xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP; break; default: return -EINVAL; } + esai_priv->slave_mode = false; + /* 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); + esai_priv->slave_mode = true; break; case SND_SOC_DAIFMT_CBS_CFM: - tccr &= ~ESAI_TCCR_TFSD; - tccr |= ESAI_TCCR_TCKD; - rccr &= ~ESAI_RCCR_RFSD; - rccr |= ESAI_RCCR_RCKD; + xccr |= ESAI_xCCR_xCKD; break; case SND_SOC_DAIFMT_CBM_CFS: - tccr &= ~ESAI_TCCR_TCKD; - tccr |= ESAI_TCCR_TFSD; - rccr &= ~ESAI_RCCR_RCKD; - rccr |= ESAI_RCCR_RFSD; + xccr |= ESAI_xCCR_xFSD; break; case SND_SOC_DAIFMT_CBS_CFS: - tccr |= (ESAI_TCCR_TFSD | ESAI_TCCR_TCKD); - rccr |= (ESAI_RCCR_RFSD | ESAI_RCCR_RCKD); + xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; 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); + mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR; + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr); - ESAI_DUMP(); - clk_disable(esai->clk); + mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP | + ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA; + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr); return 0; } static int fsl_esai_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); - clk_enable(esai->clk); - clk_prepare_enable(esai->dmaclk); - clk_prepare_enable(esai->extalclk); - - esai->substream[substream->stream] = substream; - - 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; + /* + * Some platforms might use the same bit to gate all three or two of + * clocks, so keep all clocks open/close at the same time for safety + */ + clk_prepare_enable(esai_priv->dmaclk); + clk_prepare_enable(esai_priv->coreclk); + if (!IS_ERR(esai_priv->extalclk)) + clk_prepare_enable(esai_priv->extalclk); + if (!IS_ERR(esai_priv->fsysclk)) + clk_prepare_enable(esai_priv->fsysclk); + + if (!dai->active) { + /* Set synchronous mode */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR, + ESAI_SAICR_SYNC, esai_priv->synchronous ? + ESAI_SAICR_SYNC : 0); + + /* Set a default slot number -- 2 */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, + ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2)); } - 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; + esai_priv->substream[substream->stream] = substream; - 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) +static int fsl_esai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *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; - } + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u32 width = snd_pcm_format_width(params_format(params)); + u32 channels = params_channels(params); + u32 bclk, mask, val, ret; - channels = params_channels(params); - rfcr &= ESAI_RFCR_RE_MASK; - rfcr |= ESAI_RFCR_RE(channels); + bclk = params_rate(params) * esai_priv->slot_width * 2; - rfcr |= ESAI_RFCR_RFWM(esai->fifo_depth); + ret = fsl_esai_set_bclk(dai, tx, bclk); + if (ret) + return ret; - writel(rcr, esai->base + ESAI_RCR); - writel(rfcr, esai->base + ESAI_RFCR); + /* Use Normal mode to support monaural audio */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ? + ESAI_xCR_xMOD_NETWORK : 0); - ESAI_DUMP(); - return 0; -} + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR); -/* - * 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); - int ret = 0; - - /* Tx/Rx config */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (readl(esai->base + ESAI_TCR) & ESAI_TCR_TE0) - return 0; + mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | + (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); + val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | + (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); - ret = fsl_esai_hw_tx_params(substream, params, cpu_dai); - } else { - if (readl(esai->base + ESAI_RCR) & ESAI_RCR_RE1) - return 0; + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); - ret = fsl_esai_hw_rx_params(substream, params, cpu_dai); - } + mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); + val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0); - /* - * PRRC and PCRC should be set after control register has been set, - * before the trigger() be called, according the reference manual. - */ - writel(ESAI_GPIO_ESAI, esai->base + ESAI_PRRC); - writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); - return ret; + /* Reset Port C */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); + return 0; } static void fsl_esai_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *dai) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - - if (!cpu_dai->active) { - writel(0, esai->base + ESAI_PRRC); - writel(0, esai->base + ESAI_PCRC); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + + if (!dai->active) { + /* Reset Port C */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, 0); } - esai->substream[substream->stream] = NULL; + esai_priv->substream[substream->stream] = NULL; - clk_disable_unprepare(esai->extalclk); - clk_disable_unprepare(esai->dmaclk); - clk_disable(esai->clk); + if (!IS_ERR(esai_priv->fsysclk)) + clk_disable_unprepare(esai_priv->fsysclk); + if (!IS_ERR(esai_priv->extalclk)) + clk_disable_unprepare(esai_priv->extalclk); + clk_disable_unprepare(esai_priv->coreclk); + clk_disable_unprepare(esai_priv->dmaclk); } static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *cpu_dai) + struct snd_soc_dai *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); - } + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + u8 i, channels = substream->runtime->channels; + 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); - } + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN); + + /* Write initial words reqiured by ESAI as normal procedure */ + for (i = 0; tx && i < channels; i++) + regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0); + + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, + tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); 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); - } + regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), + tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0); + + /* Disable and reset FIFO */ + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), + ESAI_xFCR_xFR, 0); 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); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx, + &esai_priv->dma_params_rx); - dai->playback_dma_data = &esai->dma_params_tx; - dai->capture_dma_data = &esai->dma_params_rx; return 0; } @@ -574,15 +602,15 @@ static struct snd_soc_dai_driver fsl_esai_dai = { .stream_name = "esai-Playback", .channels_min = 1, .channels_max = 12, - .rates = IMX_ESAI_RATES, - .formats = IMX_ESAI_FORMATS, + .rates = FSL_ESAI_RATES, + .formats = FSL_ESAI_FORMATS, }, .capture = { .stream_name = "esai-Capture", .channels_min = 1, .channels_max = 8, - .rates = IMX_ESAI_RATES, - .formats = IMX_ESAI_FORMATS, + .rates = FSL_ESAI_RATES, + .formats = FSL_ESAI_FORMATS, }, .ops = &fsl_esai_dai_ops, }; @@ -591,51 +619,128 @@ static const struct snd_soc_component_driver fsl_esai_component = { .name = "fsl-esai", }; +static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_ESAI_ERDR: + case REG_ESAI_ECR: + case REG_ESAI_ESR: + case REG_ESAI_TFCR: + case REG_ESAI_TFSR: + case REG_ESAI_RFCR: + case REG_ESAI_RFSR: + case REG_ESAI_RX0: + case REG_ESAI_RX1: + case REG_ESAI_RX2: + case REG_ESAI_RX3: + case REG_ESAI_SAISR: + case REG_ESAI_SAICR: + case REG_ESAI_TCR: + case REG_ESAI_TCCR: + case REG_ESAI_RCR: + case REG_ESAI_RCCR: + case REG_ESAI_TSMA: + case REG_ESAI_TSMB: + case REG_ESAI_RSMA: + case REG_ESAI_RSMB: + case REG_ESAI_PRRC: + case REG_ESAI_PCRC: + return true; + default: + return false; + } +} + +static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case REG_ESAI_ETDR: + case REG_ESAI_ECR: + case REG_ESAI_TFCR: + case REG_ESAI_RFCR: + case REG_ESAI_TX0: + case REG_ESAI_TX1: + case REG_ESAI_TX2: + case REG_ESAI_TX3: + case REG_ESAI_TX4: + case REG_ESAI_TX5: + case REG_ESAI_TSR: + case REG_ESAI_SAICR: + case REG_ESAI_TCR: + case REG_ESAI_TCCR: + case REG_ESAI_RCR: + case REG_ESAI_RCCR: + case REG_ESAI_TSMA: + case REG_ESAI_TSMB: + case REG_ESAI_RSMA: + case REG_ESAI_RSMB: + case REG_ESAI_PRRC: + case REG_ESAI_PCRC: + return true; + default: + return false; + } +} + +static const struct regmap_config fsl_esai_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + + .max_register = REG_ESAI_PCRC, + .readable_reg = fsl_esai_readable_reg, + .writeable_reg = fsl_esai_writeable_reg, +}; + static bool fsl_esai_check_xrun(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - u32 saisr = readl(esai->base + ESAI_SAISR); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(cpu_dai); + u32 saisr; + + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); return saisr & (ESAI_SAISR_TUE | ESAI_SAISR_ROE) ; } static int store_reg(struct snd_soc_dai *cpu_dai) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - - esai->reg_cache[0] = readl(esai->base + ESAI_ECR); - esai->reg_cache[2] = readl(esai->base + ESAI_TFCR); - esai->reg_cache[4] = readl(esai->base + ESAI_RFCR); - esai->reg_cache[8] = readl(esai->base + ESAI_SAICR); - esai->reg_cache[9] = readl(esai->base + ESAI_TCR); - esai->reg_cache[10] = readl(esai->base + ESAI_TCCR); - esai->reg_cache[11] = readl(esai->base + ESAI_RCR); - esai->reg_cache[12] = readl(esai->base + ESAI_RCCR); - esai->reg_cache[13] = readl(esai->base + ESAI_TSMA); - esai->reg_cache[14] = readl(esai->base + ESAI_TSMB); - esai->reg_cache[15] = readl(esai->base + ESAI_RSMA); - esai->reg_cache[16] = readl(esai->base + ESAI_RSMB); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(cpu_dai); + + regmap_read(esai_priv->regmap, REG_ESAI_ECR, &esai_priv->reg_cache[0]); + regmap_read(esai_priv->regmap, REG_ESAI_TFCR, &esai_priv->reg_cache[2]); + regmap_read(esai_priv->regmap, REG_ESAI_RFCR, &esai_priv->reg_cache[4]); + regmap_read(esai_priv->regmap, REG_ESAI_SAICR, &esai_priv->reg_cache[8]); + regmap_read(esai_priv->regmap, REG_ESAI_TCR, &esai_priv->reg_cache[9]); + regmap_read(esai_priv->regmap, REG_ESAI_TCCR, &esai_priv->reg_cache[10]); + regmap_read(esai_priv->regmap, REG_ESAI_RCR, &esai_priv->reg_cache[11]); + regmap_read(esai_priv->regmap, REG_ESAI_RCCR, &esai_priv->reg_cache[12]); + regmap_read(esai_priv->regmap, REG_ESAI_TSMA, &esai_priv->reg_cache[13]); + regmap_read(esai_priv->regmap, REG_ESAI_TSMB, &esai_priv->reg_cache[14]); + regmap_read(esai_priv->regmap, REG_ESAI_RSMA, &esai_priv->reg_cache[15]); + regmap_read(esai_priv->regmap, REG_ESAI_RSMB, &esai_priv->reg_cache[16]); + return 0; } static int restore_reg(struct snd_soc_dai *cpu_dai) { - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - - writel(esai->reg_cache[0], esai->base + ESAI_ECR); - writel(esai->reg_cache[2] & ~ESAI_TFCR_TFEN, esai->base + ESAI_TFCR); - writel(esai->reg_cache[4] & ~ESAI_RFCR_RFEN, esai->base + ESAI_RFCR); - writel(esai->reg_cache[8], esai->base + ESAI_SAICR); - writel(esai->reg_cache[9] & ~ESAI_TCR_TE(12), esai->base + ESAI_TCR); - writel(esai->reg_cache[10], esai->base + ESAI_TCCR); - writel(esai->reg_cache[11] & ~ESAI_RCR_RE(8), esai->base + ESAI_RCR); - writel(esai->reg_cache[12], esai->base + ESAI_RCCR); - writel(esai->reg_cache[13], esai->base + ESAI_TSMA); - writel(esai->reg_cache[14], esai->base + ESAI_TSMB); - writel(esai->reg_cache[15], esai->base + ESAI_RSMA); - writel(esai->reg_cache[16], esai->base + ESAI_RSMB); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(cpu_dai); + + regmap_write(esai_priv->regmap, REG_ESAI_ECR, esai_priv->reg_cache[0]); + regmap_write(esai_priv->regmap, REG_ESAI_TFCR, esai_priv->reg_cache[2] & ~ESAI_xFCR_xFEN); + regmap_write(esai_priv->regmap, REG_ESAI_RFCR, esai_priv->reg_cache[4] & ~ESAI_xFCR_xFEN); + regmap_write(esai_priv->regmap, REG_ESAI_SAICR, esai_priv->reg_cache[8]); + regmap_write(esai_priv->regmap, REG_ESAI_TCR, esai_priv->reg_cache[9] & ~ESAI_xCR_TE(12)); + regmap_write(esai_priv->regmap, REG_ESAI_TCCR, esai_priv->reg_cache[10]); + regmap_write(esai_priv->regmap, REG_ESAI_RCR, esai_priv->reg_cache[11] & ~ESAI_xCR_RE(8)); + regmap_write(esai_priv->regmap, REG_ESAI_RCCR, esai_priv->reg_cache[12]); + regmap_write(esai_priv->regmap, REG_ESAI_TSMA, esai_priv->reg_cache[13]); + regmap_write(esai_priv->regmap, REG_ESAI_TSMB, esai_priv->reg_cache[14]); + regmap_write(esai_priv->regmap, REG_ESAI_RSMA, esai_priv->reg_cache[15]); + regmap_write(esai_priv->regmap, REG_ESAI_RSMB, esai_priv->reg_cache[16]); + return 0; } @@ -677,229 +782,210 @@ static void fsl_esai_reset(struct snd_pcm_substream *substream, bool stop) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct fsl_esai *esai = snd_soc_dai_get_drvdata(cpu_dai); - ESAI_DUMP(); + struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(cpu_dai); + u32 saisr; if (stop) { - stop_lock_stream(esai->substream[0]); - stop_lock_stream(esai->substream[1]); + stop_lock_stream(esai_priv->substream[0]); + stop_lock_stream(esai_priv->substream[1]); } store_reg(cpu_dai); - writel(ESAI_ECR_ESAIEN | ESAI_ECR_ERST, esai->base + ESAI_ECR); - writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR); + regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN | ESAI_ECR_ERST); + regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN); - write_esai_mask(esai->base+ESAI_TCR, 0, ESAI_TCR_TPR); - write_esai_mask(esai->base+ESAI_RCR, 0, ESAI_RCR_RPR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, ESAI_xCR_xPR_MASK, ESAI_xCR_xPR); restore_reg(cpu_dai); - write_esai_mask(esai->base+ESAI_TCR, ESAI_TCR_TPR, 0); - write_esai_mask(esai->base+ESAI_RCR, ESAI_RCR_RPR, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, ESAI_xCR_xPR_MASK, 0); + regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, ESAI_xCR_xPR_MASK, 0); - writel(ESAI_GPIO_ESAI, esai->base + ESAI_PRRC); - writel(ESAI_GPIO_ESAI, esai->base + ESAI_PCRC); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC, + ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO)); + regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC, + ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO)); - /* read "TUE" flag.*/ - readl(esai->base + ESAI_SAISR); + regmap_read(esai_priv->regmap, REG_ESAI_SAISR, &saisr); if (stop) { - start_unlock_stream(esai->substream[1]); - start_unlock_stream(esai->substream[0]); + start_unlock_stream(esai_priv->substream[1]); + start_unlock_stream(esai_priv->substream[0]); } - ESAI_DUMP(); -} - -static int fsl_esai_reg_init(struct fsl_esai *esai) -{ - u32 xccr, slots = 2; - - clk_enable(esai->clk); - - /* Reset and enable the ESAI module */ - writel(ESAI_ECR_ERST, esai->base + ESAI_ECR); - writel(ESAI_ECR_ESAIEN, esai->base + ESAI_ECR); - - /* Set default slot number to 2 for common DAI FMTs */ - xccr = readl(esai->base + ESAI_TCCR); - xccr &= ESAI_TCCR_TDC_MASK; - xccr |= ESAI_TCCR_TDC(slots - 1); - writel(xccr, esai->base + ESAI_TCCR); - - xccr = readl(esai->base + ESAI_RCCR); - xccr &= ESAI_RCCR_RDC_MASK; - xccr |= ESAI_RCCR_RDC(slots - 1); - writel(xccr, esai->base + ESAI_RCCR); - - clk_disable(esai->clk); - - return 0; } static int fsl_esai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct resource res; - struct fsl_esai *esai; + struct fsl_esai *esai_priv; + struct resource *res; const uint32_t *iprop; - uint32_t flag; - const char *p; + void __iomem *regs; + int irq, ret; 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"); + esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL); + if (!esai_priv) 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_priv->pdev = pdev; + strcpy(esai_priv->name, np->name); + + /* Get the addresses and IRQ */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, + "core", regs, &fsl_esai_regmap_config); + if (IS_ERR(esai_priv->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(esai_priv->regmap)); + return PTR_ERR(esai_priv->regmap); } - esai->flags = flag; - esai->clk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(esai->clk)) { - ret = PTR_ERR(esai->clk); - dev_err(&pdev->dev, "Cannot get the clock: %d\n", ret); - return ret; + esai_priv->coreclk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(esai_priv->coreclk)) { + dev_err(&pdev->dev, "failed to get core clock: %ld\n", + PTR_ERR(esai_priv->coreclk)); + return PTR_ERR(esai_priv->coreclk); } - clk_prepare(esai->clk); - esai->dmaclk = devm_clk_get(&pdev->dev, "dma"); - if (IS_ERR(esai->dmaclk)) { - ret = PTR_ERR(esai->dmaclk); - dev_err(&pdev->dev, "Cannot get dma clock: %d\n", ret); - goto failed_get_resource; + esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal"); + if (IS_ERR(esai_priv->extalclk)) + dev_warn(&pdev->dev, "failed to get extal clock: %ld\n", + PTR_ERR(esai_priv->extalclk)); + + esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys"); + if (IS_ERR(esai_priv->fsysclk)) + dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n", + PTR_ERR(esai_priv->fsysclk)); + + esai_priv->dmaclk = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(esai_priv->dmaclk)) { + dev_err(&pdev->dev, "Cannot get dma clock: %ld\n", + PTR_ERR(esai_priv->dmaclk)); + return PTR_ERR(esai_priv->dmaclk); } - esai->extalclk = devm_clk_get(&pdev->dev, "extal"); - if (IS_ERR(esai->extalclk)) { - ret = PTR_ERR(esai->extalclk); - dev_err(&pdev->dev, "Cannot get extal clock: %d\n", ret); - goto failed_get_resource; + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); + return irq; } - ret = of_address_to_resource(np, 0, &res); + ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0, + esai_priv->name, esai_priv); if (ret) { - dev_err(&pdev->dev, "could not determine device resources\n"); - goto failed_get_resource; + dev_err(&pdev->dev, "failed to claim irq %u\n", irq); + return ret; } - esai->base = of_iomap(np, 0); - if (!esai->base) { - dev_err(&pdev->dev, "could not map device resources\n"); - ret = -ENOMEM; - goto failed_iomap; - } + /* Set a default slot size */ + esai_priv->slot_width = 32; - esai->irq = irq_of_parse_and_map(np, 0); + /* Set a default master/slave state */ + esai_priv->slave_mode = true; - /* Determine the FIFO depth. */ + /* Determine the FIFO depth */ iprop = of_get_property(np, "fsl,fifo-depth", NULL); if (iprop) - esai->fifo_depth = be32_to_cpup(iprop); + esai_priv->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_priv->fifo_depth = 64; - esai->dma_params_tx.filter_data = &esai->filter_data_tx; - esai->dma_params_rx.filter_data = &esai->filter_data_rx; + esai_priv->dma_params_tx.maxburst = 16; + esai_priv->dma_params_rx.maxburst = 16; + esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR; + esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR; - esai->dma_params_tx.check_xrun = fsl_esai_check_xrun; - esai->dma_params_rx.check_xrun = fsl_esai_check_xrun; - esai->dma_params_tx.device_reset = fsl_esai_reset; - esai->dma_params_rx.device_reset = fsl_esai_reset; + esai_priv->dma_params_tx.filter_data = &esai_priv->filter_data_tx; + esai_priv->dma_params_rx.filter_data = &esai_priv->filter_data_rx; ret = of_property_read_u32_array(pdev->dev.of_node, - "fsl,esai-dma-events", dma_events, 2); + "fsl,esai-dma-events", dma_events, 2); if (ret) { dev_err(&pdev->dev, "could not get dma events\n"); - goto failed_get_dma; + return ret; } - 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; + esai_priv->filter_data_tx.dma_request0 = dma_events[0]; + esai_priv->filter_data_rx.dma_request0 = dma_events[1]; + esai_priv->filter_data_tx.peripheral_type = IMX_DMATYPE_ESAI; + esai_priv->filter_data_rx.peripheral_type = IMX_DMATYPE_ESAI; + + esai_priv->dma_params_tx.check_xrun = fsl_esai_check_xrun; + esai_priv->dma_params_rx.check_xrun = fsl_esai_check_xrun; + esai_priv->dma_params_tx.device_reset = fsl_esai_reset; + esai_priv->dma_params_rx.device_reset = fsl_esai_reset; + + esai_priv->synchronous = + of_property_read_bool(np, "fsl,esai-synchronous"); - platform_set_drvdata(pdev, esai); + /* Implement full symmetry for synchronous mode */ + if (esai_priv->synchronous) { + fsl_esai_dai.symmetric_rates = 1; + fsl_esai_dai.symmetric_channels = 1; + fsl_esai_dai.symmetric_samplebits = 1; + } - p = strrchr(np->full_name, '/') + 1; - strcpy(esai->name, p); - fsl_esai_dai.name = esai->name; + dev_set_drvdata(&pdev->dev, esai_priv); - ret = snd_soc_register_component(&pdev->dev, &fsl_esai_component, - &fsl_esai_dai, 1); + /* Reset ESAI unit */ + ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST); if (ret) { - dev_err(&pdev->dev, "register DAI failed\n"); - goto failed_register; + dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret); + return ret; } - ret = imx_pcm_dma_init(pdev, SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | - SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_COMPAT, - IMX_ESAI_DMABUF_SIZE); + /* + * We need to enable ESAI so as to access some of its registers. + * Otherwise, we would fail to dump regmap from user space. + */ + ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN); if (ret) { - dev_err(&pdev->dev, "init pcm dma failed\n"); - goto failed_pcm_init; + dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret); + return ret; } - fsl_esai_reg_init(esai); + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component, + &fsl_esai_dai, 1); + if (ret) { + dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); + return ret; + } - return 0; + ret = imx_pcm_dma_init(pdev, SND_DMAENGINE_PCM_FLAG_NO_RESIDUE | + SND_DMAENGINE_PCM_FLAG_NO_DT | + SND_DMAENGINE_PCM_FLAG_COMPAT, + IMX_ESAI_DMABUF_SIZE); + if (ret) + dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); -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 const struct of_device_id fsl_esai_dt_ids[] = { + { .compatible = "fsl,imx35-esai", }, {} }; +MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids); 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, + .of_match_table = fsl_esai_dt_ids, }, }; module_platform_driver(fsl_esai_driver); MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("i.MX ASoC ESAI driver"); +MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver"); +MODULE_LICENSE("GPL v2"); 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 index b2551c530782..9c9f957fcae1 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -1,339 +1,354 @@ /* - * imx-esai.h -- ESAI driver header file for Freescale IMX + * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC * - * Copyright 2008-2014 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: + * Copyright (C) 2014 Freescale Semiconductor, Inc. * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * Author: Nicolin Chen <Guangyu.Chen@freescale.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. */ -#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) +#ifndef _FSL_ESAI_DAI_H +#define _FSL_ESAI_DAI_H + +/* ESAI Register Map */ +#define REG_ESAI_ETDR 0x00 +#define REG_ESAI_ERDR 0x04 +#define REG_ESAI_ECR 0x08 +#define REG_ESAI_ESR 0x0C +#define REG_ESAI_TFCR 0x10 +#define REG_ESAI_TFSR 0x14 +#define REG_ESAI_RFCR 0x18 +#define REG_ESAI_RFSR 0x1C +#define REG_ESAI_xFCR(tx) (tx ? REG_ESAI_TFCR : REG_ESAI_RFCR) +#define REG_ESAI_xFSR(tx) (tx ? REG_ESAI_TFSR : REG_ESAI_RFSR) +#define REG_ESAI_TX0 0x80 +#define REG_ESAI_TX1 0x84 +#define REG_ESAI_TX2 0x88 +#define REG_ESAI_TX3 0x8C +#define REG_ESAI_TX4 0x90 +#define REG_ESAI_TX5 0x94 +#define REG_ESAI_TSR 0x98 +#define REG_ESAI_RX0 0xA0 +#define REG_ESAI_RX1 0xA4 +#define REG_ESAI_RX2 0xA8 +#define REG_ESAI_RX3 0xAC +#define REG_ESAI_SAISR 0xCC +#define REG_ESAI_SAICR 0xD0 +#define REG_ESAI_TCR 0xD4 +#define REG_ESAI_TCCR 0xD8 +#define REG_ESAI_RCR 0xDC +#define REG_ESAI_RCCR 0xE0 +#define REG_ESAI_xCR(tx) (tx ? REG_ESAI_TCR : REG_ESAI_RCR) +#define REG_ESAI_xCCR(tx) (tx ? REG_ESAI_TCCR : REG_ESAI_RCCR) +#define REG_ESAI_TSMA 0xE4 +#define REG_ESAI_TSMB 0xE8 +#define REG_ESAI_RSMA 0xEC +#define REG_ESAI_RSMB 0xF0 +#define REG_ESAI_xSMA(tx) (tx ? REG_ESAI_TSMA : REG_ESAI_RSMA) +#define REG_ESAI_xSMB(tx) (tx ? REG_ESAI_TSMB : REG_ESAI_RSMB) +#define REG_ESAI_PRRC 0xF8 +#define REG_ESAI_PCRC 0xFC + +/* ESAI Control Register -- REG_ESAI_ECR 0x8 */ +#define ESAI_ECR_ETI_SHIFT 19 +#define ESAI_ECR_ETI_MASK (1 << ESAI_ECR_ETI_SHIFT) +#define ESAI_ECR_ETI (1 << ESAI_ECR_ETI_SHIFT) +#define ESAI_ECR_ETO_SHIFT 18 +#define ESAI_ECR_ETO_MASK (1 << ESAI_ECR_ETO_SHIFT) +#define ESAI_ECR_ETO (1 << ESAI_ECR_ETO_SHIFT) +#define ESAI_ECR_ERI_SHIFT 17 +#define ESAI_ECR_ERI_MASK (1 << ESAI_ECR_ERI_SHIFT) +#define ESAI_ECR_ERI (1 << ESAI_ECR_ERI_SHIFT) +#define ESAI_ECR_ERO_SHIFT 16 +#define ESAI_ECR_ERO_MASK (1 << ESAI_ECR_ERO_SHIFT) +#define ESAI_ECR_ERO (1 << ESAI_ECR_ERO_SHIFT) +#define ESAI_ECR_ERST_SHIFT 1 +#define ESAI_ECR_ERST_MASK (1 << ESAI_ECR_ERST_SHIFT) +#define ESAI_ECR_ERST (1 << ESAI_ECR_ERST_SHIFT) +#define ESAI_ECR_ESAIEN_SHIFT 0 +#define ESAI_ECR_ESAIEN_MASK (1 << ESAI_ECR_ESAIEN_SHIFT) +#define ESAI_ECR_ESAIEN (1 << ESAI_ECR_ESAIEN_SHIFT) + +/* ESAI Status Register -- REG_ESAI_ESR 0xC */ +#define ESAI_ESR_TINIT_SHIFT 10 +#define ESAI_ESR_TINIT_MASK (1 << ESAI_ESR_TINIT_SHIFT) +#define ESAI_ESR_TINIT (1 << ESAI_ESR_TINIT_SHIFT) +#define ESAI_ESR_RFF_SHIFT 9 +#define ESAI_ESR_RFF_MASK (1 << ESAI_ESR_RFF_SHIFT) +#define ESAI_ESR_RFF (1 << ESAI_ESR_RFF_SHIFT) +#define ESAI_ESR_TFE_SHIFT 8 +#define ESAI_ESR_TFE_MASK (1 << ESAI_ESR_TFE_SHIFT) +#define ESAI_ESR_TFE (1 << ESAI_ESR_TFE_SHIFT) +#define ESAI_ESR_TLS_SHIFT 7 +#define ESAI_ESR_TLS_MASK (1 << ESAI_ESR_TLS_SHIFT) +#define ESAI_ESR_TLS (1 << ESAI_ESR_TLS_SHIFT) +#define ESAI_ESR_TDE_SHIFT 6 +#define ESAI_ESR_TDE_MASK (1 << ESAI_ESR_TDE_SHIFT) +#define ESAI_ESR_TDE (1 << ESAI_ESR_TDE_SHIFT) +#define ESAI_ESR_TED_SHIFT 5 +#define ESAI_ESR_TED_MASK (1 << ESAI_ESR_TED_SHIFT) +#define ESAI_ESR_TED (1 << ESAI_ESR_TED_SHIFT) +#define ESAI_ESR_TD_SHIFT 4 +#define ESAI_ESR_TD_MASK (1 << ESAI_ESR_TD_SHIFT) +#define ESAI_ESR_TD (1 << ESAI_ESR_TD_SHIFT) +#define ESAI_ESR_RLS_SHIFT 3 +#define ESAI_ESR_RLS_MASK (1 << ESAI_ESR_RLS_SHIFT) +#define ESAI_ESR_RLS (1 << ESAI_ESR_RLS_SHIFT) +#define ESAI_ESR_RDE_SHIFT 2 +#define ESAI_ESR_RDE_MASK (1 << ESAI_ESR_RDE_SHIFT) +#define ESAI_ESR_RDE (1 << ESAI_ESR_RDE_SHIFT) +#define ESAI_ESR_RED_SHIFT 1 +#define ESAI_ESR_RED_MASK (1 << ESAI_ESR_RED_SHIFT) +#define ESAI_ESR_RED (1 << ESAI_ESR_RED_SHIFT) +#define ESAI_ESR_RD_SHIFT 0 +#define ESAI_ESR_RD_MASK (1 << ESAI_ESR_RD_SHIFT) +#define ESAI_ESR_RD (1 << ESAI_ESR_RD_SHIFT) -#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) +/* + * Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10 + * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18 + */ +#define ESAI_xFCR_TIEN_SHIFT 19 +#define ESAI_xFCR_TIEN_MASK (1 << ESAI_xFCR_TIEN_SHIFT) +#define ESAI_xFCR_TIEN (1 << ESAI_xFCR_TIEN_SHIFT) +#define ESAI_xFCR_REXT_SHIFT 19 +#define ESAI_xFCR_REXT_MASK (1 << ESAI_xFCR_REXT_SHIFT) +#define ESAI_xFCR_REXT (1 << ESAI_xFCR_REXT_SHIFT) +#define ESAI_xFCR_xWA_SHIFT 16 +#define ESAI_xFCR_xWA_WIDTH 3 +#define ESAI_xFCR_xWA_MASK (((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT) +#define ESAI_xFCR_xWA(v) (((8 - ((v) >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK) +#define ESAI_xFCR_xFWM_SHIFT 8 +#define ESAI_xFCR_xFWM_WIDTH 8 +#define ESAI_xFCR_xFWM_MASK (((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT) +#define ESAI_xFCR_xFWM(v) ((((v) - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK) +#define ESAI_xFCR_xE_SHIFT 2 +#define ESAI_xFCR_TE_WIDTH 6 +#define ESAI_xFCR_RE_WIDTH 4 +#define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) +#define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) +#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) +#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) +#define ESAI_xFCR_xFR_SHIFT 1 +#define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) +#define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) +#define ESAI_xFCR_xFEN_SHIFT 0 +#define ESAI_xFCR_xFEN_MASK (1 << ESAI_xFCR_xFEN_SHIFT) +#define ESAI_xFCR_xFEN (1 << ESAI_xFCR_xFEN_SHIFT) -#define ESAI_RCCR_RDC_MASK 0xffc1ff -#define ESAI_RCCR_RDC_SHIFT 9 -#define ESAI_RCCR_RDC(x) (((x) & 0x1f) << 9) +/* + * Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14 + * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C + */ +#define ESAI_xFSR_NTFO_SHIFT 12 +#define ESAI_xFSR_NRFI_SHIFT 12 +#define ESAI_xFSR_NTFI_SHIFT 8 +#define ESAI_xFSR_NRFO_SHIFT 8 +#define ESAI_xFSR_NTFx_WIDTH 3 +#define ESAI_xFSR_NRFx_WIDTH 2 +#define ESAI_xFSR_NTFO_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT) +#define ESAI_xFSR_NTFI_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT) +#define ESAI_xFSR_NRFO_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT) +#define ESAI_xFSR_NRFI_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT) +#define ESAI_xFSR_xFCNT_SHIFT 0 +#define ESAI_xFSR_xFCNT_WIDTH 8 +#define ESAI_xFSR_xFCNT_MASK (((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT) + +/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */ +#define ESAI_TSR_SHIFT 0 +#define ESAI_TSR_WIDTH 24 +#define ESAI_TSR_MASK (((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT) + +/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */ +#define ESAI_SAISR_TODFE_SHIFT 17 +#define ESAI_SAISR_TODFE_MASK (1 << ESAI_SAISR_TODFE_SHIFT) +#define ESAI_SAISR_TODFE (1 << ESAI_SAISR_TODFE_SHIFT) +#define ESAI_SAISR_TEDE_SHIFT 16 +#define ESAI_SAISR_TEDE_MASK (1 << ESAI_SAISR_TEDE_SHIFT) +#define ESAI_SAISR_TEDE (1 << ESAI_SAISR_TEDE_SHIFT) +#define ESAI_SAISR_TDE_SHIFT 15 +#define ESAI_SAISR_TDE_MASK (1 << ESAI_SAISR_TDE_SHIFT) +#define ESAI_SAISR_TDE (1 << ESAI_SAISR_TDE_SHIFT) +#define ESAI_SAISR_TUE_SHIFT 14 +#define ESAI_SAISR_TUE_MASK (1 << ESAI_SAISR_TUE_SHIFT) +#define ESAI_SAISR_TUE (1 << ESAI_SAISR_TUE_SHIFT) +#define ESAI_SAISR_TFS_SHIFT 13 +#define ESAI_SAISR_TFS_MASK (1 << ESAI_SAISR_TFS_SHIFT) +#define ESAI_SAISR_TFS (1 << ESAI_SAISR_TFS_SHIFT) +#define ESAI_SAISR_RODF_SHIFT 10 +#define ESAI_SAISR_RODF_MASK (1 << ESAI_SAISR_RODF_SHIFT) +#define ESAI_SAISR_RODF (1 << ESAI_SAISR_RODF_SHIFT) +#define ESAI_SAISR_REDF_SHIFT 9 +#define ESAI_SAISR_REDF_MASK (1 << ESAI_SAISR_REDF_SHIFT) +#define ESAI_SAISR_REDF (1 << ESAI_SAISR_REDF_SHIFT) +#define ESAI_SAISR_RDF_SHIFT 8 +#define ESAI_SAISR_RDF_MASK (1 << ESAI_SAISR_RDF_SHIFT) +#define ESAI_SAISR_RDF (1 << ESAI_SAISR_RDF_SHIFT) +#define ESAI_SAISR_ROE_SHIFT 7 +#define ESAI_SAISR_ROE_MASK (1 << ESAI_SAISR_ROE_SHIFT) +#define ESAI_SAISR_ROE (1 << ESAI_SAISR_ROE_SHIFT) +#define ESAI_SAISR_RFS_SHIFT 6 +#define ESAI_SAISR_RFS_MASK (1 << ESAI_SAISR_RFS_SHIFT) +#define ESAI_SAISR_RFS (1 << ESAI_SAISR_RFS_SHIFT) +#define ESAI_SAISR_IF2_SHIFT 2 +#define ESAI_SAISR_IF2_MASK (1 << ESAI_SAISR_IF2_SHIFT) +#define ESAI_SAISR_IF2 (1 << ESAI_SAISR_IF2_SHIFT) +#define ESAI_SAISR_IF1_SHIFT 1 +#define ESAI_SAISR_IF1_MASK (1 << ESAI_SAISR_IF1_SHIFT) +#define ESAI_SAISR_IF1 (1 << ESAI_SAISR_IF1_SHIFT) +#define ESAI_SAISR_IF0_SHIFT 0 +#define ESAI_SAISR_IF0_MASK (1 << ESAI_SAISR_IF0_SHIFT) +#define ESAI_SAISR_IF0 (1 << ESAI_SAISR_IF0_SHIFT) + +/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */ +#define ESAI_SAICR_ALC_SHIFT 8 +#define ESAI_SAICR_ALC_MASK (1 << ESAI_SAICR_ALC_SHIFT) +#define ESAI_SAICR_ALC (1 << ESAI_SAICR_ALC_SHIFT) +#define ESAI_SAICR_TEBE_SHIFT 7 +#define ESAI_SAICR_TEBE_MASK (1 << ESAI_SAICR_TEBE_SHIFT) +#define ESAI_SAICR_TEBE (1 << ESAI_SAICR_TEBE_SHIFT) +#define ESAI_SAICR_SYNC_SHIFT 6 +#define ESAI_SAICR_SYNC_MASK (1 << ESAI_SAICR_SYNC_SHIFT) +#define ESAI_SAICR_SYNC (1 << ESAI_SAICR_SYNC_SHIFT) +#define ESAI_SAICR_OF2_SHIFT 2 +#define ESAI_SAICR_OF2_MASK (1 << ESAI_SAICR_OF2_SHIFT) +#define ESAI_SAICR_OF2 (1 << ESAI_SAICR_OF2_SHIFT) +#define ESAI_SAICR_OF1_SHIFT 1 +#define ESAI_SAICR_OF1_MASK (1 << ESAI_SAICR_OF1_SHIFT) +#define ESAI_SAICR_OF1 (1 << ESAI_SAICR_OF1_SHIFT) +#define ESAI_SAICR_OF0_SHIFT 0 +#define ESAI_SAICR_OF0_MASK (1 << ESAI_SAICR_OF0_SHIFT) +#define ESAI_SAICR_OF0 (1 << ESAI_SAICR_OF0_SHIFT) -#define ESAI_RCCR_RPM_MASK 0xffff00 -#define ESAI_RCCR_RPM_SHIFT 0 -#define ESAI_RCCR_RPM(x) (x & 0xff) +/* + * Transmit Control Register -- REG_ESAI_TCR 0xD4 + * Receive Control Register -- REG_ESAI_RCR 0xDC + */ +#define ESAI_xCR_xLIE_SHIFT 23 +#define ESAI_xCR_xLIE_MASK (1 << ESAI_xCR_xLIE_SHIFT) +#define ESAI_xCR_xLIE (1 << ESAI_xCR_xLIE_SHIFT) +#define ESAI_xCR_xIE_SHIFT 22 +#define ESAI_xCR_xIE_MASK (1 << ESAI_xCR_xIE_SHIFT) +#define ESAI_xCR_xIE (1 << ESAI_xCR_xIE_SHIFT) +#define ESAI_xCR_xEDIE_SHIFT 21 +#define ESAI_xCR_xEDIE_MASK (1 << ESAI_xCR_xEDIE_SHIFT) +#define ESAI_xCR_xEDIE (1 << ESAI_xCR_xEDIE_SHIFT) +#define ESAI_xCR_xEIE_SHIFT 20 +#define ESAI_xCR_xEIE_MASK (1 << ESAI_xCR_xEIE_SHIFT) +#define ESAI_xCR_xEIE (1 << ESAI_xCR_xEIE_SHIFT) +#define ESAI_xCR_xPR_SHIFT 19 +#define ESAI_xCR_xPR_MASK (1 << ESAI_xCR_xPR_SHIFT) +#define ESAI_xCR_xPR (1 << ESAI_xCR_xPR_SHIFT) +#define ESAI_xCR_PADC_SHIFT 17 +#define ESAI_xCR_PADC_MASK (1 << ESAI_xCR_PADC_SHIFT) +#define ESAI_xCR_PADC (1 << ESAI_xCR_PADC_SHIFT) +#define ESAI_xCR_xFSR_SHIFT 16 +#define ESAI_xCR_xFSR_MASK (1 << ESAI_xCR_xFSR_SHIFT) +#define ESAI_xCR_xFSR (1 << ESAI_xCR_xFSR_SHIFT) +#define ESAI_xCR_xFSL_SHIFT 15 +#define ESAI_xCR_xFSL_MASK (1 << ESAI_xCR_xFSL_SHIFT) +#define ESAI_xCR_xFSL (1 << ESAI_xCR_xFSL_SHIFT) +#define ESAI_xCR_xSWS_SHIFT 10 +#define ESAI_xCR_xSWS_WIDTH 5 +#define ESAI_xCR_xSWS_MASK (((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT) +#define ESAI_xCR_xSWS(s, w) ((w < 24 ? (s - w + ((w - 8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT) +#define ESAI_xCR_xMOD_SHIFT 8 +#define ESAI_xCR_xMOD_WIDTH 2 +#define ESAI_xCR_xMOD_MASK (((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT) +#define ESAI_xCR_xMOD_ONDEMAND (0x1 << ESAI_xCR_xMOD_SHIFT) +#define ESAI_xCR_xMOD_NETWORK (0x1 << ESAI_xCR_xMOD_SHIFT) +#define ESAI_xCR_xMOD_AC97 (0x3 << ESAI_xCR_xMOD_SHIFT) +#define ESAI_xCR_xWA_SHIFT 7 +#define ESAI_xCR_xWA_MASK (1 << ESAI_xCR_xWA_SHIFT) +#define ESAI_xCR_xWA (1 << ESAI_xCR_xWA_SHIFT) +#define ESAI_xCR_xSHFD_SHIFT 6 +#define ESAI_xCR_xSHFD_MASK (1 << ESAI_xCR_xSHFD_SHIFT) +#define ESAI_xCR_xSHFD (1 << ESAI_xCR_xSHFD_SHIFT) +#define ESAI_xCR_xE_SHIFT 0 +#define ESAI_xCR_TE_WIDTH 6 +#define ESAI_xCR_RE_WIDTH 4 +#define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) +#define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) +#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) +#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) -#define ESAI_GPIO_ESAI 0xfff +/* + * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 + * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0 + */ +#define ESAI_xCCR_xHCKD_SHIFT 23 +#define ESAI_xCCR_xHCKD_MASK (1 << ESAI_xCCR_xHCKD_SHIFT) +#define ESAI_xCCR_xHCKD (1 << ESAI_xCCR_xHCKD_SHIFT) +#define ESAI_xCCR_xFSD_SHIFT 22 +#define ESAI_xCCR_xFSD_MASK (1 << ESAI_xCCR_xFSD_SHIFT) +#define ESAI_xCCR_xFSD (1 << ESAI_xCCR_xFSD_SHIFT) +#define ESAI_xCCR_xCKD_SHIFT 21 +#define ESAI_xCCR_xCKD_MASK (1 << ESAI_xCCR_xCKD_SHIFT) +#define ESAI_xCCR_xCKD (1 << ESAI_xCCR_xCKD_SHIFT) +#define ESAI_xCCR_xHCKP_SHIFT 20 +#define ESAI_xCCR_xHCKP_MASK (1 << ESAI_xCCR_xHCKP_SHIFT) +#define ESAI_xCCR_xHCKP (1 << ESAI_xCCR_xHCKP_SHIFT) +#define ESAI_xCCR_xFSP_SHIFT 19 +#define ESAI_xCCR_xFSP_MASK (1 << ESAI_xCCR_xFSP_SHIFT) +#define ESAI_xCCR_xFSP (1 << ESAI_xCCR_xFSP_SHIFT) +#define ESAI_xCCR_xCKP_SHIFT 18 +#define ESAI_xCCR_xCKP_MASK (1 << ESAI_xCCR_xCKP_SHIFT) +#define ESAI_xCCR_xCKP (1 << ESAI_xCCR_xCKP_SHIFT) +#define ESAI_xCCR_xFP_SHIFT 14 +#define ESAI_xCCR_xFP_WIDTH 4 +#define ESAI_xCCR_xFP_MASK (((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT) +#define ESAI_xCCR_xFP(v) ((((v) - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK) +#define ESAI_xCCR_xDC_SHIFT 9 +#define ESAI_xCCR_xDC_WIDTH 4 +#define ESAI_xCCR_xDC_MASK (((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT) +#define ESAI_xCCR_xDC(v) ((((v) - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK) +#define ESAI_xCCR_xPSR_SHIFT 8 +#define ESAI_xCCR_xPSR_MASK (1 << ESAI_xCCR_xPSR_SHIFT) +#define ESAI_xCCR_xPSR_BYPASS (1 << ESAI_xCCR_xPSR_SHIFT) +#define ESAI_xCCR_xPSR_DIV8 (0 << ESAI_xCCR_xPSR_SHIFT) +#define ESAI_xCCR_xPM_SHIFT 0 +#define ESAI_xCCR_xPM_WIDTH 8 +#define ESAI_xCCR_xPM_MASK (((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT) +#define ESAI_xCCR_xPM(v) ((((v) - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK) + +/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 ~ 0xF0 */ +#define ESAI_xSMA_xS_SHIFT 0 +#define ESAI_xSMA_xS_WIDTH 16 +#define ESAI_xSMA_xS_MASK (((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT) +#define ESAI_xSMA_xS(v) ((v) & ESAI_xSMA_xS_MASK) +#define ESAI_xSMB_xS_SHIFT 0 +#define ESAI_xSMB_xS_WIDTH 16 +#define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT) +#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK) + +/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */ +#define ESAI_PRRC_PDC_SHIFT 0 +#define ESAI_PRRC_PDC_WIDTH 12 +#define ESAI_PRRC_PDC_MASK (((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT) +#define ESAI_PRRC_PDC(v) ((v) & ESAI_PRRC_PDC_MASK) + +/* Port C Control Register -- REG_ESAI_PCRC 0xFC */ +#define ESAI_PCRC_PC_SHIFT 0 +#define ESAI_PCRC_PC_WIDTH 12 +#define ESAI_PCRC_PC_MASK (((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT) +#define ESAI_PCRC_PC(v) ((v) & ESAI_PCRC_PC_MASK) + +#define ESAI_GPIO 0xfff /* ESAI clock source */ -#define ESAI_CLK_FSYS 0 -#define ESAI_CLK_EXTAL 1 -#define ESAI_CLK_EXTAL_DIV 2 +#define ESAI_HCKT_FSYS 0 +#define ESAI_HCKT_EXTAL 1 +#define ESAI_HCKR_FSYS 2 +#define ESAI_HCKR_EXTAL 3 /* 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) -#define REG_CACHE_NUM 20 - -struct fsl_esai { - struct clk *clk; - struct clk *dmaclk; - struct clk *extalclk; - 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; - struct snd_pcm_substream *substream[2]; - - char name[32]; - u32 reg_cache[REG_CACHE_NUM]; -}; - -#endif +#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 +#endif /* _FSL_ESAI_DAI_H */ diff --git a/sound/soc/fsl/imx-cs42888.c b/sound/soc/fsl/imx-cs42888.c index a56f4f1984ed..f625cd609853 100644 --- a/sound/soc/fsl/imx-cs42888.c +++ b/sound/soc/fsl/imx-cs42888.c @@ -33,7 +33,6 @@ #define CODEC_CLK_ESAI_HCKT 2 struct imx_priv { - int hw; int fe_p2p_rate; int fe_p2p_width; unsigned int mclk_freq; @@ -43,43 +42,6 @@ struct imx_priv { static struct imx_priv card_priv; -static int imx_cs42888_startup(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct imx_priv *priv = &card_priv; - - if (!cpu_dai->active) - priv->hw = 0; - return 0; -} - -static void imx_cs42888_shutdown(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct imx_priv *priv = &card_priv; - - if (!cpu_dai->active) - priv->hw = 0; -} - -static const struct { - int rate; - int ratio1; - int ratio2; -} sr_vals[] = { - { 32000, 3, 3 }, - { 48000, 3, 3 }, - { 64000, 1, 1 }, - { 96000, 1, 1 }, - { 128000, 1, 1 }, - { 44100, 3, 3 }, - { 88200, 1, 1 }, - { 176400, 0, 0 }, - { 192000, 0, 0 }, -}; - static int imx_cs42888_surround_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -87,47 +49,22 @@ static int imx_cs42888_surround_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct imx_priv *priv = &card_priv; - unsigned int rate = params_rate(params); - unsigned int lrclk_ratio = 0, i; u32 dai_format = 0; - if (priv->hw) - return 0; - - priv->hw = 1; - - for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { - if (sr_vals[i].rate == rate) { - if (priv->codec_mclk & CODEC_CLK_ESAI_HCKT) - lrclk_ratio = sr_vals[i].ratio1; - if (priv->codec_mclk & CODEC_CLK_EXTER_OSC) - lrclk_ratio = sr_vals[i].ratio2; - break; - } - } - if (i == ARRAY_SIZE(sr_vals)) { - dev_err(&priv->pdev->dev, "Unsupported rate %dHz\n", rate); - return -EINVAL; - } - dai_format = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; - - snd_soc_dai_set_sysclk(cpu_dai, ESAI_CLK_EXTAL, + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + snd_soc_dai_set_sysclk(cpu_dai, ESAI_HCKT_EXTAL, + priv->mclk_freq, SND_SOC_CLOCK_OUT); + else + snd_soc_dai_set_sysclk(cpu_dai, ESAI_HCKR_EXTAL, priv->mclk_freq, SND_SOC_CLOCK_OUT); - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PM, 0); - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PM, 0); snd_soc_dai_set_sysclk(codec_dai, 0, priv->mclk_freq, SND_SOC_CLOCK_IN); /* set cpu DAI configuration */ snd_soc_dai_set_fmt(cpu_dai, dai_format); /* set i.MX active slot mask */ snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 32); - /* set the ratio */ - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_PSR, 1); - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_TX_DIV_FP, lrclk_ratio); - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_PSR, 1); - snd_soc_dai_set_clkdiv(cpu_dai, ESAI_RX_DIV_FP, lrclk_ratio); /* set codec DAI configuration */ snd_soc_dai_set_fmt(codec_dai, dai_format); @@ -135,8 +72,6 @@ static int imx_cs42888_surround_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops imx_cs42888_surround_ops = { - .startup = imx_cs42888_startup, - .shutdown = imx_cs42888_shutdown, .hw_params = imx_cs42888_surround_hw_params, }; |