aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolin Chen <Guangyu.Chen@freescale.com>2014-01-10 04:54:06 -0500
committerMark Brown <broonie@linaro.org>2014-01-10 07:52:15 -0500
commit43d24e76b69826ce32292f47060ad78cdd0197fa (patch)
tree102d87faa7583b88b7e1a1216e72dfc2d495f8ef
parent633ff8f8a4393b4a13b94eddd2613198c32035e6 (diff)
ASoC: fsl_esai: Add ESAI CPU DAI driver
This patch implements a device-tree-only CPU DAI driver for Freescale ESAI controller that supports: - 12 channels playback and 8 channels record. [ Some of the inner transmitters and receivers are sharing same group of pins. So the maxmium 12 output or 8 input channels are only valid if there is no pin conflict occurring to it. ] - Independent (asynchronous mode) or shared (synchronous mode) transmit and receive sections with separate or shared internal/external clocks and frame syncs, operating in Master or Slave mode. [ Current ALSA seems not to allow CPU DAI drivers to configure DAI format separately for PLAYBACK and CAPTURE. So this first version only supports the case that uses the same DAI format for both directions. ] - Various DAI formats: I2S, Left-Justified, Right-Justified, DSP-A and DSP-B. - Programmable word length (8, 16, 20 or 24bits) - Flexible selection between system clock or external oscillator as input clock source, programmable internal clock divider and frame sync generation. Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt50
-rw-r--r--sound/soc/fsl/Kconfig3
-rw-r--r--sound/soc/fsl/Makefile2
-rw-r--r--sound/soc/fsl/fsl_esai.c815
-rw-r--r--sound/soc/fsl/fsl_esai.h354
5 files changed, 1224 insertions, 0 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 @@
1Freescale Enhanced Serial Audio Interface (ESAI) Controller
2
3The Enhanced Serial Audio Interface (ESAI) provides a full-duplex serial port
4for serial communication with a variety of serial devices, including industry
5standard codecs, Sony/Phillips Digital Interface (S/PDIF) transceivers, and
6other DSPs. It has up to six transmitters and four receivers.
7
8Required properties:
9
10 - compatible : Compatible list, must contain "fsl,imx35-esai".
11
12 - reg : Offset and length of the register set for the device.
13
14 - interrupts : Contains the spdif interrupt.
15
16 - dmas : Generic dma devicetree binding as described in
17 Documentation/devicetree/bindings/dma/dma.txt.
18
19 - dma-names : Two dmas have to be defined, "tx" and "rx".
20
21 - clocks: Contains an entry for each entry in clock-names.
22
23 - clock-names : Includes the following entries:
24 "core" The core clock used to access registers
25 "extal" The esai baud clock for esai controller used to derive
26 HCK, SCK and FS.
27 "fsys" The system clock derived from ahb clock used to derive
28 HCK, SCK and FS.
29
30 - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
31 This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
32
33 - fsl,esai-synchronous: This is a boolean property. If present, indicating
34 that ESAI would work in the synchronous mode, which means all the settings
35 for Receiving would be duplicated from Transmition related registers.
36
37Example:
38
39esai: esai@02024000 {
40 compatible = "fsl,imx35-esai";
41 reg = <0x02024000 0x4000>;
42 interrupts = <0 51 0x04>;
43 clocks = <&clks 208>, <&clks 118>, <&clks 208>;
44 clock-names = "core", "extal", "fsys";
45 dmas = <&sdma 23 21 0>, <&sdma 24 21 0>;
46 dma-names = "rx", "tx";
47 fsl,fifo-depth = <128>;
48 fsl,esai-synchronous;
49 status = "disabled";
50};
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index ac4fe4ea15a9..f2f39dd13bc7 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -8,6 +8,9 @@ config SND_SOC_FSL_SSI
8config SND_SOC_FSL_SPDIF 8config SND_SOC_FSL_SPDIF
9 tristate 9 tristate
10 10
11config SND_SOC_FSL_ESAI
12 tristate
13
11config SND_SOC_FSL_UTILS 14config SND_SOC_FSL_UTILS
12 tristate 15 tristate
13 16
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index aaccbee17006..b12ad4b9b4da 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -14,11 +14,13 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
14snd-soc-fsl-sai-objs := fsl_sai.o 14snd-soc-fsl-sai-objs := fsl_sai.o
15snd-soc-fsl-ssi-objs := fsl_ssi.o 15snd-soc-fsl-ssi-objs := fsl_ssi.o
16snd-soc-fsl-spdif-objs := fsl_spdif.o 16snd-soc-fsl-spdif-objs := fsl_spdif.o
17snd-soc-fsl-esai-objs := fsl_esai.o
17snd-soc-fsl-utils-objs := fsl_utils.o 18snd-soc-fsl-utils-objs := fsl_utils.o
18snd-soc-fsl-dma-objs := fsl_dma.o 19snd-soc-fsl-dma-objs := fsl_dma.o
19obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o 20obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
20obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o 21obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
21obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o 22obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
23obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
22obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o 24obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
23obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o 25obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
24 26
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
new file mode 100644
index 000000000000..d0c72ed261e7
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.c
@@ -0,0 +1,815 @@
1/*
2 * Freescale ESAI ALSA SoC Digital Audio Interface (DAI) driver
3 *
4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
5 *
6 * This file is licensed under the terms of the GNU General Public License
7 * version 2. This program is licensed "as is" without any warranty of any
8 * kind, whether express or implied.
9 */
10
11#include <linux/clk.h>
12#include <linux/dmaengine.h>
13#include <linux/module.h>
14#include <linux/of_irq.h>
15#include <linux/of_platform.h>
16#include <sound/dmaengine_pcm.h>
17#include <sound/pcm_params.h>
18
19#include "fsl_esai.h"
20#include "imx-pcm.h"
21
22#define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000
23#define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
24 SNDRV_PCM_FMTBIT_S16_LE | \
25 SNDRV_PCM_FMTBIT_S20_3LE | \
26 SNDRV_PCM_FMTBIT_S24_LE)
27
28/**
29 * fsl_esai: ESAI private data
30 *
31 * @dma_params_rx: DMA parameters for receive channel
32 * @dma_params_tx: DMA parameters for transmit channel
33 * @pdev: platform device pointer
34 * @regmap: regmap handler
35 * @coreclk: clock source to access register
36 * @extalclk: esai clock source to derive HCK, SCK and FS
37 * @fsysclk: system clock source to derive HCK, SCK and FS
38 * @fifo_depth: depth of tx/rx FIFO
39 * @slot_width: width of each DAI slot
40 * @hck_rate: clock rate of desired HCKx clock
41 * @sck_div: if using PSR/PM dividers for SCKx clock
42 * @slave_mode: if fully using DAI slave mode
43 * @synchronous: if using tx/rx synchronous mode
44 * @name: driver name
45 */
46struct fsl_esai {
47 struct snd_dmaengine_dai_dma_data dma_params_rx;
48 struct snd_dmaengine_dai_dma_data dma_params_tx;
49 struct platform_device *pdev;
50 struct regmap *regmap;
51 struct clk *coreclk;
52 struct clk *extalclk;
53 struct clk *fsysclk;
54 u32 fifo_depth;
55 u32 slot_width;
56 u32 hck_rate[2];
57 bool sck_div[2];
58 bool slave_mode;
59 bool synchronous;
60 char name[32];
61};
62
63static irqreturn_t esai_isr(int irq, void *devid)
64{
65 struct fsl_esai *esai_priv = (struct fsl_esai *)devid;
66 struct platform_device *pdev = esai_priv->pdev;
67 u32 esr;
68
69 regmap_read(esai_priv->regmap, REG_ESAI_ESR, &esr);
70
71 if (esr & ESAI_ESR_TINIT_MASK)
72 dev_dbg(&pdev->dev, "isr: Transmition Initialized\n");
73
74 if (esr & ESAI_ESR_RFF_MASK)
75 dev_warn(&pdev->dev, "isr: Receiving overrun\n");
76
77 if (esr & ESAI_ESR_TFE_MASK)
78 dev_warn(&pdev->dev, "isr: Transmition underrun\n");
79
80 if (esr & ESAI_ESR_TLS_MASK)
81 dev_dbg(&pdev->dev, "isr: Just transmitted the last slot\n");
82
83 if (esr & ESAI_ESR_TDE_MASK)
84 dev_dbg(&pdev->dev, "isr: Transmition data exception\n");
85
86 if (esr & ESAI_ESR_TED_MASK)
87 dev_dbg(&pdev->dev, "isr: Transmitting even slots\n");
88
89 if (esr & ESAI_ESR_TD_MASK)
90 dev_dbg(&pdev->dev, "isr: Transmitting data\n");
91
92 if (esr & ESAI_ESR_RLS_MASK)
93 dev_dbg(&pdev->dev, "isr: Just received the last slot\n");
94
95 if (esr & ESAI_ESR_RDE_MASK)
96 dev_dbg(&pdev->dev, "isr: Receiving data exception\n");
97
98 if (esr & ESAI_ESR_RED_MASK)
99 dev_dbg(&pdev->dev, "isr: Receiving even slots\n");
100
101 if (esr & ESAI_ESR_RD_MASK)
102 dev_dbg(&pdev->dev, "isr: Receiving data\n");
103
104 return IRQ_HANDLED;
105}
106
107/**
108 * This function is used to calculate the divisors of psr, pm, fp and it is
109 * supposed to be called in set_dai_sysclk() and set_bclk().
110 *
111 * @ratio: desired overall ratio for the paticipating dividers
112 * @usefp: for HCK setting, there is no need to set fp divider
113 * @fp: bypass other dividers by setting fp directly if fp != 0
114 * @tx: current setting is for playback or capture
115 */
116static int fsl_esai_divisor_cal(struct snd_soc_dai *dai, bool tx, u32 ratio,
117 bool usefp, u32 fp)
118{
119 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
120 u32 psr, pm = 999, maxfp, prod, sub, savesub, i, j;
121
122 maxfp = usefp ? 16 : 1;
123
124 if (usefp && fp)
125 goto out_fp;
126
127 if (ratio > 2 * 8 * 256 * maxfp || ratio < 2) {
128 dev_err(dai->dev, "the ratio is out of range (2 ~ %d)\n",
129 2 * 8 * 256 * maxfp);
130 return -EINVAL;
131 } else if (ratio % 2) {
132 dev_err(dai->dev, "the raio must be even if using upper divider\n");
133 return -EINVAL;
134 }
135
136 ratio /= 2;
137
138 psr = ratio <= 256 * maxfp ? ESAI_xCCR_xPSR_BYPASS : ESAI_xCCR_xPSR_DIV8;
139
140 /* Set the max fluctuation -- 0.1% of the max devisor */
141 savesub = (psr ? 1 : 8) * 256 * maxfp / 1000;
142
143 /* Find the best value for PM */
144 for (i = 1; i <= 256; i++) {
145 for (j = 1; j <= maxfp; j++) {
146 /* PSR (1 or 8) * PM (1 ~ 256) * FP (1 ~ 16) */
147 prod = (psr ? 1 : 8) * i * j;
148
149 if (prod == ratio)
150 sub = 0;
151 else if (prod / ratio == 1)
152 sub = prod - ratio;
153 else if (ratio / prod == 1)
154 sub = ratio - prod;
155 else
156 continue;
157
158 /* Calculate the fraction */
159 sub = sub * 1000 / ratio;
160 if (sub < savesub) {
161 savesub = sub;
162 pm = i;
163 fp = j;
164 }
165
166 /* We are lucky */
167 if (savesub == 0)
168 goto out;
169 }
170 }
171
172 if (pm == 999) {
173 dev_err(dai->dev, "failed to calculate proper divisors\n");
174 return -EINVAL;
175 }
176
177out:
178 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
179 ESAI_xCCR_xPSR_MASK | ESAI_xCCR_xPM_MASK,
180 psr | ESAI_xCCR_xPM(pm));
181
182out_fp:
183 /* Bypass fp if not being required */
184 if (maxfp <= 1)
185 return 0;
186
187 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
188 ESAI_xCCR_xFP_MASK, ESAI_xCCR_xFP(fp));
189
190 return 0;
191}
192
193/**
194 * This function mainly configures the clock frequency of MCLK (HCKT/HCKR)
195 *
196 * @Parameters:
197 * clk_id: The clock source of HCKT/HCKR
198 * (Input from outside; output from inside, FSYS or EXTAL)
199 * freq: The required clock rate of HCKT/HCKR
200 * dir: The clock direction of HCKT/HCKR
201 *
202 * Note: If the direction is input, we do not care about clk_id.
203 */
204static int fsl_esai_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
205 unsigned int freq, int dir)
206{
207 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
208 struct clk *clksrc = esai_priv->extalclk;
209 bool tx = clk_id <= ESAI_HCKT_EXTAL;
210 bool in = dir == SND_SOC_CLOCK_IN;
211 u32 ret, ratio, ecr = 0;
212 unsigned long clk_rate;
213
214 /* sck_div can be only bypassed if ETO/ERO=0 and SNC_SOC_CLOCK_OUT */
215 esai_priv->sck_div[tx] = true;
216
217 /* Set the direction of HCKT/HCKR pins */
218 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCCR(tx),
219 ESAI_xCCR_xHCKD, in ? 0 : ESAI_xCCR_xHCKD);
220
221 if (in)
222 goto out;
223
224 switch (clk_id) {
225 case ESAI_HCKT_FSYS:
226 case ESAI_HCKR_FSYS:
227 clksrc = esai_priv->fsysclk;
228 break;
229 case ESAI_HCKT_EXTAL:
230 ecr |= ESAI_ECR_ETI;
231 case ESAI_HCKR_EXTAL:
232 ecr |= ESAI_ECR_ERI;
233 break;
234 default:
235 return -EINVAL;
236 }
237
238 if (IS_ERR(clksrc)) {
239 dev_err(dai->dev, "no assigned %s clock\n",
240 clk_id % 2 ? "extal" : "fsys");
241 return PTR_ERR(clksrc);
242 }
243 clk_rate = clk_get_rate(clksrc);
244
245 ratio = clk_rate / freq;
246 if (ratio * freq > clk_rate)
247 ret = ratio * freq - clk_rate;
248 else if (ratio * freq < clk_rate)
249 ret = clk_rate - ratio * freq;
250 else
251 ret = 0;
252
253 /* Block if clock source can not be divided into the required rate */
254 if (ret != 0 && clk_rate / ret < 1000) {
255 dev_err(dai->dev, "failed to derive required HCK%c rate\n",
256 tx ? 'T' : 'R');
257 return -EINVAL;
258 }
259
260 if (ratio == 1) {
261 /* Bypass all the dividers if not being needed */
262 ecr |= tx ? ESAI_ECR_ETO : ESAI_ECR_ERO;
263 goto out;
264 }
265
266 ret = fsl_esai_divisor_cal(dai, tx, ratio, false, 0);
267 if (ret)
268 return ret;
269
270 esai_priv->sck_div[tx] = false;
271
272out:
273 esai_priv->hck_rate[tx] = freq;
274
275 regmap_update_bits(esai_priv->regmap, REG_ESAI_ECR,
276 tx ? ESAI_ECR_ETI | ESAI_ECR_ETO :
277 ESAI_ECR_ERI | ESAI_ECR_ERO, ecr);
278
279 return 0;
280}
281
282/**
283 * This function configures the related dividers according to the bclk rate
284 */
285static int fsl_esai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
286{
287 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
288 u32 hck_rate = esai_priv->hck_rate[tx];
289 u32 sub, ratio = hck_rate / freq;
290
291 /* Don't apply for fully slave mode*/
292 if (esai_priv->slave_mode)
293 return 0;
294
295 if (ratio * freq > hck_rate)
296 sub = ratio * freq - hck_rate;
297 else if (ratio * freq < hck_rate)
298 sub = hck_rate - ratio * freq;
299 else
300 sub = 0;
301
302 /* Block if clock source can not be divided into the required rate */
303 if (sub != 0 && hck_rate / sub < 1000) {
304 dev_err(dai->dev, "failed to derive required SCK%c rate\n",
305 tx ? 'T' : 'R');
306 return -EINVAL;
307 }
308
309 if (esai_priv->sck_div[tx] && (ratio > 16 || ratio == 0)) {
310 dev_err(dai->dev, "the ratio is out of range (1 ~ 16)\n");
311 return -EINVAL;
312 }
313
314 return fsl_esai_divisor_cal(dai, tx, ratio, true,
315 esai_priv->sck_div[tx] ? 0 : ratio);
316}
317
318static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask,
319 u32 rx_mask, int slots, int slot_width)
320{
321 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
322
323 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
324 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
325
326 regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA,
327 ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask));
328 regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB,
329 ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask));
330
331 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
332 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots));
333
334 regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA,
335 ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask));
336 regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB,
337 ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask));
338
339 esai_priv->slot_width = slot_width;
340
341 return 0;
342}
343
344static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
345{
346 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
347 u32 xcr = 0, xccr = 0, mask;
348
349 /* DAI mode */
350 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
351 case SND_SOC_DAIFMT_I2S:
352 /* Data on rising edge of bclk, frame low, 1clk before data */
353 xcr |= ESAI_xCR_xFSR;
354 xccr |= ESAI_xCCR_xFSP | ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
355 break;
356 case SND_SOC_DAIFMT_LEFT_J:
357 /* Data on rising edge of bclk, frame high */
358 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
359 break;
360 case SND_SOC_DAIFMT_RIGHT_J:
361 /* Data on rising edge of bclk, frame high, right aligned */
362 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCR_xWA;
363 break;
364 case SND_SOC_DAIFMT_DSP_A:
365 /* Data on rising edge of bclk, frame high, 1clk before data */
366 xcr |= ESAI_xCR_xFSL | ESAI_xCR_xFSR;
367 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
368 break;
369 case SND_SOC_DAIFMT_DSP_B:
370 /* Data on rising edge of bclk, frame high */
371 xcr |= ESAI_xCR_xFSL;
372 xccr |= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
373 break;
374 default:
375 return -EINVAL;
376 }
377
378 /* DAI clock inversion */
379 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
380 case SND_SOC_DAIFMT_NB_NF:
381 /* Nothing to do for both normal cases */
382 break;
383 case SND_SOC_DAIFMT_IB_NF:
384 /* Invert bit clock */
385 xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP;
386 break;
387 case SND_SOC_DAIFMT_NB_IF:
388 /* Invert frame clock */
389 xccr ^= ESAI_xCCR_xFSP;
390 break;
391 case SND_SOC_DAIFMT_IB_IF:
392 /* Invert both clocks */
393 xccr ^= ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP;
394 break;
395 default:
396 return -EINVAL;
397 }
398
399 esai_priv->slave_mode = false;
400
401 /* DAI clock master masks */
402 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
403 case SND_SOC_DAIFMT_CBM_CFM:
404 esai_priv->slave_mode = true;
405 break;
406 case SND_SOC_DAIFMT_CBS_CFM:
407 xccr |= ESAI_xCCR_xCKD;
408 break;
409 case SND_SOC_DAIFMT_CBM_CFS:
410 xccr |= ESAI_xCCR_xFSD;
411 break;
412 case SND_SOC_DAIFMT_CBS_CFS:
413 xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD;
414 break;
415 default:
416 return -EINVAL;
417 }
418
419 mask = ESAI_xCR_xFSL | ESAI_xCR_xFSR;
420 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, xcr);
421 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCR, mask, xcr);
422
423 mask = ESAI_xCCR_xCKP | ESAI_xCCR_xHCKP | ESAI_xCCR_xFSP |
424 ESAI_xCCR_xFSD | ESAI_xCCR_xCKD | ESAI_xCR_xWA;
425 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR, mask, xccr);
426 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, mask, xccr);
427
428 return 0;
429}
430
431static int fsl_esai_startup(struct snd_pcm_substream *substream,
432 struct snd_soc_dai *dai)
433{
434 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
435
436 /*
437 * Some platforms might use the same bit to gate all three or two of
438 * clocks, so keep all clocks open/close at the same time for safety
439 */
440 clk_prepare_enable(esai_priv->coreclk);
441 if (!IS_ERR(esai_priv->extalclk))
442 clk_prepare_enable(esai_priv->extalclk);
443 if (!IS_ERR(esai_priv->fsysclk))
444 clk_prepare_enable(esai_priv->fsysclk);
445
446 if (!dai->active) {
447 /* Reset Port C */
448 regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
449 ESAI_PRRC_PDC_MASK, ESAI_PRRC_PDC(ESAI_GPIO));
450 regmap_update_bits(esai_priv->regmap, REG_ESAI_PCRC,
451 ESAI_PCRC_PC_MASK, ESAI_PCRC_PC(ESAI_GPIO));
452
453 /* Set synchronous mode */
454 regmap_update_bits(esai_priv->regmap, REG_ESAI_SAICR,
455 ESAI_SAICR_SYNC, esai_priv->synchronous ?
456 ESAI_SAICR_SYNC : 0);
457
458 /* Set a default slot number -- 2 */
459 regmap_update_bits(esai_priv->regmap, REG_ESAI_TCCR,
460 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
461 regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR,
462 ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(2));
463 }
464
465 return 0;
466}
467
468static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
469 struct snd_pcm_hw_params *params,
470 struct snd_soc_dai *dai)
471{
472 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
473 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
474 u32 width = snd_pcm_format_width(params_format(params));
475 u32 channels = params_channels(params);
476 u32 bclk, mask, val, ret;
477
478 bclk = params_rate(params) * esai_priv->slot_width * 2;
479
480 ret = fsl_esai_set_bclk(dai, tx, bclk);
481 if (ret)
482 return ret;
483
484 /* Use Normal mode to support monaural audio */
485 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
486 ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
487 ESAI_xCR_xMOD_NETWORK : 0);
488
489 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
490 ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
491
492 mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK |
493 (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK);
494 val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) |
495 (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels));
496
497 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
498
499 mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
500 val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
501
502 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
503
504 return 0;
505}
506
507static void fsl_esai_shutdown(struct snd_pcm_substream *substream,
508 struct snd_soc_dai *dai)
509{
510 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
511
512 if (!IS_ERR(esai_priv->fsysclk))
513 clk_disable_unprepare(esai_priv->fsysclk);
514 if (!IS_ERR(esai_priv->extalclk))
515 clk_disable_unprepare(esai_priv->extalclk);
516 clk_disable_unprepare(esai_priv->coreclk);
517}
518
519static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd,
520 struct snd_soc_dai *dai)
521{
522 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
523 bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
524 u8 i, channels = substream->runtime->channels;
525
526 switch (cmd) {
527 case SNDRV_PCM_TRIGGER_START:
528 case SNDRV_PCM_TRIGGER_RESUME:
529 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
530 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
531 ESAI_xFCR_xFEN_MASK, ESAI_xFCR_xFEN);
532
533 /* Write initial words reqiured by ESAI as normal procedure */
534 for (i = 0; tx && i < channels; i++)
535 regmap_write(esai_priv->regmap, REG_ESAI_ETDR, 0x0);
536
537 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
538 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK,
539 tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels));
540 break;
541 case SNDRV_PCM_TRIGGER_SUSPEND:
542 case SNDRV_PCM_TRIGGER_STOP:
543 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
544 regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
545 tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, 0);
546
547 /* Disable and reset FIFO */
548 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
549 ESAI_xFCR_xFR | ESAI_xFCR_xFEN, ESAI_xFCR_xFR);
550 regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
551 ESAI_xFCR_xFR, 0);
552 break;
553 default:
554 return -EINVAL;
555 }
556
557 return 0;
558}
559
560static struct snd_soc_dai_ops fsl_esai_dai_ops = {
561 .startup = fsl_esai_startup,
562 .shutdown = fsl_esai_shutdown,
563 .trigger = fsl_esai_trigger,
564 .hw_params = fsl_esai_hw_params,
565 .set_sysclk = fsl_esai_set_dai_sysclk,
566 .set_fmt = fsl_esai_set_dai_fmt,
567 .set_tdm_slot = fsl_esai_set_dai_tdm_slot,
568};
569
570static int fsl_esai_dai_probe(struct snd_soc_dai *dai)
571{
572 struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai);
573
574 snd_soc_dai_init_dma_data(dai, &esai_priv->dma_params_tx,
575 &esai_priv->dma_params_rx);
576
577 return 0;
578}
579
580static struct snd_soc_dai_driver fsl_esai_dai = {
581 .probe = fsl_esai_dai_probe,
582 .playback = {
583 .channels_min = 1,
584 .channels_max = 12,
585 .rates = FSL_ESAI_RATES,
586 .formats = FSL_ESAI_FORMATS,
587 },
588 .capture = {
589 .channels_min = 1,
590 .channels_max = 8,
591 .rates = FSL_ESAI_RATES,
592 .formats = FSL_ESAI_FORMATS,
593 },
594 .ops = &fsl_esai_dai_ops,
595};
596
597static const struct snd_soc_component_driver fsl_esai_component = {
598 .name = "fsl-esai",
599};
600
601static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg)
602{
603 switch (reg) {
604 case REG_ESAI_ERDR:
605 case REG_ESAI_ECR:
606 case REG_ESAI_ESR:
607 case REG_ESAI_TFCR:
608 case REG_ESAI_TFSR:
609 case REG_ESAI_RFCR:
610 case REG_ESAI_RFSR:
611 case REG_ESAI_RX0:
612 case REG_ESAI_RX1:
613 case REG_ESAI_RX2:
614 case REG_ESAI_RX3:
615 case REG_ESAI_SAISR:
616 case REG_ESAI_SAICR:
617 case REG_ESAI_TCR:
618 case REG_ESAI_TCCR:
619 case REG_ESAI_RCR:
620 case REG_ESAI_RCCR:
621 case REG_ESAI_TSMA:
622 case REG_ESAI_TSMB:
623 case REG_ESAI_RSMA:
624 case REG_ESAI_RSMB:
625 case REG_ESAI_PRRC:
626 case REG_ESAI_PCRC:
627 return true;
628 default:
629 return false;
630 }
631}
632
633static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg)
634{
635 switch (reg) {
636 case REG_ESAI_ETDR:
637 case REG_ESAI_ECR:
638 case REG_ESAI_TFCR:
639 case REG_ESAI_RFCR:
640 case REG_ESAI_TX0:
641 case REG_ESAI_TX1:
642 case REG_ESAI_TX2:
643 case REG_ESAI_TX3:
644 case REG_ESAI_TX4:
645 case REG_ESAI_TX5:
646 case REG_ESAI_TSR:
647 case REG_ESAI_SAICR:
648 case REG_ESAI_TCR:
649 case REG_ESAI_TCCR:
650 case REG_ESAI_RCR:
651 case REG_ESAI_RCCR:
652 case REG_ESAI_TSMA:
653 case REG_ESAI_TSMB:
654 case REG_ESAI_RSMA:
655 case REG_ESAI_RSMB:
656 case REG_ESAI_PRRC:
657 case REG_ESAI_PCRC:
658 return true;
659 default:
660 return false;
661 }
662}
663
664static const struct regmap_config fsl_esai_regmap_config = {
665 .reg_bits = 32,
666 .reg_stride = 4,
667 .val_bits = 32,
668
669 .max_register = REG_ESAI_PCRC,
670 .readable_reg = fsl_esai_readable_reg,
671 .writeable_reg = fsl_esai_writeable_reg,
672};
673
674static int fsl_esai_probe(struct platform_device *pdev)
675{
676 struct device_node *np = pdev->dev.of_node;
677 struct fsl_esai *esai_priv;
678 struct resource *res;
679 const uint32_t *iprop;
680 void __iomem *regs;
681 int irq, ret;
682
683 esai_priv = devm_kzalloc(&pdev->dev, sizeof(*esai_priv), GFP_KERNEL);
684 if (!esai_priv)
685 return -ENOMEM;
686
687 esai_priv->pdev = pdev;
688 strcpy(esai_priv->name, np->name);
689
690 /* Get the addresses and IRQ */
691 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
692 regs = devm_ioremap_resource(&pdev->dev, res);
693 if (IS_ERR(regs))
694 return PTR_ERR(regs);
695
696 esai_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
697 "core", regs, &fsl_esai_regmap_config);
698 if (IS_ERR(esai_priv->regmap)) {
699 dev_err(&pdev->dev, "failed to init regmap: %ld\n",
700 PTR_ERR(esai_priv->regmap));
701 return PTR_ERR(esai_priv->regmap);
702 }
703
704 esai_priv->coreclk = devm_clk_get(&pdev->dev, "core");
705 if (IS_ERR(esai_priv->coreclk)) {
706 dev_err(&pdev->dev, "failed to get core clock: %ld\n",
707 PTR_ERR(esai_priv->coreclk));
708 return PTR_ERR(esai_priv->coreclk);
709 }
710
711 esai_priv->extalclk = devm_clk_get(&pdev->dev, "extal");
712 if (IS_ERR(esai_priv->extalclk))
713 dev_warn(&pdev->dev, "failed to get extal clock: %ld\n",
714 PTR_ERR(esai_priv->extalclk));
715
716 esai_priv->fsysclk = devm_clk_get(&pdev->dev, "fsys");
717 if (IS_ERR(esai_priv->fsysclk))
718 dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n",
719 PTR_ERR(esai_priv->fsysclk));
720
721 irq = platform_get_irq(pdev, 0);
722 if (irq < 0) {
723 dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
724 return irq;
725 }
726
727 ret = devm_request_irq(&pdev->dev, irq, esai_isr, 0,
728 esai_priv->name, esai_priv);
729 if (ret) {
730 dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
731 return ret;
732 }
733
734 /* Set a default slot size */
735 esai_priv->slot_width = 32;
736
737 /* Set a default master/slave state */
738 esai_priv->slave_mode = true;
739
740 /* Determine the FIFO depth */
741 iprop = of_get_property(np, "fsl,fifo-depth", NULL);
742 if (iprop)
743 esai_priv->fifo_depth = be32_to_cpup(iprop);
744 else
745 esai_priv->fifo_depth = 64;
746
747 esai_priv->dma_params_tx.maxburst = 16;
748 esai_priv->dma_params_rx.maxburst = 16;
749 esai_priv->dma_params_tx.addr = res->start + REG_ESAI_ETDR;
750 esai_priv->dma_params_rx.addr = res->start + REG_ESAI_ERDR;
751
752 esai_priv->synchronous =
753 of_property_read_bool(np, "fsl,esai-synchronous");
754
755 /* Implement full symmetry for synchronous mode */
756 if (esai_priv->synchronous) {
757 fsl_esai_dai.symmetric_rates = 1;
758 fsl_esai_dai.symmetric_channels = 1;
759 fsl_esai_dai.symmetric_samplebits = 1;
760 }
761
762 dev_set_drvdata(&pdev->dev, esai_priv);
763
764 /* Reset ESAI unit */
765 ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ERST);
766 if (ret) {
767 dev_err(&pdev->dev, "failed to reset ESAI: %d\n", ret);
768 return ret;
769 }
770
771 /*
772 * We need to enable ESAI so as to access some of its registers.
773 * Otherwise, we would fail to dump regmap from user space.
774 */
775 ret = regmap_write(esai_priv->regmap, REG_ESAI_ECR, ESAI_ECR_ESAIEN);
776 if (ret) {
777 dev_err(&pdev->dev, "failed to enable ESAI: %d\n", ret);
778 return ret;
779 }
780
781 ret = devm_snd_soc_register_component(&pdev->dev, &fsl_esai_component,
782 &fsl_esai_dai, 1);
783 if (ret) {
784 dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
785 return ret;
786 }
787
788 ret = imx_pcm_dma_init(pdev);
789 if (ret)
790 dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret);
791
792 return ret;
793}
794
795static const struct of_device_id fsl_esai_dt_ids[] = {
796 { .compatible = "fsl,imx35-esai", },
797 {}
798};
799MODULE_DEVICE_TABLE(of, fsl_esai_dt_ids);
800
801static struct platform_driver fsl_esai_driver = {
802 .probe = fsl_esai_probe,
803 .driver = {
804 .name = "fsl-esai-dai",
805 .owner = THIS_MODULE,
806 .of_match_table = fsl_esai_dt_ids,
807 },
808};
809
810module_platform_driver(fsl_esai_driver);
811
812MODULE_AUTHOR("Freescale Semiconductor, Inc.");
813MODULE_DESCRIPTION("Freescale ESAI CPU DAI driver");
814MODULE_LICENSE("GPL v2");
815MODULE_ALIAS("platform:fsl-esai-dai");
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h
new file mode 100644
index 000000000000..9c9f957fcae1
--- /dev/null
+++ b/sound/soc/fsl/fsl_esai.h
@@ -0,0 +1,354 @@
1/*
2 * fsl_esai.h - ALSA ESAI interface for the Freescale i.MX SoC
3 *
4 * Copyright (C) 2014 Freescale Semiconductor, Inc.
5 *
6 * Author: Nicolin Chen <Guangyu.Chen@freescale.com>
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#ifndef _FSL_ESAI_DAI_H
14#define _FSL_ESAI_DAI_H
15
16/* ESAI Register Map */
17#define REG_ESAI_ETDR 0x00
18#define REG_ESAI_ERDR 0x04
19#define REG_ESAI_ECR 0x08
20#define REG_ESAI_ESR 0x0C
21#define REG_ESAI_TFCR 0x10
22#define REG_ESAI_TFSR 0x14
23#define REG_ESAI_RFCR 0x18
24#define REG_ESAI_RFSR 0x1C
25#define REG_ESAI_xFCR(tx) (tx ? REG_ESAI_TFCR : REG_ESAI_RFCR)
26#define REG_ESAI_xFSR(tx) (tx ? REG_ESAI_TFSR : REG_ESAI_RFSR)
27#define REG_ESAI_TX0 0x80
28#define REG_ESAI_TX1 0x84
29#define REG_ESAI_TX2 0x88
30#define REG_ESAI_TX3 0x8C
31#define REG_ESAI_TX4 0x90
32#define REG_ESAI_TX5 0x94
33#define REG_ESAI_TSR 0x98
34#define REG_ESAI_RX0 0xA0
35#define REG_ESAI_RX1 0xA4
36#define REG_ESAI_RX2 0xA8
37#define REG_ESAI_RX3 0xAC
38#define REG_ESAI_SAISR 0xCC
39#define REG_ESAI_SAICR 0xD0
40#define REG_ESAI_TCR 0xD4
41#define REG_ESAI_TCCR 0xD8
42#define REG_ESAI_RCR 0xDC
43#define REG_ESAI_RCCR 0xE0
44#define REG_ESAI_xCR(tx) (tx ? REG_ESAI_TCR : REG_ESAI_RCR)
45#define REG_ESAI_xCCR(tx) (tx ? REG_ESAI_TCCR : REG_ESAI_RCCR)
46#define REG_ESAI_TSMA 0xE4
47#define REG_ESAI_TSMB 0xE8
48#define REG_ESAI_RSMA 0xEC
49#define REG_ESAI_RSMB 0xF0
50#define REG_ESAI_xSMA(tx) (tx ? REG_ESAI_TSMA : REG_ESAI_RSMA)
51#define REG_ESAI_xSMB(tx) (tx ? REG_ESAI_TSMB : REG_ESAI_RSMB)
52#define REG_ESAI_PRRC 0xF8
53#define REG_ESAI_PCRC 0xFC
54
55/* ESAI Control Register -- REG_ESAI_ECR 0x8 */
56#define ESAI_ECR_ETI_SHIFT 19
57#define ESAI_ECR_ETI_MASK (1 << ESAI_ECR_ETI_SHIFT)
58#define ESAI_ECR_ETI (1 << ESAI_ECR_ETI_SHIFT)
59#define ESAI_ECR_ETO_SHIFT 18
60#define ESAI_ECR_ETO_MASK (1 << ESAI_ECR_ETO_SHIFT)
61#define ESAI_ECR_ETO (1 << ESAI_ECR_ETO_SHIFT)
62#define ESAI_ECR_ERI_SHIFT 17
63#define ESAI_ECR_ERI_MASK (1 << ESAI_ECR_ERI_SHIFT)
64#define ESAI_ECR_ERI (1 << ESAI_ECR_ERI_SHIFT)
65#define ESAI_ECR_ERO_SHIFT 16
66#define ESAI_ECR_ERO_MASK (1 << ESAI_ECR_ERO_SHIFT)
67#define ESAI_ECR_ERO (1 << ESAI_ECR_ERO_SHIFT)
68#define ESAI_ECR_ERST_SHIFT 1
69#define ESAI_ECR_ERST_MASK (1 << ESAI_ECR_ERST_SHIFT)
70#define ESAI_ECR_ERST (1 << ESAI_ECR_ERST_SHIFT)
71#define ESAI_ECR_ESAIEN_SHIFT 0
72#define ESAI_ECR_ESAIEN_MASK (1 << ESAI_ECR_ESAIEN_SHIFT)
73#define ESAI_ECR_ESAIEN (1 << ESAI_ECR_ESAIEN_SHIFT)
74
75/* ESAI Status Register -- REG_ESAI_ESR 0xC */
76#define ESAI_ESR_TINIT_SHIFT 10
77#define ESAI_ESR_TINIT_MASK (1 << ESAI_ESR_TINIT_SHIFT)
78#define ESAI_ESR_TINIT (1 << ESAI_ESR_TINIT_SHIFT)
79#define ESAI_ESR_RFF_SHIFT 9
80#define ESAI_ESR_RFF_MASK (1 << ESAI_ESR_RFF_SHIFT)
81#define ESAI_ESR_RFF (1 << ESAI_ESR_RFF_SHIFT)
82#define ESAI_ESR_TFE_SHIFT 8
83#define ESAI_ESR_TFE_MASK (1 << ESAI_ESR_TFE_SHIFT)
84#define ESAI_ESR_TFE (1 << ESAI_ESR_TFE_SHIFT)
85#define ESAI_ESR_TLS_SHIFT 7
86#define ESAI_ESR_TLS_MASK (1 << ESAI_ESR_TLS_SHIFT)
87#define ESAI_ESR_TLS (1 << ESAI_ESR_TLS_SHIFT)
88#define ESAI_ESR_TDE_SHIFT 6
89#define ESAI_ESR_TDE_MASK (1 << ESAI_ESR_TDE_SHIFT)
90#define ESAI_ESR_TDE (1 << ESAI_ESR_TDE_SHIFT)
91#define ESAI_ESR_TED_SHIFT 5
92#define ESAI_ESR_TED_MASK (1 << ESAI_ESR_TED_SHIFT)
93#define ESAI_ESR_TED (1 << ESAI_ESR_TED_SHIFT)
94#define ESAI_ESR_TD_SHIFT 4
95#define ESAI_ESR_TD_MASK (1 << ESAI_ESR_TD_SHIFT)
96#define ESAI_ESR_TD (1 << ESAI_ESR_TD_SHIFT)
97#define ESAI_ESR_RLS_SHIFT 3
98#define ESAI_ESR_RLS_MASK (1 << ESAI_ESR_RLS_SHIFT)
99#define ESAI_ESR_RLS (1 << ESAI_ESR_RLS_SHIFT)
100#define ESAI_ESR_RDE_SHIFT 2
101#define ESAI_ESR_RDE_MASK (1 << ESAI_ESR_RDE_SHIFT)
102#define ESAI_ESR_RDE (1 << ESAI_ESR_RDE_SHIFT)
103#define ESAI_ESR_RED_SHIFT 1
104#define ESAI_ESR_RED_MASK (1 << ESAI_ESR_RED_SHIFT)
105#define ESAI_ESR_RED (1 << ESAI_ESR_RED_SHIFT)
106#define ESAI_ESR_RD_SHIFT 0
107#define ESAI_ESR_RD_MASK (1 << ESAI_ESR_RD_SHIFT)
108#define ESAI_ESR_RD (1 << ESAI_ESR_RD_SHIFT)
109
110/*
111 * Transmit FIFO Configuration Register -- REG_ESAI_TFCR 0x10
112 * Receive FIFO Configuration Register -- REG_ESAI_RFCR 0x18
113 */
114#define ESAI_xFCR_TIEN_SHIFT 19
115#define ESAI_xFCR_TIEN_MASK (1 << ESAI_xFCR_TIEN_SHIFT)
116#define ESAI_xFCR_TIEN (1 << ESAI_xFCR_TIEN_SHIFT)
117#define ESAI_xFCR_REXT_SHIFT 19
118#define ESAI_xFCR_REXT_MASK (1 << ESAI_xFCR_REXT_SHIFT)
119#define ESAI_xFCR_REXT (1 << ESAI_xFCR_REXT_SHIFT)
120#define ESAI_xFCR_xWA_SHIFT 16
121#define ESAI_xFCR_xWA_WIDTH 3
122#define ESAI_xFCR_xWA_MASK (((1 << ESAI_xFCR_xWA_WIDTH) - 1) << ESAI_xFCR_xWA_SHIFT)
123#define ESAI_xFCR_xWA(v) (((8 - ((v) >> 2)) << ESAI_xFCR_xWA_SHIFT) & ESAI_xFCR_xWA_MASK)
124#define ESAI_xFCR_xFWM_SHIFT 8
125#define ESAI_xFCR_xFWM_WIDTH 8
126#define ESAI_xFCR_xFWM_MASK (((1 << ESAI_xFCR_xFWM_WIDTH) - 1) << ESAI_xFCR_xFWM_SHIFT)
127#define ESAI_xFCR_xFWM(v) ((((v) - 1) << ESAI_xFCR_xFWM_SHIFT) & ESAI_xFCR_xFWM_MASK)
128#define ESAI_xFCR_xE_SHIFT 2
129#define ESAI_xFCR_TE_WIDTH 6
130#define ESAI_xFCR_RE_WIDTH 4
131#define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
132#define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT)
133#define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK)
134#define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK)
135#define ESAI_xFCR_xFR_SHIFT 1
136#define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT)
137#define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT)
138#define ESAI_xFCR_xFEN_SHIFT 0
139#define ESAI_xFCR_xFEN_MASK (1 << ESAI_xFCR_xFEN_SHIFT)
140#define ESAI_xFCR_xFEN (1 << ESAI_xFCR_xFEN_SHIFT)
141
142/*
143 * Transmit FIFO Status Register -- REG_ESAI_TFSR 0x14
144 * Receive FIFO Status Register --REG_ESAI_RFSR 0x1C
145 */
146#define ESAI_xFSR_NTFO_SHIFT 12
147#define ESAI_xFSR_NRFI_SHIFT 12
148#define ESAI_xFSR_NTFI_SHIFT 8
149#define ESAI_xFSR_NRFO_SHIFT 8
150#define ESAI_xFSR_NTFx_WIDTH 3
151#define ESAI_xFSR_NRFx_WIDTH 2
152#define ESAI_xFSR_NTFO_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFO_SHIFT)
153#define ESAI_xFSR_NTFI_MASK (((1 << ESAI_xFSR_NTFx_WIDTH) - 1) << ESAI_xFSR_NTFI_SHIFT)
154#define ESAI_xFSR_NRFO_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFO_SHIFT)
155#define ESAI_xFSR_NRFI_MASK (((1 << ESAI_xFSR_NRFx_WIDTH) - 1) << ESAI_xFSR_NRFI_SHIFT)
156#define ESAI_xFSR_xFCNT_SHIFT 0
157#define ESAI_xFSR_xFCNT_WIDTH 8
158#define ESAI_xFSR_xFCNT_MASK (((1 << ESAI_xFSR_xFCNT_WIDTH) - 1) << ESAI_xFSR_xFCNT_SHIFT)
159
160/* ESAI Transmit Slot Register -- REG_ESAI_TSR 0x98 */
161#define ESAI_TSR_SHIFT 0
162#define ESAI_TSR_WIDTH 24
163#define ESAI_TSR_MASK (((1 << ESAI_TSR_WIDTH) - 1) << ESAI_TSR_SHIFT)
164
165/* Serial Audio Interface Status Register -- REG_ESAI_SAISR 0xCC */
166#define ESAI_SAISR_TODFE_SHIFT 17
167#define ESAI_SAISR_TODFE_MASK (1 << ESAI_SAISR_TODFE_SHIFT)
168#define ESAI_SAISR_TODFE (1 << ESAI_SAISR_TODFE_SHIFT)
169#define ESAI_SAISR_TEDE_SHIFT 16
170#define ESAI_SAISR_TEDE_MASK (1 << ESAI_SAISR_TEDE_SHIFT)
171#define ESAI_SAISR_TEDE (1 << ESAI_SAISR_TEDE_SHIFT)
172#define ESAI_SAISR_TDE_SHIFT 15
173#define ESAI_SAISR_TDE_MASK (1 << ESAI_SAISR_TDE_SHIFT)
174#define ESAI_SAISR_TDE (1 << ESAI_SAISR_TDE_SHIFT)
175#define ESAI_SAISR_TUE_SHIFT 14
176#define ESAI_SAISR_TUE_MASK (1 << ESAI_SAISR_TUE_SHIFT)
177#define ESAI_SAISR_TUE (1 << ESAI_SAISR_TUE_SHIFT)
178#define ESAI_SAISR_TFS_SHIFT 13
179#define ESAI_SAISR_TFS_MASK (1 << ESAI_SAISR_TFS_SHIFT)
180#define ESAI_SAISR_TFS (1 << ESAI_SAISR_TFS_SHIFT)
181#define ESAI_SAISR_RODF_SHIFT 10
182#define ESAI_SAISR_RODF_MASK (1 << ESAI_SAISR_RODF_SHIFT)
183#define ESAI_SAISR_RODF (1 << ESAI_SAISR_RODF_SHIFT)
184#define ESAI_SAISR_REDF_SHIFT 9
185#define ESAI_SAISR_REDF_MASK (1 << ESAI_SAISR_REDF_SHIFT)
186#define ESAI_SAISR_REDF (1 << ESAI_SAISR_REDF_SHIFT)
187#define ESAI_SAISR_RDF_SHIFT 8
188#define ESAI_SAISR_RDF_MASK (1 << ESAI_SAISR_RDF_SHIFT)
189#define ESAI_SAISR_RDF (1 << ESAI_SAISR_RDF_SHIFT)
190#define ESAI_SAISR_ROE_SHIFT 7
191#define ESAI_SAISR_ROE_MASK (1 << ESAI_SAISR_ROE_SHIFT)
192#define ESAI_SAISR_ROE (1 << ESAI_SAISR_ROE_SHIFT)
193#define ESAI_SAISR_RFS_SHIFT 6
194#define ESAI_SAISR_RFS_MASK (1 << ESAI_SAISR_RFS_SHIFT)
195#define ESAI_SAISR_RFS (1 << ESAI_SAISR_RFS_SHIFT)
196#define ESAI_SAISR_IF2_SHIFT 2
197#define ESAI_SAISR_IF2_MASK (1 << ESAI_SAISR_IF2_SHIFT)
198#define ESAI_SAISR_IF2 (1 << ESAI_SAISR_IF2_SHIFT)
199#define ESAI_SAISR_IF1_SHIFT 1
200#define ESAI_SAISR_IF1_MASK (1 << ESAI_SAISR_IF1_SHIFT)
201#define ESAI_SAISR_IF1 (1 << ESAI_SAISR_IF1_SHIFT)
202#define ESAI_SAISR_IF0_SHIFT 0
203#define ESAI_SAISR_IF0_MASK (1 << ESAI_SAISR_IF0_SHIFT)
204#define ESAI_SAISR_IF0 (1 << ESAI_SAISR_IF0_SHIFT)
205
206/* Serial Audio Interface Control Register -- REG_ESAI_SAICR 0xD0 */
207#define ESAI_SAICR_ALC_SHIFT 8
208#define ESAI_SAICR_ALC_MASK (1 << ESAI_SAICR_ALC_SHIFT)
209#define ESAI_SAICR_ALC (1 << ESAI_SAICR_ALC_SHIFT)
210#define ESAI_SAICR_TEBE_SHIFT 7
211#define ESAI_SAICR_TEBE_MASK (1 << ESAI_SAICR_TEBE_SHIFT)
212#define ESAI_SAICR_TEBE (1 << ESAI_SAICR_TEBE_SHIFT)
213#define ESAI_SAICR_SYNC_SHIFT 6
214#define ESAI_SAICR_SYNC_MASK (1 << ESAI_SAICR_SYNC_SHIFT)
215#define ESAI_SAICR_SYNC (1 << ESAI_SAICR_SYNC_SHIFT)
216#define ESAI_SAICR_OF2_SHIFT 2
217#define ESAI_SAICR_OF2_MASK (1 << ESAI_SAICR_OF2_SHIFT)
218#define ESAI_SAICR_OF2 (1 << ESAI_SAICR_OF2_SHIFT)
219#define ESAI_SAICR_OF1_SHIFT 1
220#define ESAI_SAICR_OF1_MASK (1 << ESAI_SAICR_OF1_SHIFT)
221#define ESAI_SAICR_OF1 (1 << ESAI_SAICR_OF1_SHIFT)
222#define ESAI_SAICR_OF0_SHIFT 0
223#define ESAI_SAICR_OF0_MASK (1 << ESAI_SAICR_OF0_SHIFT)
224#define ESAI_SAICR_OF0 (1 << ESAI_SAICR_OF0_SHIFT)
225
226/*
227 * Transmit Control Register -- REG_ESAI_TCR 0xD4
228 * Receive Control Register -- REG_ESAI_RCR 0xDC
229 */
230#define ESAI_xCR_xLIE_SHIFT 23
231#define ESAI_xCR_xLIE_MASK (1 << ESAI_xCR_xLIE_SHIFT)
232#define ESAI_xCR_xLIE (1 << ESAI_xCR_xLIE_SHIFT)
233#define ESAI_xCR_xIE_SHIFT 22
234#define ESAI_xCR_xIE_MASK (1 << ESAI_xCR_xIE_SHIFT)
235#define ESAI_xCR_xIE (1 << ESAI_xCR_xIE_SHIFT)
236#define ESAI_xCR_xEDIE_SHIFT 21
237#define ESAI_xCR_xEDIE_MASK (1 << ESAI_xCR_xEDIE_SHIFT)
238#define ESAI_xCR_xEDIE (1 << ESAI_xCR_xEDIE_SHIFT)
239#define ESAI_xCR_xEIE_SHIFT 20
240#define ESAI_xCR_xEIE_MASK (1 << ESAI_xCR_xEIE_SHIFT)
241#define ESAI_xCR_xEIE (1 << ESAI_xCR_xEIE_SHIFT)
242#define ESAI_xCR_xPR_SHIFT 19
243#define ESAI_xCR_xPR_MASK (1 << ESAI_xCR_xPR_SHIFT)
244#define ESAI_xCR_xPR (1 << ESAI_xCR_xPR_SHIFT)
245#define ESAI_xCR_PADC_SHIFT 17
246#define ESAI_xCR_PADC_MASK (1 << ESAI_xCR_PADC_SHIFT)
247#define ESAI_xCR_PADC (1 << ESAI_xCR_PADC_SHIFT)
248#define ESAI_xCR_xFSR_SHIFT 16
249#define ESAI_xCR_xFSR_MASK (1 << ESAI_xCR_xFSR_SHIFT)
250#define ESAI_xCR_xFSR (1 << ESAI_xCR_xFSR_SHIFT)
251#define ESAI_xCR_xFSL_SHIFT 15
252#define ESAI_xCR_xFSL_MASK (1 << ESAI_xCR_xFSL_SHIFT)
253#define ESAI_xCR_xFSL (1 << ESAI_xCR_xFSL_SHIFT)
254#define ESAI_xCR_xSWS_SHIFT 10
255#define ESAI_xCR_xSWS_WIDTH 5
256#define ESAI_xCR_xSWS_MASK (((1 << ESAI_xCR_xSWS_WIDTH) - 1) << ESAI_xCR_xSWS_SHIFT)
257#define ESAI_xCR_xSWS(s, w) ((w < 24 ? (s - w + ((w - 8) >> 2)) : (s < 32 ? 0x1e : 0x1f)) << ESAI_xCR_xSWS_SHIFT)
258#define ESAI_xCR_xMOD_SHIFT 8
259#define ESAI_xCR_xMOD_WIDTH 2
260#define ESAI_xCR_xMOD_MASK (((1 << ESAI_xCR_xMOD_WIDTH) - 1) << ESAI_xCR_xMOD_SHIFT)
261#define ESAI_xCR_xMOD_ONDEMAND (0x1 << ESAI_xCR_xMOD_SHIFT)
262#define ESAI_xCR_xMOD_NETWORK (0x1 << ESAI_xCR_xMOD_SHIFT)
263#define ESAI_xCR_xMOD_AC97 (0x3 << ESAI_xCR_xMOD_SHIFT)
264#define ESAI_xCR_xWA_SHIFT 7
265#define ESAI_xCR_xWA_MASK (1 << ESAI_xCR_xWA_SHIFT)
266#define ESAI_xCR_xWA (1 << ESAI_xCR_xWA_SHIFT)
267#define ESAI_xCR_xSHFD_SHIFT 6
268#define ESAI_xCR_xSHFD_MASK (1 << ESAI_xCR_xSHFD_SHIFT)
269#define ESAI_xCR_xSHFD (1 << ESAI_xCR_xSHFD_SHIFT)
270#define ESAI_xCR_xE_SHIFT 0
271#define ESAI_xCR_TE_WIDTH 6
272#define ESAI_xCR_RE_WIDTH 4
273#define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
274#define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT)
275#define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK)
276#define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK)
277
278/*
279 * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8
280 * Receive Clock Control Register -- REG_ESAI_RCCR 0xE0
281 */
282#define ESAI_xCCR_xHCKD_SHIFT 23
283#define ESAI_xCCR_xHCKD_MASK (1 << ESAI_xCCR_xHCKD_SHIFT)
284#define ESAI_xCCR_xHCKD (1 << ESAI_xCCR_xHCKD_SHIFT)
285#define ESAI_xCCR_xFSD_SHIFT 22
286#define ESAI_xCCR_xFSD_MASK (1 << ESAI_xCCR_xFSD_SHIFT)
287#define ESAI_xCCR_xFSD (1 << ESAI_xCCR_xFSD_SHIFT)
288#define ESAI_xCCR_xCKD_SHIFT 21
289#define ESAI_xCCR_xCKD_MASK (1 << ESAI_xCCR_xCKD_SHIFT)
290#define ESAI_xCCR_xCKD (1 << ESAI_xCCR_xCKD_SHIFT)
291#define ESAI_xCCR_xHCKP_SHIFT 20
292#define ESAI_xCCR_xHCKP_MASK (1 << ESAI_xCCR_xHCKP_SHIFT)
293#define ESAI_xCCR_xHCKP (1 << ESAI_xCCR_xHCKP_SHIFT)
294#define ESAI_xCCR_xFSP_SHIFT 19
295#define ESAI_xCCR_xFSP_MASK (1 << ESAI_xCCR_xFSP_SHIFT)
296#define ESAI_xCCR_xFSP (1 << ESAI_xCCR_xFSP_SHIFT)
297#define ESAI_xCCR_xCKP_SHIFT 18
298#define ESAI_xCCR_xCKP_MASK (1 << ESAI_xCCR_xCKP_SHIFT)
299#define ESAI_xCCR_xCKP (1 << ESAI_xCCR_xCKP_SHIFT)
300#define ESAI_xCCR_xFP_SHIFT 14
301#define ESAI_xCCR_xFP_WIDTH 4
302#define ESAI_xCCR_xFP_MASK (((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
303#define ESAI_xCCR_xFP(v) ((((v) - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
304#define ESAI_xCCR_xDC_SHIFT 9
305#define ESAI_xCCR_xDC_WIDTH 4
306#define ESAI_xCCR_xDC_MASK (((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
307#define ESAI_xCCR_xDC(v) ((((v) - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
308#define ESAI_xCCR_xPSR_SHIFT 8
309#define ESAI_xCCR_xPSR_MASK (1 << ESAI_xCCR_xPSR_SHIFT)
310#define ESAI_xCCR_xPSR_BYPASS (1 << ESAI_xCCR_xPSR_SHIFT)
311#define ESAI_xCCR_xPSR_DIV8 (0 << ESAI_xCCR_xPSR_SHIFT)
312#define ESAI_xCCR_xPM_SHIFT 0
313#define ESAI_xCCR_xPM_WIDTH 8
314#define ESAI_xCCR_xPM_MASK (((1 << ESAI_xCCR_xPM_WIDTH) - 1) << ESAI_xCCR_xPM_SHIFT)
315#define ESAI_xCCR_xPM(v) ((((v) - 1) << ESAI_xCCR_xPM_SHIFT) & ESAI_xCCR_xPM_MASK)
316
317/* Transmit Slot Mask Register A/B -- REG_ESAI_TSMA/B 0xE4 ~ 0xF0 */
318#define ESAI_xSMA_xS_SHIFT 0
319#define ESAI_xSMA_xS_WIDTH 16
320#define ESAI_xSMA_xS_MASK (((1 << ESAI_xSMA_xS_WIDTH) - 1) << ESAI_xSMA_xS_SHIFT)
321#define ESAI_xSMA_xS(v) ((v) & ESAI_xSMA_xS_MASK)
322#define ESAI_xSMB_xS_SHIFT 0
323#define ESAI_xSMB_xS_WIDTH 16
324#define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT)
325#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK)
326
327/* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */
328#define ESAI_PRRC_PDC_SHIFT 0
329#define ESAI_PRRC_PDC_WIDTH 12
330#define ESAI_PRRC_PDC_MASK (((1 << ESAI_PRRC_PDC_WIDTH) - 1) << ESAI_PRRC_PDC_SHIFT)
331#define ESAI_PRRC_PDC(v) ((v) & ESAI_PRRC_PDC_MASK)
332
333/* Port C Control Register -- REG_ESAI_PCRC 0xFC */
334#define ESAI_PCRC_PC_SHIFT 0
335#define ESAI_PCRC_PC_WIDTH 12
336#define ESAI_PCRC_PC_MASK (((1 << ESAI_PCRC_PC_WIDTH) - 1) << ESAI_PCRC_PC_SHIFT)
337#define ESAI_PCRC_PC(v) ((v) & ESAI_PCRC_PC_MASK)
338
339#define ESAI_GPIO 0xfff
340
341/* ESAI clock source */
342#define ESAI_HCKT_FSYS 0
343#define ESAI_HCKT_EXTAL 1
344#define ESAI_HCKR_FSYS 2
345#define ESAI_HCKR_EXTAL 3
346
347/* ESAI clock divider */
348#define ESAI_TX_DIV_PSR 0
349#define ESAI_TX_DIV_PM 1
350#define ESAI_TX_DIV_FP 2
351#define ESAI_RX_DIV_PSR 3
352#define ESAI_RX_DIV_PM 4
353#define ESAI_RX_DIV_FP 5
354#endif /* _FSL_ESAI_DAI_H */