diff options
author | Nicolin Chen <b42378@freescale.com> | 2013-08-20 23:13:16 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-08-22 05:45:22 -0400 |
commit | a2388a498ad2f85be01aca29e364abf427d9b53c (patch) | |
tree | 45671072f04d6052101b6c4fc2e670255b0ff778 | |
parent | 0783e648988a2ccef6eac9b1c376e7832e09cd94 (diff) |
ASoC: fsl: Add S/PDIF CPU DAI driver
This patch implements a device-tree-only CPU DAI driver for Freescale
S/PDIF controller that supports stereo playback and record feature.
Signed-off-by: Nicolin Chen <b42378@freescale.com>
Acked-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r-- | Documentation/devicetree/bindings/sound/fsl,spdif.txt | 54 | ||||
-rw-r--r-- | sound/soc/fsl/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/fsl/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_spdif.c | 1236 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_spdif.h | 191 |
5 files changed, 1486 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt new file mode 100644 index 000000000000..f2ae335670f5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt | |||
@@ -0,0 +1,54 @@ | |||
1 | Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller | ||
2 | |||
3 | The Freescale S/PDIF audio block is a stereo transceiver that allows the | ||
4 | processor to receive and transmit digital audio via an coaxial cable or | ||
5 | a fibre cable. | ||
6 | |||
7 | Required properties: | ||
8 | |||
9 | - compatible : Compatible list, must contain "fsl,imx35-spdif". | ||
10 | |||
11 | - reg : Offset and length of the register set for the device. | ||
12 | |||
13 | - interrupts : Contains the spdif interrupt. | ||
14 | |||
15 | - dmas : Generic dma devicetree binding as described in | ||
16 | Documentation/devicetree/bindings/dma/dma.txt. | ||
17 | |||
18 | - dma-names : Two dmas have to be defined, "tx" and "rx". | ||
19 | |||
20 | - clocks : Contains an entry for each entry in clock-names. | ||
21 | |||
22 | - clock-names : Includes the following entries: | ||
23 | "core" The core clock of spdif controller | ||
24 | "rxtx<0-7>" Clock source list for tx and rx clock. | ||
25 | This clock list should be identical to | ||
26 | the source list connecting to the spdif | ||
27 | clock mux in "SPDIF Transceiver Clock | ||
28 | Diagram" of SoC reference manual. It | ||
29 | can also be referred to TxClk_Source | ||
30 | bit of register SPDIF_STC. | ||
31 | |||
32 | Example: | ||
33 | |||
34 | spdif: spdif@02004000 { | ||
35 | compatible = "fsl,imx35-spdif"; | ||
36 | reg = <0x02004000 0x4000>; | ||
37 | interrupts = <0 52 0x04>; | ||
38 | dmas = <&sdma 14 18 0>, | ||
39 | <&sdma 15 18 0>; | ||
40 | dma-names = "rx", "tx"; | ||
41 | |||
42 | clocks = <&clks 197>, <&clks 3>, | ||
43 | <&clks 197>, <&clks 107>, | ||
44 | <&clks 0>, <&clks 118>, | ||
45 | <&clks 62>, <&clks 139>, | ||
46 | <&clks 0>; | ||
47 | clock-names = "core", "rxtx0", | ||
48 | "rxtx1", "rxtx2", | ||
49 | "rxtx3", "rxtx4", | ||
50 | "rxtx5", "rxtx6", | ||
51 | "rxtx7"; | ||
52 | |||
53 | status = "okay"; | ||
54 | }; | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 3a4808d376d0..cd088cc8c866 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,6 +1,9 @@ | |||
1 | config SND_SOC_FSL_SSI | 1 | config SND_SOC_FSL_SSI |
2 | tristate | 2 | tristate |
3 | 3 | ||
4 | config SND_SOC_FSL_SPDIF | ||
5 | tristate | ||
6 | |||
4 | config SND_SOC_FSL_UTILS | 7 | config SND_SOC_FSL_UTILS |
5 | tristate | 8 | tristate |
6 | 9 | ||
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index d4b4aa8b5649..4b5970e014dd 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -12,9 +12,11 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o | |||
12 | 12 | ||
13 | # Freescale PowerPC SSI/DMA Platform Support | 13 | # Freescale PowerPC SSI/DMA Platform Support |
14 | snd-soc-fsl-ssi-objs := fsl_ssi.o | 14 | snd-soc-fsl-ssi-objs := fsl_ssi.o |
15 | snd-soc-fsl-spdif-objs := fsl_spdif.o | ||
15 | snd-soc-fsl-utils-objs := fsl_utils.o | 16 | snd-soc-fsl-utils-objs := fsl_utils.o |
16 | snd-soc-fsl-dma-objs := fsl_dma.o | 17 | snd-soc-fsl-dma-objs := fsl_dma.o |
17 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o | 18 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o |
19 | obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o | ||
18 | obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o | 20 | obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o |
19 | obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o | 21 | obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o |
20 | 22 | ||
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c new file mode 100644 index 000000000000..42a43820d993 --- /dev/null +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -0,0 +1,1236 @@ | |||
1 | /* | ||
2 | * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Based on stmp3xxx_spdif_dai.c | ||
7 | * Vladimir Barinov <vbarinov@embeddedalley.com> | ||
8 | * Copyright 2008 SigmaTel, Inc | ||
9 | * Copyright 2008 Embedded Alley Solutions, Inc | ||
10 | * | ||
11 | * This file is licensed under the terms of the GNU General Public License | ||
12 | * version 2. This program is licensed "as is" without any warranty of any | ||
13 | * kind, whether express or implied. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/clk-private.h> | ||
19 | #include <linux/bitrev.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/of_device.h> | ||
23 | #include <linux/of_irq.h> | ||
24 | |||
25 | #include <sound/asoundef.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/dmaengine_pcm.h> | ||
28 | |||
29 | #include "fsl_spdif.h" | ||
30 | #include "imx-pcm.h" | ||
31 | |||
32 | #define FSL_SPDIF_TXFIFO_WML 0x8 | ||
33 | #define FSL_SPDIF_RXFIFO_WML 0x8 | ||
34 | |||
35 | #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) | ||
36 | #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\ | ||
37 | INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\ | ||
38 | INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED) | ||
39 | |||
40 | /* Index list for the values that has if (DPLL Locked) condition */ | ||
41 | static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; | ||
42 | #define SRPC_NODPLL_START1 0x5 | ||
43 | #define SRPC_NODPLL_START2 0xc | ||
44 | |||
45 | #define DEFAULT_RXCLK_SRC 1 | ||
46 | |||
47 | /* | ||
48 | * SPDIF control structure | ||
49 | * Defines channel status, subcode and Q sub | ||
50 | */ | ||
51 | struct spdif_mixer_control { | ||
52 | /* spinlock to access control data */ | ||
53 | spinlock_t ctl_lock; | ||
54 | |||
55 | /* IEC958 channel tx status bit */ | ||
56 | unsigned char ch_status[4]; | ||
57 | |||
58 | /* User bits */ | ||
59 | unsigned char subcode[2 * SPDIF_UBITS_SIZE]; | ||
60 | |||
61 | /* Q subcode part of user bits */ | ||
62 | unsigned char qsub[2 * SPDIF_QSUB_SIZE]; | ||
63 | |||
64 | /* Buffer offset for U/Q */ | ||
65 | u32 upos; | ||
66 | u32 qpos; | ||
67 | |||
68 | /* Ready buffer index of the two buffers */ | ||
69 | u32 ready_buf; | ||
70 | }; | ||
71 | |||
72 | struct fsl_spdif_priv { | ||
73 | struct spdif_mixer_control fsl_spdif_control; | ||
74 | struct snd_soc_dai_driver cpu_dai_drv; | ||
75 | struct platform_device *pdev; | ||
76 | struct regmap *regmap; | ||
77 | bool dpll_locked; | ||
78 | u8 txclk_div[SPDIF_TXRATE_MAX]; | ||
79 | u8 txclk_src[SPDIF_TXRATE_MAX]; | ||
80 | u8 rxclk_src; | ||
81 | struct clk *txclk[SPDIF_TXRATE_MAX]; | ||
82 | struct clk *rxclk; | ||
83 | struct snd_dmaengine_dai_dma_data dma_params_tx; | ||
84 | struct snd_dmaengine_dai_dma_data dma_params_rx; | ||
85 | |||
86 | /* The name space will be allocated dynamically */ | ||
87 | char name[0]; | ||
88 | }; | ||
89 | |||
90 | |||
91 | /* DPLL locked and lock loss interrupt handler */ | ||
92 | static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) | ||
93 | { | ||
94 | struct regmap *regmap = spdif_priv->regmap; | ||
95 | struct platform_device *pdev = spdif_priv->pdev; | ||
96 | u32 locked; | ||
97 | |||
98 | regmap_read(regmap, REG_SPDIF_SRPC, &locked); | ||
99 | locked &= SRPC_DPLL_LOCKED; | ||
100 | |||
101 | dev_dbg(&pdev->dev, "isr: Rx dpll %s \n", | ||
102 | locked ? "locked" : "loss lock"); | ||
103 | |||
104 | spdif_priv->dpll_locked = locked ? true : false; | ||
105 | } | ||
106 | |||
107 | /* Receiver found illegal symbol interrupt handler */ | ||
108 | static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv) | ||
109 | { | ||
110 | struct regmap *regmap = spdif_priv->regmap; | ||
111 | struct platform_device *pdev = spdif_priv->pdev; | ||
112 | |||
113 | dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); | ||
114 | |||
115 | if (!spdif_priv->dpll_locked) { | ||
116 | /* DPLL unlocked seems no audio stream */ | ||
117 | regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* U/Q Channel receive register full */ | ||
122 | static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name) | ||
123 | { | ||
124 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
125 | struct regmap *regmap = spdif_priv->regmap; | ||
126 | struct platform_device *pdev = spdif_priv->pdev; | ||
127 | u32 *pos, size, val, reg; | ||
128 | |||
129 | switch (name) { | ||
130 | case 'U': | ||
131 | pos = &ctrl->upos; | ||
132 | size = SPDIF_UBITS_SIZE; | ||
133 | reg = REG_SPDIF_SRU; | ||
134 | break; | ||
135 | case 'Q': | ||
136 | pos = &ctrl->qpos; | ||
137 | size = SPDIF_QSUB_SIZE; | ||
138 | reg = REG_SPDIF_SRQ; | ||
139 | break; | ||
140 | default: | ||
141 | dev_err(&pdev->dev, "unsupported channel name\n"); | ||
142 | return; | ||
143 | } | ||
144 | |||
145 | dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name); | ||
146 | |||
147 | if (*pos >= size * 2) { | ||
148 | *pos = 0; | ||
149 | } else if (unlikely((*pos % size) + 3 > size)) { | ||
150 | dev_err(&pdev->dev, "User bit receivce buffer overflow\n"); | ||
151 | return; | ||
152 | } | ||
153 | |||
154 | regmap_read(regmap, reg, &val); | ||
155 | ctrl->subcode[*pos++] = val >> 16; | ||
156 | ctrl->subcode[*pos++] = val >> 8; | ||
157 | ctrl->subcode[*pos++] = val; | ||
158 | } | ||
159 | |||
160 | /* U/Q Channel sync found */ | ||
161 | static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv) | ||
162 | { | ||
163 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
164 | struct platform_device *pdev = spdif_priv->pdev; | ||
165 | |||
166 | dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n"); | ||
167 | |||
168 | /* U/Q buffer reset */ | ||
169 | if (ctrl->qpos == 0) | ||
170 | return; | ||
171 | |||
172 | /* Set ready to this buffer */ | ||
173 | ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1; | ||
174 | } | ||
175 | |||
176 | /* U/Q Channel framing error */ | ||
177 | static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv) | ||
178 | { | ||
179 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
180 | struct regmap *regmap = spdif_priv->regmap; | ||
181 | struct platform_device *pdev = spdif_priv->pdev; | ||
182 | u32 val; | ||
183 | |||
184 | dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n"); | ||
185 | |||
186 | /* Read U/Q data to clear the irq and do buffer reset */ | ||
187 | regmap_read(regmap, REG_SPDIF_SRU, &val); | ||
188 | regmap_read(regmap, REG_SPDIF_SRQ, &val); | ||
189 | |||
190 | /* Drop this U/Q buffer */ | ||
191 | ctrl->ready_buf = 0; | ||
192 | ctrl->upos = 0; | ||
193 | ctrl->qpos = 0; | ||
194 | } | ||
195 | |||
196 | /* Get spdif interrupt status and clear the interrupt */ | ||
197 | static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv) | ||
198 | { | ||
199 | struct regmap *regmap = spdif_priv->regmap; | ||
200 | u32 val, val2; | ||
201 | |||
202 | regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
203 | regmap_read(regmap, REG_SPDIF_SIE, &val2); | ||
204 | |||
205 | regmap_write(regmap, REG_SPDIF_SIC, val & val2); | ||
206 | |||
207 | return val; | ||
208 | } | ||
209 | |||
210 | static irqreturn_t spdif_isr(int irq, void *devid) | ||
211 | { | ||
212 | struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid; | ||
213 | struct platform_device *pdev = spdif_priv->pdev; | ||
214 | u32 sis; | ||
215 | |||
216 | sis = spdif_intr_status_clear(spdif_priv); | ||
217 | |||
218 | if (sis & INT_DPLL_LOCKED) | ||
219 | spdif_irq_dpll_lock(spdif_priv); | ||
220 | |||
221 | if (sis & INT_TXFIFO_UNOV) | ||
222 | dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n"); | ||
223 | |||
224 | if (sis & INT_TXFIFO_RESYNC) | ||
225 | dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n"); | ||
226 | |||
227 | if (sis & INT_CNEW) | ||
228 | dev_dbg(&pdev->dev, "isr: cstatus new\n"); | ||
229 | |||
230 | if (sis & INT_VAL_NOGOOD) | ||
231 | dev_dbg(&pdev->dev, "isr: validity flag no good\n"); | ||
232 | |||
233 | if (sis & INT_SYM_ERR) | ||
234 | spdif_irq_sym_error(spdif_priv); | ||
235 | |||
236 | if (sis & INT_BIT_ERR) | ||
237 | dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n"); | ||
238 | |||
239 | if (sis & INT_URX_FUL) | ||
240 | spdif_irq_uqrx_full(spdif_priv, 'U'); | ||
241 | |||
242 | if (sis & INT_URX_OV) | ||
243 | dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n"); | ||
244 | |||
245 | if (sis & INT_QRX_FUL) | ||
246 | spdif_irq_uqrx_full(spdif_priv, 'Q'); | ||
247 | |||
248 | if (sis & INT_QRX_OV) | ||
249 | dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n"); | ||
250 | |||
251 | if (sis & INT_UQ_SYNC) | ||
252 | spdif_irq_uq_sync(spdif_priv); | ||
253 | |||
254 | if (sis & INT_UQ_ERR) | ||
255 | spdif_irq_uq_err(spdif_priv); | ||
256 | |||
257 | if (sis & INT_RXFIFO_UNOV) | ||
258 | dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n"); | ||
259 | |||
260 | if (sis & INT_RXFIFO_RESYNC) | ||
261 | dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n"); | ||
262 | |||
263 | if (sis & INT_LOSS_LOCK) | ||
264 | spdif_irq_dpll_lock(spdif_priv); | ||
265 | |||
266 | /* FIXME: Write Tx FIFO to clear TxEm */ | ||
267 | if (sis & INT_TX_EM) | ||
268 | dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n"); | ||
269 | |||
270 | /* FIXME: Read Rx FIFO to clear RxFIFOFul */ | ||
271 | if (sis & INT_RXFIFO_FUL) | ||
272 | dev_dbg(&pdev->dev, "isr: Rx FIFO full\n"); | ||
273 | |||
274 | return IRQ_HANDLED; | ||
275 | } | ||
276 | |||
277 | static int spdif_softreset(struct fsl_spdif_priv *spdif_priv) | ||
278 | { | ||
279 | struct regmap *regmap = spdif_priv->regmap; | ||
280 | u32 val, cycle = 1000; | ||
281 | |||
282 | regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET); | ||
283 | |||
284 | /* | ||
285 | * RESET bit would be cleared after finishing its reset procedure, | ||
286 | * which typically lasts 8 cycles. 1000 cycles will keep it safe. | ||
287 | */ | ||
288 | do { | ||
289 | regmap_read(regmap, REG_SPDIF_SCR, &val); | ||
290 | } while ((val & SCR_SOFT_RESET) && cycle--); | ||
291 | |||
292 | if (cycle) | ||
293 | return 0; | ||
294 | else | ||
295 | return -EBUSY; | ||
296 | } | ||
297 | |||
298 | static void spdif_set_cstatus(struct spdif_mixer_control *ctrl, | ||
299 | u8 mask, u8 cstatus) | ||
300 | { | ||
301 | ctrl->ch_status[3] &= ~mask; | ||
302 | ctrl->ch_status[3] |= cstatus & mask; | ||
303 | } | ||
304 | |||
305 | static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv) | ||
306 | { | ||
307 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
308 | struct regmap *regmap = spdif_priv->regmap; | ||
309 | struct platform_device *pdev = spdif_priv->pdev; | ||
310 | u32 ch_status; | ||
311 | |||
312 | ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | | ||
313 | (bitrev8(ctrl->ch_status[1]) << 8) | | ||
314 | bitrev8(ctrl->ch_status[2]); | ||
315 | regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); | ||
316 | |||
317 | dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); | ||
318 | |||
319 | ch_status = bitrev8(ctrl->ch_status[3]) << 16; | ||
320 | regmap_write(regmap, REG_SPDIF_STCSCL, ch_status); | ||
321 | |||
322 | dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status); | ||
323 | } | ||
324 | |||
325 | /* Set SPDIF PhaseConfig register for rx clock */ | ||
326 | static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, | ||
327 | enum spdif_gainsel gainsel, int dpll_locked) | ||
328 | { | ||
329 | struct regmap *regmap = spdif_priv->regmap; | ||
330 | u8 clksrc = spdif_priv->rxclk_src; | ||
331 | |||
332 | if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX) | ||
333 | return -EINVAL; | ||
334 | |||
335 | regmap_update_bits(regmap, REG_SPDIF_SRPC, | ||
336 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, | ||
337 | SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel)); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int spdif_set_sample_rate(struct snd_pcm_substream *substream, | ||
343 | int sample_rate) | ||
344 | { | ||
345 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
346 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
347 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
348 | struct regmap *regmap = spdif_priv->regmap; | ||
349 | struct platform_device *pdev = spdif_priv->pdev; | ||
350 | unsigned long csfs = 0; | ||
351 | u32 stc, mask, rate; | ||
352 | u8 clk, div; | ||
353 | int ret; | ||
354 | |||
355 | switch (sample_rate) { | ||
356 | case 32000: | ||
357 | rate = SPDIF_TXRATE_32000; | ||
358 | csfs = IEC958_AES3_CON_FS_32000; | ||
359 | break; | ||
360 | case 44100: | ||
361 | rate = SPDIF_TXRATE_44100; | ||
362 | csfs = IEC958_AES3_CON_FS_44100; | ||
363 | break; | ||
364 | case 48000: | ||
365 | rate = SPDIF_TXRATE_48000; | ||
366 | csfs = IEC958_AES3_CON_FS_48000; | ||
367 | break; | ||
368 | default: | ||
369 | dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | clk = spdif_priv->txclk_src[rate]; | ||
374 | if (clk >= STC_TXCLK_SRC_MAX) { | ||
375 | dev_err(&pdev->dev, "tx clock source is out of range\n"); | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | |||
379 | div = spdif_priv->txclk_div[rate]; | ||
380 | if (div == 0) { | ||
381 | dev_err(&pdev->dev, "the divisor can't be zero\n"); | ||
382 | return -EINVAL; | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * The S/PDIF block needs a clock of 64 * fs * div. The S/PDIF block | ||
387 | * will divide by (div). So request 64 * fs * (div+1) which will | ||
388 | * get rounded. | ||
389 | */ | ||
390 | ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1)); | ||
391 | if (ret) { | ||
392 | dev_err(&pdev->dev, "failed to set tx clock rate\n"); | ||
393 | return ret; | ||
394 | } | ||
395 | |||
396 | dev_dbg(&pdev->dev, "expected clock rate = %d\n", | ||
397 | (64 * sample_rate * div)); | ||
398 | dev_dbg(&pdev->dev, "actual clock rate = %ld\n", | ||
399 | clk_get_rate(spdif_priv->txclk[rate])); | ||
400 | |||
401 | /* set fs field in consumer channel status */ | ||
402 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); | ||
403 | |||
404 | /* select clock source and divisor */ | ||
405 | stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div); | ||
406 | mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK; | ||
407 | regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); | ||
408 | |||
409 | dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | int fsl_spdif_startup(struct snd_pcm_substream *substream, | ||
415 | struct snd_soc_dai *cpu_dai) | ||
416 | { | ||
417 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
418 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
419 | struct platform_device *pdev = spdif_priv->pdev; | ||
420 | struct regmap *regmap = spdif_priv->regmap; | ||
421 | u32 scr, mask, i; | ||
422 | int ret; | ||
423 | |||
424 | /* Reset module and interrupts only for first initialization */ | ||
425 | if (!cpu_dai->active) { | ||
426 | ret = spdif_softreset(spdif_priv); | ||
427 | if (ret) { | ||
428 | dev_err(&pdev->dev, "failed to soft reset\n"); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | /* Disable all the interrupts */ | ||
433 | regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0); | ||
434 | } | ||
435 | |||
436 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
437 | scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL | | ||
438 | SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP | | ||
439 | SCR_TXFIFO_FSEL_IF8; | ||
440 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | ||
441 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | ||
442 | SCR_TXFIFO_FSEL_MASK; | ||
443 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) | ||
444 | clk_prepare_enable(spdif_priv->txclk[i]); | ||
445 | } else { | ||
446 | scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; | ||
447 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | ||
448 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | ||
449 | clk_prepare_enable(spdif_priv->rxclk); | ||
450 | } | ||
451 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | ||
452 | |||
453 | /* Power up SPDIF module */ | ||
454 | regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, | ||
460 | struct snd_soc_dai *cpu_dai) | ||
461 | { | ||
462 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
463 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
464 | struct regmap *regmap = spdif_priv->regmap; | ||
465 | u32 scr, mask, i; | ||
466 | |||
467 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
468 | scr = 0; | ||
469 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | ||
470 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | ||
471 | SCR_TXFIFO_FSEL_MASK; | ||
472 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) | ||
473 | clk_disable_unprepare(spdif_priv->txclk[i]); | ||
474 | } else { | ||
475 | scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; | ||
476 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | ||
477 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | ||
478 | clk_disable_unprepare(spdif_priv->rxclk); | ||
479 | } | ||
480 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | ||
481 | |||
482 | /* Power down SPDIF module only if tx&rx are both inactive */ | ||
483 | if (!cpu_dai->active) { | ||
484 | spdif_intr_status_clear(spdif_priv); | ||
485 | regmap_update_bits(regmap, REG_SPDIF_SCR, | ||
486 | SCR_LOW_POWER, SCR_LOW_POWER); | ||
487 | } | ||
488 | } | ||
489 | |||
490 | static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, | ||
491 | struct snd_pcm_hw_params *params, | ||
492 | struct snd_soc_dai *dai) | ||
493 | { | ||
494 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
495 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
496 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
497 | struct platform_device *pdev = spdif_priv->pdev; | ||
498 | u32 sample_rate = params_rate(params); | ||
499 | int ret = 0; | ||
500 | |||
501 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
502 | ret = spdif_set_sample_rate(substream, sample_rate); | ||
503 | if (ret) { | ||
504 | dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", | ||
505 | __func__, sample_rate); | ||
506 | return ret; | ||
507 | } | ||
508 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, | ||
509 | IEC958_AES3_CON_CLOCK_1000PPM); | ||
510 | spdif_write_channel_status(spdif_priv); | ||
511 | } else { | ||
512 | /* Setup rx clock source */ | ||
513 | ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); | ||
514 | } | ||
515 | |||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | static int fsl_spdif_trigger(struct snd_pcm_substream *substream, | ||
520 | int cmd, struct snd_soc_dai *dai) | ||
521 | { | ||
522 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
523 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
524 | struct regmap *regmap = spdif_priv->regmap; | ||
525 | int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
526 | u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE; | ||
527 | u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;; | ||
528 | |||
529 | switch (cmd) { | ||
530 | case SNDRV_PCM_TRIGGER_START: | ||
531 | case SNDRV_PCM_TRIGGER_RESUME: | ||
532 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
533 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr); | ||
534 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen); | ||
535 | break; | ||
536 | case SNDRV_PCM_TRIGGER_STOP: | ||
537 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
538 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
539 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0); | ||
540 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0); | ||
541 | break; | ||
542 | default: | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | struct snd_soc_dai_ops fsl_spdif_dai_ops = { | ||
550 | .startup = fsl_spdif_startup, | ||
551 | .hw_params = fsl_spdif_hw_params, | ||
552 | .trigger = fsl_spdif_trigger, | ||
553 | .shutdown = fsl_spdif_shutdown, | ||
554 | }; | ||
555 | |||
556 | |||
557 | /* | ||
558 | * ============================================ | ||
559 | * FSL SPDIF IEC958 controller(mixer) functions | ||
560 | * | ||
561 | * Channel status get/put control | ||
562 | * User bit value get/put control | ||
563 | * Valid bit value get control | ||
564 | * DPLL lock status get control | ||
565 | * User bit sync mode selection control | ||
566 | * ============================================ | ||
567 | */ | ||
568 | |||
569 | static int fsl_spdif_info(struct snd_kcontrol *kcontrol, | ||
570 | struct snd_ctl_elem_info *uinfo) | ||
571 | { | ||
572 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
573 | uinfo->count = 1; | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol, | ||
579 | struct snd_ctl_elem_value *uvalue) | ||
580 | { | ||
581 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
582 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
583 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
584 | |||
585 | uvalue->value.iec958.status[0] = ctrl->ch_status[0]; | ||
586 | uvalue->value.iec958.status[1] = ctrl->ch_status[1]; | ||
587 | uvalue->value.iec958.status[2] = ctrl->ch_status[2]; | ||
588 | uvalue->value.iec958.status[3] = ctrl->ch_status[3]; | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol, | ||
594 | struct snd_ctl_elem_value *uvalue) | ||
595 | { | ||
596 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
597 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
598 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
599 | |||
600 | ctrl->ch_status[0] = uvalue->value.iec958.status[0]; | ||
601 | ctrl->ch_status[1] = uvalue->value.iec958.status[1]; | ||
602 | ctrl->ch_status[2] = uvalue->value.iec958.status[2]; | ||
603 | ctrl->ch_status[3] = uvalue->value.iec958.status[3]; | ||
604 | |||
605 | spdif_write_channel_status(spdif_priv); | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | /* Get channel status from SPDIF_RX_CCHAN register */ | ||
611 | static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, | ||
612 | struct snd_ctl_elem_value *ucontrol) | ||
613 | { | ||
614 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
615 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
616 | struct regmap *regmap = spdif_priv->regmap; | ||
617 | u32 cstatus, val; | ||
618 | |||
619 | regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
620 | if (!(val & INT_CNEW)) { | ||
621 | return -EAGAIN; | ||
622 | } | ||
623 | |||
624 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); | ||
625 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; | ||
626 | ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF; | ||
627 | ucontrol->value.iec958.status[2] = cstatus & 0xFF; | ||
628 | |||
629 | regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus); | ||
630 | ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF; | ||
631 | ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF; | ||
632 | ucontrol->value.iec958.status[5] = cstatus & 0xFF; | ||
633 | |||
634 | /* Clear intr */ | ||
635 | regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Get User bits (subcode) from chip value which readed out | ||
642 | * in UChannel register. | ||
643 | */ | ||
644 | static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, | ||
645 | struct snd_ctl_elem_value *ucontrol) | ||
646 | { | ||
647 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
648 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
649 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
650 | unsigned long flags; | ||
651 | int ret = 0; | ||
652 | |||
653 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
654 | if (ctrl->ready_buf) { | ||
655 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; | ||
656 | memcpy(&ucontrol->value.iec958.subcode[0], | ||
657 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); | ||
658 | } else { | ||
659 | ret = -EAGAIN; | ||
660 | } | ||
661 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
662 | |||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | /* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */ | ||
667 | static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, | ||
668 | struct snd_ctl_elem_info *uinfo) | ||
669 | { | ||
670 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
671 | uinfo->count = SPDIF_QSUB_SIZE; | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* Get Q subcode from chip value which readed out in QChannel register */ | ||
677 | static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, | ||
678 | struct snd_ctl_elem_value *ucontrol) | ||
679 | { | ||
680 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
681 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
682 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | ||
683 | unsigned long flags; | ||
684 | int ret = 0; | ||
685 | |||
686 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | ||
687 | if (ctrl->ready_buf) { | ||
688 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; | ||
689 | memcpy(&ucontrol->value.bytes.data[0], | ||
690 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); | ||
691 | } else { | ||
692 | ret = -EAGAIN; | ||
693 | } | ||
694 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | ||
695 | |||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | /* Valid bit infomation */ | ||
700 | static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, | ||
701 | struct snd_ctl_elem_info *uinfo) | ||
702 | { | ||
703 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
704 | uinfo->count = 1; | ||
705 | uinfo->value.integer.min = 0; | ||
706 | uinfo->value.integer.max = 1; | ||
707 | |||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | /* Get valid good bit from interrupt status register */ | ||
712 | static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, | ||
713 | struct snd_ctl_elem_value *ucontrol) | ||
714 | { | ||
715 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
716 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
717 | struct regmap *regmap = spdif_priv->regmap; | ||
718 | u32 val; | ||
719 | |||
720 | val = regmap_read(regmap, REG_SPDIF_SIS, &val); | ||
721 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; | ||
722 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | /* DPLL lock infomation */ | ||
728 | static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, | ||
729 | struct snd_ctl_elem_info *uinfo) | ||
730 | { | ||
731 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
732 | uinfo->count = 1; | ||
733 | uinfo->value.integer.min = 16000; | ||
734 | uinfo->value.integer.max = 96000; | ||
735 | |||
736 | return 0; | ||
737 | } | ||
738 | |||
739 | static u32 gainsel_multi[GAINSEL_MULTI_MAX] = { | ||
740 | 24, 16, 12, 8, 6, 4, 3, | ||
741 | }; | ||
742 | |||
743 | /* Get RX data clock rate given the SPDIF bus_clk */ | ||
744 | static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, | ||
745 | enum spdif_gainsel gainsel) | ||
746 | { | ||
747 | struct regmap *regmap = spdif_priv->regmap; | ||
748 | struct platform_device *pdev = spdif_priv->pdev; | ||
749 | u64 tmpval64, busclk_freq = 0; | ||
750 | u32 freqmeas, phaseconf; | ||
751 | u8 clksrc; | ||
752 | |||
753 | regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas); | ||
754 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); | ||
755 | |||
756 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; | ||
757 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) { | ||
758 | /* Get bus clock from system */ | ||
759 | busclk_freq = clk_get_rate(spdif_priv->rxclk); | ||
760 | } | ||
761 | |||
762 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ | ||
763 | tmpval64 = (u64) busclk_freq * freqmeas; | ||
764 | do_div(tmpval64, gainsel_multi[gainsel] * 1024); | ||
765 | do_div(tmpval64, 128 * 1024); | ||
766 | |||
767 | dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas); | ||
768 | dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq); | ||
769 | dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64); | ||
770 | |||
771 | return (int)tmpval64; | ||
772 | } | ||
773 | |||
774 | /* | ||
775 | * Get DPLL lock or not info from stable interrupt status register. | ||
776 | * User application must use this control to get locked, | ||
777 | * then can do next PCM operation | ||
778 | */ | ||
779 | static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, | ||
780 | struct snd_ctl_elem_value *ucontrol) | ||
781 | { | ||
782 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
783 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
784 | int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); | ||
785 | |||
786 | if (spdif_priv->dpll_locked) | ||
787 | ucontrol->value.integer.value[0] = rate; | ||
788 | else | ||
789 | ucontrol->value.integer.value[0] = 0; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* User bit sync mode info */ | ||
795 | static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, | ||
796 | struct snd_ctl_elem_info *uinfo) | ||
797 | { | ||
798 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
799 | uinfo->count = 1; | ||
800 | uinfo->value.integer.min = 0; | ||
801 | uinfo->value.integer.max = 1; | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * User bit sync mode: | ||
808 | * 1 CD User channel subcode | ||
809 | * 0 Non-CD data | ||
810 | */ | ||
811 | static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol, | ||
812 | struct snd_ctl_elem_value *ucontrol) | ||
813 | { | ||
814 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
815 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
816 | struct regmap *regmap = spdif_priv->regmap; | ||
817 | u32 val; | ||
818 | |||
819 | regmap_read(regmap, REG_SPDIF_SRCD, &val); | ||
820 | ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0; | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | /* | ||
826 | * User bit sync mode: | ||
827 | * 1 CD User channel subcode | ||
828 | * 0 Non-CD data | ||
829 | */ | ||
830 | static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol, | ||
831 | struct snd_ctl_elem_value *ucontrol) | ||
832 | { | ||
833 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
834 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
835 | struct regmap *regmap = spdif_priv->regmap; | ||
836 | u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET; | ||
837 | |||
838 | regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val); | ||
839 | |||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | /* FSL SPDIF IEC958 controller defines */ | ||
844 | static struct snd_kcontrol_new fsl_spdif_ctrls[] = { | ||
845 | /* Status cchanel controller */ | ||
846 | { | ||
847 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
848 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
849 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
850 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
851 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
852 | .info = fsl_spdif_info, | ||
853 | .get = fsl_spdif_pb_get, | ||
854 | .put = fsl_spdif_pb_put, | ||
855 | }, | ||
856 | { | ||
857 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
858 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
859 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
860 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
861 | .info = fsl_spdif_info, | ||
862 | .get = fsl_spdif_capture_get, | ||
863 | }, | ||
864 | /* User bits controller */ | ||
865 | { | ||
866 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
867 | .name = "IEC958 Subcode Capture Default", | ||
868 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
869 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
870 | .info = fsl_spdif_info, | ||
871 | .get = fsl_spdif_subcode_get, | ||
872 | }, | ||
873 | { | ||
874 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
875 | .name = "IEC958 Q-subcode Capture Default", | ||
876 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
877 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
878 | .info = fsl_spdif_qinfo, | ||
879 | .get = fsl_spdif_qget, | ||
880 | }, | ||
881 | /* Valid bit error controller */ | ||
882 | { | ||
883 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
884 | .name = "IEC958 V-Bit Errors", | ||
885 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
886 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
887 | .info = fsl_spdif_vbit_info, | ||
888 | .get = fsl_spdif_vbit_get, | ||
889 | }, | ||
890 | /* DPLL lock info get controller */ | ||
891 | { | ||
892 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
893 | .name = "RX Sample Rate", | ||
894 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
895 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
896 | .info = fsl_spdif_rxrate_info, | ||
897 | .get = fsl_spdif_rxrate_get, | ||
898 | }, | ||
899 | /* User bit sync mode set/get controller */ | ||
900 | { | ||
901 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
902 | .name = "IEC958 USyncMode CDText", | ||
903 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
904 | SNDRV_CTL_ELEM_ACCESS_WRITE | | ||
905 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
906 | .info = fsl_spdif_usync_info, | ||
907 | .get = fsl_spdif_usync_get, | ||
908 | .put = fsl_spdif_usync_put, | ||
909 | }, | ||
910 | }; | ||
911 | |||
912 | static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | ||
913 | { | ||
914 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | ||
915 | |||
916 | dai->playback_dma_data = &spdif_private->dma_params_tx; | ||
917 | dai->capture_dma_data = &spdif_private->dma_params_rx; | ||
918 | |||
919 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | ||
920 | |||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | struct snd_soc_dai_driver fsl_spdif_dai = { | ||
925 | .probe = &fsl_spdif_dai_probe, | ||
926 | .playback = { | ||
927 | .channels_min = 2, | ||
928 | .channels_max = 2, | ||
929 | .rates = FSL_SPDIF_RATES_PLAYBACK, | ||
930 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, | ||
931 | }, | ||
932 | .capture = { | ||
933 | .channels_min = 2, | ||
934 | .channels_max = 2, | ||
935 | .rates = FSL_SPDIF_RATES_CAPTURE, | ||
936 | .formats = FSL_SPDIF_FORMATS_CAPTURE, | ||
937 | }, | ||
938 | .ops = &fsl_spdif_dai_ops, | ||
939 | }; | ||
940 | |||
941 | static const struct snd_soc_component_driver fsl_spdif_component = { | ||
942 | .name = "fsl-spdif", | ||
943 | }; | ||
944 | |||
945 | /* | ||
946 | * ================ | ||
947 | * FSL SPDIF REGMAP | ||
948 | * ================ | ||
949 | */ | ||
950 | |||
951 | static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) | ||
952 | { | ||
953 | switch (reg) { | ||
954 | case REG_SPDIF_SCR: | ||
955 | case REG_SPDIF_SRCD: | ||
956 | case REG_SPDIF_SRPC: | ||
957 | case REG_SPDIF_SIE: | ||
958 | case REG_SPDIF_SIS: | ||
959 | case REG_SPDIF_SRL: | ||
960 | case REG_SPDIF_SRR: | ||
961 | case REG_SPDIF_SRCSH: | ||
962 | case REG_SPDIF_SRCSL: | ||
963 | case REG_SPDIF_SRU: | ||
964 | case REG_SPDIF_SRQ: | ||
965 | case REG_SPDIF_STCSCH: | ||
966 | case REG_SPDIF_STCSCL: | ||
967 | case REG_SPDIF_SRFM: | ||
968 | case REG_SPDIF_STC: | ||
969 | return true; | ||
970 | default: | ||
971 | return false; | ||
972 | }; | ||
973 | } | ||
974 | |||
975 | static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | ||
976 | { | ||
977 | switch (reg) { | ||
978 | case REG_SPDIF_SCR: | ||
979 | case REG_SPDIF_SRCD: | ||
980 | case REG_SPDIF_SRPC: | ||
981 | case REG_SPDIF_SIE: | ||
982 | case REG_SPDIF_SIC: | ||
983 | case REG_SPDIF_STL: | ||
984 | case REG_SPDIF_STR: | ||
985 | case REG_SPDIF_STCSCH: | ||
986 | case REG_SPDIF_STCSCL: | ||
987 | case REG_SPDIF_STC: | ||
988 | return true; | ||
989 | default: | ||
990 | return false; | ||
991 | }; | ||
992 | } | ||
993 | |||
994 | static const struct regmap_config fsl_spdif_regmap_config = { | ||
995 | .reg_bits = 32, | ||
996 | .reg_stride = 4, | ||
997 | .val_bits = 32, | ||
998 | |||
999 | .max_register = REG_SPDIF_STC, | ||
1000 | .readable_reg = fsl_spdif_readable_reg, | ||
1001 | .writeable_reg = fsl_spdif_writeable_reg, | ||
1002 | }; | ||
1003 | |||
1004 | static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | ||
1005 | struct clk *clk, u64 savesub, | ||
1006 | enum spdif_txrate index) | ||
1007 | { | ||
1008 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1009 | u64 rate_ideal, rate_actual, sub; | ||
1010 | u32 div, arate; | ||
1011 | |||
1012 | for (div = 1; div <= 128; div++) { | ||
1013 | rate_ideal = rate[index] * (div + 1) * 64; | ||
1014 | rate_actual = clk_round_rate(clk, rate_ideal); | ||
1015 | |||
1016 | arate = rate_actual / 64; | ||
1017 | arate /= div; | ||
1018 | |||
1019 | if (arate == rate[index]) { | ||
1020 | /* We are lucky */ | ||
1021 | savesub = 0; | ||
1022 | spdif_priv->txclk_div[index] = div; | ||
1023 | break; | ||
1024 | } else if (arate / rate[index] == 1) { | ||
1025 | /* A little bigger than expect */ | ||
1026 | sub = (arate - rate[index]) * 100000; | ||
1027 | do_div(sub, rate[index]); | ||
1028 | if (sub < savesub) { | ||
1029 | savesub = sub; | ||
1030 | spdif_priv->txclk_div[index] = div; | ||
1031 | } | ||
1032 | } else if (rate[index] / arate == 1) { | ||
1033 | /* A little smaller than expect */ | ||
1034 | sub = (rate[index] - arate) * 100000; | ||
1035 | do_div(sub, rate[index]); | ||
1036 | if (sub < savesub) { | ||
1037 | savesub = sub; | ||
1038 | spdif_priv->txclk_div[index] = div; | ||
1039 | } | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | return savesub; | ||
1044 | } | ||
1045 | |||
1046 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, | ||
1047 | enum spdif_txrate index) | ||
1048 | { | ||
1049 | const u32 rate[] = { 32000, 44100, 48000 }; | ||
1050 | struct platform_device *pdev = spdif_priv->pdev; | ||
1051 | struct device *dev = &pdev->dev; | ||
1052 | u64 savesub = 100000, ret; | ||
1053 | struct clk *clk; | ||
1054 | char tmp[16]; | ||
1055 | int i; | ||
1056 | |||
1057 | for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { | ||
1058 | sprintf(tmp, "rxtx%d", i); | ||
1059 | clk = devm_clk_get(&pdev->dev, tmp); | ||
1060 | if (IS_ERR(clk)) { | ||
1061 | dev_err(dev, "no rxtx%d clock in devicetree\n", i); | ||
1062 | return PTR_ERR(clk); | ||
1063 | } | ||
1064 | if (!clk_get_rate(clk)) | ||
1065 | continue; | ||
1066 | |||
1067 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index); | ||
1068 | if (savesub == ret) | ||
1069 | continue; | ||
1070 | |||
1071 | savesub = ret; | ||
1072 | spdif_priv->txclk[index] = clk; | ||
1073 | spdif_priv->txclk_src[index] = i; | ||
1074 | |||
1075 | /* To quick catch a divisor, we allow a 0.1% deviation */ | ||
1076 | if (savesub < 100) | ||
1077 | break; | ||
1078 | } | ||
1079 | |||
1080 | dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate", | ||
1081 | spdif_priv->txclk_src[index], rate[index]); | ||
1082 | dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate", | ||
1083 | spdif_priv->txclk_div[index], rate[index]); | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static int fsl_spdif_probe(struct platform_device *pdev) | ||
1089 | { | ||
1090 | struct device_node *np = pdev->dev.of_node; | ||
1091 | struct fsl_spdif_priv *spdif_priv; | ||
1092 | struct spdif_mixer_control *ctrl; | ||
1093 | struct resource *res; | ||
1094 | void __iomem *regs; | ||
1095 | int irq, ret, i; | ||
1096 | |||
1097 | if (!np) | ||
1098 | return -ENODEV; | ||
1099 | |||
1100 | spdif_priv = devm_kzalloc(&pdev->dev, | ||
1101 | sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1, | ||
1102 | GFP_KERNEL); | ||
1103 | if (!spdif_priv) | ||
1104 | return -ENOMEM; | ||
1105 | |||
1106 | strcpy(spdif_priv->name, np->name); | ||
1107 | |||
1108 | spdif_priv->pdev = pdev; | ||
1109 | |||
1110 | /* Initialize this copy of the CPU DAI driver structure */ | ||
1111 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | ||
1112 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | ||
1113 | |||
1114 | /* Get the addresses and IRQ */ | ||
1115 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1116 | if (IS_ERR(res)) { | ||
1117 | dev_err(&pdev->dev, "could not determine device resources\n"); | ||
1118 | return PTR_ERR(res); | ||
1119 | } | ||
1120 | |||
1121 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
1122 | if (IS_ERR(regs)) { | ||
1123 | dev_err(&pdev->dev, "could not map device resources\n"); | ||
1124 | return PTR_ERR(regs); | ||
1125 | } | ||
1126 | |||
1127 | spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, | ||
1128 | "core", regs, &fsl_spdif_regmap_config); | ||
1129 | if (IS_ERR(spdif_priv->regmap)) { | ||
1130 | dev_err(&pdev->dev, "regmap init failed\n"); | ||
1131 | return PTR_ERR(spdif_priv->regmap); | ||
1132 | } | ||
1133 | |||
1134 | irq = platform_get_irq(pdev, 0); | ||
1135 | if (irq < 0) { | ||
1136 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | ||
1137 | return irq; | ||
1138 | } | ||
1139 | |||
1140 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, | ||
1141 | spdif_priv->name, spdif_priv); | ||
1142 | if (ret) { | ||
1143 | dev_err(&pdev->dev, "could not claim irq %u\n", irq); | ||
1144 | return ret; | ||
1145 | } | ||
1146 | |||
1147 | /* Select clock source for rx/tx clock */ | ||
1148 | spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); | ||
1149 | if (IS_ERR(spdif_priv->rxclk)) { | ||
1150 | dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); | ||
1151 | return PTR_ERR(spdif_priv->rxclk); | ||
1152 | } | ||
1153 | spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; | ||
1154 | |||
1155 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) { | ||
1156 | ret = fsl_spdif_probe_txclk(spdif_priv, i); | ||
1157 | if (ret) | ||
1158 | return ret; | ||
1159 | } | ||
1160 | |||
1161 | /* Initial spinlock for control data */ | ||
1162 | ctrl = &spdif_priv->fsl_spdif_control; | ||
1163 | spin_lock_init(&ctrl->ctl_lock); | ||
1164 | |||
1165 | /* Init tx channel status default value */ | ||
1166 | ctrl->ch_status[0] = | ||
1167 | IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015; | ||
1168 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; | ||
1169 | ctrl->ch_status[2] = 0x00; | ||
1170 | ctrl->ch_status[3] = | ||
1171 | IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM; | ||
1172 | |||
1173 | spdif_priv->dpll_locked = false; | ||
1174 | |||
1175 | spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; | ||
1176 | spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; | ||
1177 | spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; | ||
1178 | spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; | ||
1179 | |||
1180 | /* Register with ASoC */ | ||
1181 | dev_set_drvdata(&pdev->dev, spdif_priv); | ||
1182 | |||
1183 | ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component, | ||
1184 | &spdif_priv->cpu_dai_drv, 1); | ||
1185 | if (ret) { | ||
1186 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); | ||
1187 | goto error_dev; | ||
1188 | } | ||
1189 | |||
1190 | ret = imx_pcm_dma_init(pdev); | ||
1191 | if (ret) { | ||
1192 | dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); | ||
1193 | goto error_component; | ||
1194 | } | ||
1195 | |||
1196 | return ret; | ||
1197 | |||
1198 | error_component: | ||
1199 | snd_soc_unregister_component(&pdev->dev); | ||
1200 | error_dev: | ||
1201 | dev_set_drvdata(&pdev->dev, NULL); | ||
1202 | |||
1203 | return ret; | ||
1204 | } | ||
1205 | |||
1206 | static int fsl_spdif_remove(struct platform_device *pdev) | ||
1207 | { | ||
1208 | imx_pcm_dma_exit(pdev); | ||
1209 | snd_soc_unregister_component(&pdev->dev); | ||
1210 | dev_set_drvdata(&pdev->dev, NULL); | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static const struct of_device_id fsl_spdif_dt_ids[] = { | ||
1216 | { .compatible = "fsl,imx35-spdif", }, | ||
1217 | {} | ||
1218 | }; | ||
1219 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); | ||
1220 | |||
1221 | static struct platform_driver fsl_spdif_driver = { | ||
1222 | .driver = { | ||
1223 | .name = "fsl-spdif-dai", | ||
1224 | .owner = THIS_MODULE, | ||
1225 | .of_match_table = fsl_spdif_dt_ids, | ||
1226 | }, | ||
1227 | .probe = fsl_spdif_probe, | ||
1228 | .remove = fsl_spdif_remove, | ||
1229 | }; | ||
1230 | |||
1231 | module_platform_driver(fsl_spdif_driver); | ||
1232 | |||
1233 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | ||
1234 | MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver"); | ||
1235 | MODULE_LICENSE("GPL v2"); | ||
1236 | MODULE_ALIAS("platform:fsl-spdif-dai"); | ||
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h new file mode 100644 index 000000000000..b1266790d117 --- /dev/null +++ b/sound/soc/fsl/fsl_spdif.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC | ||
3 | * | ||
4 | * Copyright (C) 2013 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <b42378@freescale.com> | ||
7 | * | ||
8 | * Based on fsl_ssi.h | ||
9 | * Author: Timur Tabi <timur@freescale.com> | ||
10 | * Copyright 2007-2008 Freescale Semiconductor, Inc. | ||
11 | * | ||
12 | * This file is licensed under the terms of the GNU General Public License | ||
13 | * version 2. This program is licensed "as is" without any warranty of any | ||
14 | * kind, whether express or implied. | ||
15 | */ | ||
16 | |||
17 | #ifndef _FSL_SPDIF_DAI_H | ||
18 | #define _FSL_SPDIF_DAI_H | ||
19 | |||
20 | /* S/PDIF Register Map */ | ||
21 | #define REG_SPDIF_SCR 0x0 /* SPDIF Configuration Register */ | ||
22 | #define REG_SPDIF_SRCD 0x4 /* CDText Control Register */ | ||
23 | #define REG_SPDIF_SRPC 0x8 /* PhaseConfig Register */ | ||
24 | #define REG_SPDIF_SIE 0xc /* InterruptEn Register */ | ||
25 | #define REG_SPDIF_SIS 0x10 /* InterruptStat Register */ | ||
26 | #define REG_SPDIF_SIC 0x10 /* InterruptClear Register */ | ||
27 | #define REG_SPDIF_SRL 0x14 /* SPDIFRxLeft Register */ | ||
28 | #define REG_SPDIF_SRR 0x18 /* SPDIFRxRight Register */ | ||
29 | #define REG_SPDIF_SRCSH 0x1c /* SPDIFRxCChannel_h Register */ | ||
30 | #define REG_SPDIF_SRCSL 0x20 /* SPDIFRxCChannel_l Register */ | ||
31 | #define REG_SPDIF_SRU 0x24 /* UchannelRx Register */ | ||
32 | #define REG_SPDIF_SRQ 0x28 /* QchannelRx Register */ | ||
33 | #define REG_SPDIF_STL 0x2C /* SPDIFTxLeft Register */ | ||
34 | #define REG_SPDIF_STR 0x30 /* SPDIFTxRight Register */ | ||
35 | #define REG_SPDIF_STCSCH 0x34 /* SPDIFTxCChannelCons_h Register */ | ||
36 | #define REG_SPDIF_STCSCL 0x38 /* SPDIFTxCChannelCons_l Register */ | ||
37 | #define REG_SPDIF_SRFM 0x44 /* FreqMeas Register */ | ||
38 | #define REG_SPDIF_STC 0x50 /* SPDIFTxClk Register */ | ||
39 | |||
40 | |||
41 | /* SPDIF Configuration register */ | ||
42 | #define SCR_RXFIFO_CTL_OFFSET 23 | ||
43 | #define SCR_RXFIFO_CTL_MASK (1 << SCR_RXFIFO_CTL_OFFSET) | ||
44 | #define SCR_RXFIFO_CTL_ZERO (1 << SCR_RXFIFO_CTL_OFFSET) | ||
45 | #define SCR_RXFIFO_OFF_OFFSET 22 | ||
46 | #define SCR_RXFIFO_OFF_MASK (1 << SCR_RXFIFO_OFF_OFFSET) | ||
47 | #define SCR_RXFIFO_OFF (1 << SCR_RXFIFO_OFF_OFFSET) | ||
48 | #define SCR_RXFIFO_RST_OFFSET 21 | ||
49 | #define SCR_RXFIFO_RST_MASK (1 << SCR_RXFIFO_RST_OFFSET) | ||
50 | #define SCR_RXFIFO_RST (1 << SCR_RXFIFO_RST_OFFSET) | ||
51 | #define SCR_RXFIFO_FSEL_OFFSET 19 | ||
52 | #define SCR_RXFIFO_FSEL_MASK (0x3 << SCR_RXFIFO_FSEL_OFFSET) | ||
53 | #define SCR_RXFIFO_FSEL_IF0 (0x0 << SCR_RXFIFO_FSEL_OFFSET) | ||
54 | #define SCR_RXFIFO_FSEL_IF4 (0x1 << SCR_RXFIFO_FSEL_OFFSET) | ||
55 | #define SCR_RXFIFO_FSEL_IF8 (0x2 << SCR_RXFIFO_FSEL_OFFSET) | ||
56 | #define SCR_RXFIFO_FSEL_IF12 (0x3 << SCR_RXFIFO_FSEL_OFFSET) | ||
57 | #define SCR_RXFIFO_AUTOSYNC_OFFSET 18 | ||
58 | #define SCR_RXFIFO_AUTOSYNC_MASK (1 << SCR_RXFIFO_AUTOSYNC_OFFSET) | ||
59 | #define SCR_RXFIFO_AUTOSYNC (1 << SCR_RXFIFO_AUTOSYNC_OFFSET) | ||
60 | #define SCR_TXFIFO_AUTOSYNC_OFFSET 17 | ||
61 | #define SCR_TXFIFO_AUTOSYNC_MASK (1 << SCR_TXFIFO_AUTOSYNC_OFFSET) | ||
62 | #define SCR_TXFIFO_AUTOSYNC (1 << SCR_TXFIFO_AUTOSYNC_OFFSET) | ||
63 | #define SCR_TXFIFO_FSEL_OFFSET 15 | ||
64 | #define SCR_TXFIFO_FSEL_MASK (0x3 << SCR_TXFIFO_FSEL_OFFSET) | ||
65 | #define SCR_TXFIFO_FSEL_IF0 (0x0 << SCR_TXFIFO_FSEL_OFFSET) | ||
66 | #define SCR_TXFIFO_FSEL_IF4 (0x1 << SCR_TXFIFO_FSEL_OFFSET) | ||
67 | #define SCR_TXFIFO_FSEL_IF8 (0x2 << SCR_TXFIFO_FSEL_OFFSET) | ||
68 | #define SCR_TXFIFO_FSEL_IF12 (0x3 << SCR_TXFIFO_FSEL_OFFSET) | ||
69 | #define SCR_LOW_POWER (1 << 13) | ||
70 | #define SCR_SOFT_RESET (1 << 12) | ||
71 | #define SCR_TXFIFO_CTRL_OFFSET 10 | ||
72 | #define SCR_TXFIFO_CTRL_MASK (0x3 << SCR_TXFIFO_CTRL_OFFSET) | ||
73 | #define SCR_TXFIFO_CTRL_ZERO (0x0 << SCR_TXFIFO_CTRL_OFFSET) | ||
74 | #define SCR_TXFIFO_CTRL_NORMAL (0x1 << SCR_TXFIFO_CTRL_OFFSET) | ||
75 | #define SCR_TXFIFO_CTRL_ONESAMPLE (0x2 << SCR_TXFIFO_CTRL_OFFSET) | ||
76 | #define SCR_DMA_RX_EN_OFFSET 9 | ||
77 | #define SCR_DMA_RX_EN_MASK (1 << SCR_DMA_RX_EN_OFFSET) | ||
78 | #define SCR_DMA_RX_EN (1 << SCR_DMA_RX_EN_OFFSET) | ||
79 | #define SCR_DMA_TX_EN_OFFSET 8 | ||
80 | #define SCR_DMA_TX_EN_MASK (1 << SCR_DMA_TX_EN_OFFSET) | ||
81 | #define SCR_DMA_TX_EN (1 << SCR_DMA_TX_EN_OFFSET) | ||
82 | #define SCR_VAL_OFFSET 5 | ||
83 | #define SCR_VAL_MASK (1 << SCR_VAL_OFFSET) | ||
84 | #define SCR_VAL_CLEAR (1 << SCR_VAL_OFFSET) | ||
85 | #define SCR_TXSEL_OFFSET 2 | ||
86 | #define SCR_TXSEL_MASK (0x7 << SCR_TXSEL_OFFSET) | ||
87 | #define SCR_TXSEL_OFF (0 << SCR_TXSEL_OFFSET) | ||
88 | #define SCR_TXSEL_RX (1 << SCR_TXSEL_OFFSET) | ||
89 | #define SCR_TXSEL_NORMAL (0x5 << SCR_TXSEL_OFFSET) | ||
90 | #define SCR_USRC_SEL_OFFSET 0x0 | ||
91 | #define SCR_USRC_SEL_MASK (0x3 << SCR_USRC_SEL_OFFSET) | ||
92 | #define SCR_USRC_SEL_NONE (0x0 << SCR_USRC_SEL_OFFSET) | ||
93 | #define SCR_USRC_SEL_RECV (0x1 << SCR_USRC_SEL_OFFSET) | ||
94 | #define SCR_USRC_SEL_CHIP (0x3 << SCR_USRC_SEL_OFFSET) | ||
95 | |||
96 | /* SPDIF CDText control */ | ||
97 | #define SRCD_CD_USER_OFFSET 1 | ||
98 | #define SRCD_CD_USER (1 << SRCD_CD_USER_OFFSET) | ||
99 | |||
100 | /* SPDIF Phase Configuration register */ | ||
101 | #define SRPC_DPLL_LOCKED (1 << 6) | ||
102 | #define SRPC_CLKSRC_SEL_OFFSET 7 | ||
103 | #define SRPC_CLKSRC_SEL_MASK (0xf << SRPC_CLKSRC_SEL_OFFSET) | ||
104 | #define SRPC_CLKSRC_SEL_SET(x) ((x << SRPC_CLKSRC_SEL_OFFSET) & SRPC_CLKSRC_SEL_MASK) | ||
105 | #define SRPC_CLKSRC_SEL_LOCKED_OFFSET1 5 | ||
106 | #define SRPC_CLKSRC_SEL_LOCKED_OFFSET2 2 | ||
107 | #define SRPC_GAINSEL_OFFSET 3 | ||
108 | #define SRPC_GAINSEL_MASK (0x7 << SRPC_GAINSEL_OFFSET) | ||
109 | #define SRPC_GAINSEL_SET(x) ((x << SRPC_GAINSEL_OFFSET) & SRPC_GAINSEL_MASK) | ||
110 | |||
111 | #define SRPC_CLKSRC_MAX 16 | ||
112 | |||
113 | enum spdif_gainsel { | ||
114 | GAINSEL_MULTI_24 = 0, | ||
115 | GAINSEL_MULTI_16, | ||
116 | GAINSEL_MULTI_12, | ||
117 | GAINSEL_MULTI_8, | ||
118 | GAINSEL_MULTI_6, | ||
119 | GAINSEL_MULTI_4, | ||
120 | GAINSEL_MULTI_3, | ||
121 | }; | ||
122 | #define GAINSEL_MULTI_MAX (GAINSEL_MULTI_3 + 1) | ||
123 | #define SPDIF_DEFAULT_GAINSEL GAINSEL_MULTI_8 | ||
124 | |||
125 | /* SPDIF interrupt mask define */ | ||
126 | #define INT_DPLL_LOCKED (1 << 20) | ||
127 | #define INT_TXFIFO_UNOV (1 << 19) | ||
128 | #define INT_TXFIFO_RESYNC (1 << 18) | ||
129 | #define INT_CNEW (1 << 17) | ||
130 | #define INT_VAL_NOGOOD (1 << 16) | ||
131 | #define INT_SYM_ERR (1 << 15) | ||
132 | #define INT_BIT_ERR (1 << 14) | ||
133 | #define INT_URX_FUL (1 << 10) | ||
134 | #define INT_URX_OV (1 << 9) | ||
135 | #define INT_QRX_FUL (1 << 8) | ||
136 | #define INT_QRX_OV (1 << 7) | ||
137 | #define INT_UQ_SYNC (1 << 6) | ||
138 | #define INT_UQ_ERR (1 << 5) | ||
139 | #define INT_RXFIFO_UNOV (1 << 4) | ||
140 | #define INT_RXFIFO_RESYNC (1 << 3) | ||
141 | #define INT_LOSS_LOCK (1 << 2) | ||
142 | #define INT_TX_EM (1 << 1) | ||
143 | #define INT_RXFIFO_FUL (1 << 0) | ||
144 | |||
145 | /* SPDIF Clock register */ | ||
146 | #define STC_SYSCLK_DIV_OFFSET 11 | ||
147 | #define STC_SYSCLK_DIV_MASK (0x1ff << STC_TXCLK_SRC_OFFSET) | ||
148 | #define STC_SYSCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK) | ||
149 | #define STC_TXCLK_SRC_OFFSET 8 | ||
150 | #define STC_TXCLK_SRC_MASK (0x7 << STC_TXCLK_SRC_OFFSET) | ||
151 | #define STC_TXCLK_SRC_SET(x) ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK) | ||
152 | #define STC_TXCLK_ALL_EN_OFFSET 7 | ||
153 | #define STC_TXCLK_ALL_EN_MASK (1 << STC_TXCLK_ALL_EN_OFFSET) | ||
154 | #define STC_TXCLK_ALL_EN (1 << STC_TXCLK_ALL_EN_OFFSET) | ||
155 | #define STC_TXCLK_DIV_OFFSET 0 | ||
156 | #define STC_TXCLK_DIV_MASK (0x7ff << STC_TXCLK_DIV_OFFSET) | ||
157 | #define STC_TXCLK_DIV(x) ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK) | ||
158 | #define STC_TXCLK_SRC_MAX 8 | ||
159 | |||
160 | /* SPDIF tx rate */ | ||
161 | enum spdif_txrate { | ||
162 | SPDIF_TXRATE_32000 = 0, | ||
163 | SPDIF_TXRATE_44100, | ||
164 | SPDIF_TXRATE_48000, | ||
165 | }; | ||
166 | #define SPDIF_TXRATE_MAX (SPDIF_TXRATE_48000 + 1) | ||
167 | |||
168 | |||
169 | #define SPDIF_CSTATUS_BYTE 6 | ||
170 | #define SPDIF_UBITS_SIZE 96 | ||
171 | #define SPDIF_QSUB_SIZE (SPDIF_UBITS_SIZE / 8) | ||
172 | |||
173 | |||
174 | #define FSL_SPDIF_RATES_PLAYBACK (SNDRV_PCM_RATE_32000 | \ | ||
175 | SNDRV_PCM_RATE_44100 | \ | ||
176 | SNDRV_PCM_RATE_48000) | ||
177 | |||
178 | #define FSL_SPDIF_RATES_CAPTURE (SNDRV_PCM_RATE_16000 | \ | ||
179 | SNDRV_PCM_RATE_32000 | \ | ||
180 | SNDRV_PCM_RATE_44100 | \ | ||
181 | SNDRV_PCM_RATE_48000 | \ | ||
182 | SNDRV_PCM_RATE_64000 | \ | ||
183 | SNDRV_PCM_RATE_96000) | ||
184 | |||
185 | #define FSL_SPDIF_FORMATS_PLAYBACK (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
186 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
187 | SNDRV_PCM_FMTBIT_S24_LE) | ||
188 | |||
189 | #define FSL_SPDIF_FORMATS_CAPTURE (SNDRV_PCM_FMTBIT_S24_LE) | ||
190 | |||
191 | #endif /* _FSL_SPDIF_DAI_H */ | ||