Commit | Line | Data |
---|---|---|
a2388a49 NC |
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 | ||
add180ed | 16 | #include <linux/bitrev.h> |
a2388a49 | 17 | #include <linux/clk.h> |
add180ed | 18 | #include <linux/module.h> |
a2388a49 NC |
19 | #include <linux/of_address.h> |
20 | #include <linux/of_device.h> | |
21 | #include <linux/of_irq.h> | |
add180ed | 22 | #include <linux/regmap.h> |
a2388a49 NC |
23 | |
24 | #include <sound/asoundef.h> | |
a2388a49 | 25 | #include <sound/dmaengine_pcm.h> |
add180ed | 26 | #include <sound/soc.h> |
a2388a49 NC |
27 | |
28 | #include "fsl_spdif.h" | |
29 | #include "imx-pcm.h" | |
30 | ||
31 | #define FSL_SPDIF_TXFIFO_WML 0x8 | |
32 | #define FSL_SPDIF_RXFIFO_WML 0x8 | |
33 | ||
f3a30baa NC |
34 | #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) |
35 | #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL |\ | |
36 | INT_URX_OV | INT_QRX_FUL | INT_QRX_OV |\ | |
37 | INT_UQ_SYNC | INT_UQ_ERR | INT_RXFIFO_RESYNC |\ | |
38 | INT_LOSS_LOCK | INT_DPLL_LOCKED) | |
39 | ||
40 | #define SIE_INTR_FOR(tx) (tx ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE) | |
a2388a49 NC |
41 | |
42 | /* Index list for the values that has if (DPLL Locked) condition */ | |
43 | static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; | |
44 | #define SRPC_NODPLL_START1 0x5 | |
45 | #define SRPC_NODPLL_START2 0xc | |
46 | ||
47 | #define DEFAULT_RXCLK_SRC 1 | |
48 | ||
49 | /* | |
50 | * SPDIF control structure | |
51 | * Defines channel status, subcode and Q sub | |
52 | */ | |
53 | struct spdif_mixer_control { | |
54 | /* spinlock to access control data */ | |
55 | spinlock_t ctl_lock; | |
56 | ||
57 | /* IEC958 channel tx status bit */ | |
58 | unsigned char ch_status[4]; | |
59 | ||
60 | /* User bits */ | |
61 | unsigned char subcode[2 * SPDIF_UBITS_SIZE]; | |
62 | ||
63 | /* Q subcode part of user bits */ | |
64 | unsigned char qsub[2 * SPDIF_QSUB_SIZE]; | |
65 | ||
66 | /* Buffer offset for U/Q */ | |
67 | u32 upos; | |
68 | u32 qpos; | |
69 | ||
70 | /* Ready buffer index of the two buffers */ | |
71 | u32 ready_buf; | |
72 | }; | |
73 | ||
b8a832a0 NC |
74 | /** |
75 | * fsl_spdif_priv: Freescale SPDIF private data | |
76 | * | |
77 | * @fsl_spdif_control: SPDIF control data | |
78 | * @cpu_dai_drv: cpu dai driver | |
79 | * @pdev: platform device pointer | |
80 | * @regmap: regmap handler | |
81 | * @dpll_locked: dpll lock flag | |
82 | * @txrate: the best rates for playback | |
83 | * @txclk_df: STC_TXCLK_DF dividers value for playback | |
84 | * @sysclk_df: STC_SYSCLK_DF dividers value for playback | |
85 | * @txclk_src: STC_TXCLK_SRC values for playback | |
86 | * @rxclk_src: SRPC_CLKSRC_SEL values for capture | |
87 | * @txclk: tx clock sources for playback | |
88 | * @rxclk: rx clock sources for capture | |
89 | * @coreclk: core clock for register access via DMA | |
90 | * @sysclk: system clock for rx clock rate measurement | |
0bc5680a | 91 | * @spbaclk: SPBA clock (optional, depending on SoC design) |
b8a832a0 NC |
92 | * @dma_params_tx: DMA parameters for transmit channel |
93 | * @dma_params_rx: DMA parameters for receive channel | |
b8a832a0 | 94 | */ |
a2388a49 NC |
95 | struct fsl_spdif_priv { |
96 | struct spdif_mixer_control fsl_spdif_control; | |
97 | struct snd_soc_dai_driver cpu_dai_drv; | |
98 | struct platform_device *pdev; | |
99 | struct regmap *regmap; | |
100 | bool dpll_locked; | |
c7dfeed1 | 101 | u32 txrate[SPDIF_TXRATE_MAX]; |
e41a4a79 | 102 | u8 txclk_df[SPDIF_TXRATE_MAX]; |
27c647bf | 103 | u8 sysclk_df[SPDIF_TXRATE_MAX]; |
a2388a49 NC |
104 | u8 txclk_src[SPDIF_TXRATE_MAX]; |
105 | u8 rxclk_src; | |
106 | struct clk *txclk[SPDIF_TXRATE_MAX]; | |
107 | struct clk *rxclk; | |
08f7336e | 108 | struct clk *coreclk; |
0b864390 | 109 | struct clk *sysclk; |
0bc5680a | 110 | struct clk *spbaclk; |
a2388a49 NC |
111 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
112 | struct snd_dmaengine_dai_dma_data dma_params_rx; | |
f9f4fa61 ZW |
113 | /* regcache for SRPC */ |
114 | u32 regcache_srpc; | |
a2388a49 NC |
115 | }; |
116 | ||
a2388a49 NC |
117 | /* DPLL locked and lock loss interrupt handler */ |
118 | static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) | |
119 | { | |
120 | struct regmap *regmap = spdif_priv->regmap; | |
121 | struct platform_device *pdev = spdif_priv->pdev; | |
122 | u32 locked; | |
123 | ||
124 | regmap_read(regmap, REG_SPDIF_SRPC, &locked); | |
125 | locked &= SRPC_DPLL_LOCKED; | |
126 | ||
127 | dev_dbg(&pdev->dev, "isr: Rx dpll %s \n", | |
128 | locked ? "locked" : "loss lock"); | |
129 | ||
130 | spdif_priv->dpll_locked = locked ? true : false; | |
131 | } | |
132 | ||
133 | /* Receiver found illegal symbol interrupt handler */ | |
134 | static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv) | |
135 | { | |
136 | struct regmap *regmap = spdif_priv->regmap; | |
137 | struct platform_device *pdev = spdif_priv->pdev; | |
138 | ||
139 | dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); | |
140 | ||
f3a30baa NC |
141 | /* Clear illegal symbol if DPLL unlocked since no audio stream */ |
142 | if (!spdif_priv->dpll_locked) | |
a2388a49 | 143 | regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); |
a2388a49 NC |
144 | } |
145 | ||
146 | /* U/Q Channel receive register full */ | |
147 | static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name) | |
148 | { | |
149 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
150 | struct regmap *regmap = spdif_priv->regmap; | |
151 | struct platform_device *pdev = spdif_priv->pdev; | |
152 | u32 *pos, size, val, reg; | |
153 | ||
154 | switch (name) { | |
155 | case 'U': | |
156 | pos = &ctrl->upos; | |
157 | size = SPDIF_UBITS_SIZE; | |
158 | reg = REG_SPDIF_SRU; | |
159 | break; | |
160 | case 'Q': | |
161 | pos = &ctrl->qpos; | |
162 | size = SPDIF_QSUB_SIZE; | |
163 | reg = REG_SPDIF_SRQ; | |
164 | break; | |
165 | default: | |
166 | dev_err(&pdev->dev, "unsupported channel name\n"); | |
167 | return; | |
168 | } | |
169 | ||
170 | dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name); | |
171 | ||
172 | if (*pos >= size * 2) { | |
173 | *pos = 0; | |
174 | } else if (unlikely((*pos % size) + 3 > size)) { | |
175 | dev_err(&pdev->dev, "User bit receivce buffer overflow\n"); | |
176 | return; | |
177 | } | |
178 | ||
179 | regmap_read(regmap, reg, &val); | |
180 | ctrl->subcode[*pos++] = val >> 16; | |
181 | ctrl->subcode[*pos++] = val >> 8; | |
182 | ctrl->subcode[*pos++] = val; | |
183 | } | |
184 | ||
185 | /* U/Q Channel sync found */ | |
186 | static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv) | |
187 | { | |
188 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
189 | struct platform_device *pdev = spdif_priv->pdev; | |
190 | ||
191 | dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n"); | |
192 | ||
193 | /* U/Q buffer reset */ | |
194 | if (ctrl->qpos == 0) | |
195 | return; | |
196 | ||
197 | /* Set ready to this buffer */ | |
198 | ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1; | |
199 | } | |
200 | ||
201 | /* U/Q Channel framing error */ | |
202 | static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv) | |
203 | { | |
204 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
205 | struct regmap *regmap = spdif_priv->regmap; | |
206 | struct platform_device *pdev = spdif_priv->pdev; | |
207 | u32 val; | |
208 | ||
209 | dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n"); | |
210 | ||
211 | /* Read U/Q data to clear the irq and do buffer reset */ | |
212 | regmap_read(regmap, REG_SPDIF_SRU, &val); | |
213 | regmap_read(regmap, REG_SPDIF_SRQ, &val); | |
214 | ||
215 | /* Drop this U/Q buffer */ | |
216 | ctrl->ready_buf = 0; | |
217 | ctrl->upos = 0; | |
218 | ctrl->qpos = 0; | |
219 | } | |
220 | ||
221 | /* Get spdif interrupt status and clear the interrupt */ | |
222 | static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv) | |
223 | { | |
224 | struct regmap *regmap = spdif_priv->regmap; | |
225 | u32 val, val2; | |
226 | ||
227 | regmap_read(regmap, REG_SPDIF_SIS, &val); | |
228 | regmap_read(regmap, REG_SPDIF_SIE, &val2); | |
229 | ||
230 | regmap_write(regmap, REG_SPDIF_SIC, val & val2); | |
231 | ||
232 | return val; | |
233 | } | |
234 | ||
235 | static irqreturn_t spdif_isr(int irq, void *devid) | |
236 | { | |
237 | struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid; | |
238 | struct platform_device *pdev = spdif_priv->pdev; | |
239 | u32 sis; | |
240 | ||
241 | sis = spdif_intr_status_clear(spdif_priv); | |
242 | ||
243 | if (sis & INT_DPLL_LOCKED) | |
244 | spdif_irq_dpll_lock(spdif_priv); | |
245 | ||
246 | if (sis & INT_TXFIFO_UNOV) | |
247 | dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n"); | |
248 | ||
249 | if (sis & INT_TXFIFO_RESYNC) | |
250 | dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n"); | |
251 | ||
252 | if (sis & INT_CNEW) | |
253 | dev_dbg(&pdev->dev, "isr: cstatus new\n"); | |
254 | ||
255 | if (sis & INT_VAL_NOGOOD) | |
256 | dev_dbg(&pdev->dev, "isr: validity flag no good\n"); | |
257 | ||
258 | if (sis & INT_SYM_ERR) | |
259 | spdif_irq_sym_error(spdif_priv); | |
260 | ||
261 | if (sis & INT_BIT_ERR) | |
262 | dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n"); | |
263 | ||
264 | if (sis & INT_URX_FUL) | |
265 | spdif_irq_uqrx_full(spdif_priv, 'U'); | |
266 | ||
267 | if (sis & INT_URX_OV) | |
268 | dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n"); | |
269 | ||
270 | if (sis & INT_QRX_FUL) | |
271 | spdif_irq_uqrx_full(spdif_priv, 'Q'); | |
272 | ||
273 | if (sis & INT_QRX_OV) | |
274 | dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n"); | |
275 | ||
276 | if (sis & INT_UQ_SYNC) | |
277 | spdif_irq_uq_sync(spdif_priv); | |
278 | ||
279 | if (sis & INT_UQ_ERR) | |
280 | spdif_irq_uq_err(spdif_priv); | |
281 | ||
282 | if (sis & INT_RXFIFO_UNOV) | |
283 | dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n"); | |
284 | ||
285 | if (sis & INT_RXFIFO_RESYNC) | |
286 | dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n"); | |
287 | ||
288 | if (sis & INT_LOSS_LOCK) | |
289 | spdif_irq_dpll_lock(spdif_priv); | |
290 | ||
291 | /* FIXME: Write Tx FIFO to clear TxEm */ | |
292 | if (sis & INT_TX_EM) | |
293 | dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n"); | |
294 | ||
295 | /* FIXME: Read Rx FIFO to clear RxFIFOFul */ | |
296 | if (sis & INT_RXFIFO_FUL) | |
297 | dev_dbg(&pdev->dev, "isr: Rx FIFO full\n"); | |
298 | ||
299 | return IRQ_HANDLED; | |
300 | } | |
301 | ||
302 | static int spdif_softreset(struct fsl_spdif_priv *spdif_priv) | |
303 | { | |
304 | struct regmap *regmap = spdif_priv->regmap; | |
305 | u32 val, cycle = 1000; | |
306 | ||
f9f4fa61 ZW |
307 | regcache_cache_bypass(regmap, true); |
308 | ||
a2388a49 NC |
309 | regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET); |
310 | ||
311 | /* | |
312 | * RESET bit would be cleared after finishing its reset procedure, | |
313 | * which typically lasts 8 cycles. 1000 cycles will keep it safe. | |
314 | */ | |
315 | do { | |
316 | regmap_read(regmap, REG_SPDIF_SCR, &val); | |
317 | } while ((val & SCR_SOFT_RESET) && cycle--); | |
318 | ||
f9f4fa61 ZW |
319 | regcache_cache_bypass(regmap, false); |
320 | regcache_mark_dirty(regmap); | |
321 | regcache_sync(regmap); | |
322 | ||
a2388a49 NC |
323 | if (cycle) |
324 | return 0; | |
325 | else | |
326 | return -EBUSY; | |
327 | } | |
328 | ||
329 | static void spdif_set_cstatus(struct spdif_mixer_control *ctrl, | |
330 | u8 mask, u8 cstatus) | |
331 | { | |
332 | ctrl->ch_status[3] &= ~mask; | |
333 | ctrl->ch_status[3] |= cstatus & mask; | |
334 | } | |
335 | ||
336 | static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv) | |
337 | { | |
338 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
339 | struct regmap *regmap = spdif_priv->regmap; | |
340 | struct platform_device *pdev = spdif_priv->pdev; | |
341 | u32 ch_status; | |
342 | ||
343 | ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | | |
f3a30baa NC |
344 | (bitrev8(ctrl->ch_status[1]) << 8) | |
345 | bitrev8(ctrl->ch_status[2]); | |
a2388a49 NC |
346 | regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); |
347 | ||
348 | dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); | |
349 | ||
350 | ch_status = bitrev8(ctrl->ch_status[3]) << 16; | |
351 | regmap_write(regmap, REG_SPDIF_STCSCL, ch_status); | |
352 | ||
353 | dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status); | |
354 | } | |
355 | ||
356 | /* Set SPDIF PhaseConfig register for rx clock */ | |
357 | static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, | |
358 | enum spdif_gainsel gainsel, int dpll_locked) | |
359 | { | |
360 | struct regmap *regmap = spdif_priv->regmap; | |
361 | u8 clksrc = spdif_priv->rxclk_src; | |
362 | ||
363 | if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX) | |
364 | return -EINVAL; | |
365 | ||
366 | regmap_update_bits(regmap, REG_SPDIF_SRPC, | |
367 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, | |
368 | SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel)); | |
369 | ||
370 | return 0; | |
371 | } | |
372 | ||
373 | static int spdif_set_sample_rate(struct snd_pcm_substream *substream, | |
374 | int sample_rate) | |
375 | { | |
376 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
377 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | |
378 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
379 | struct regmap *regmap = spdif_priv->regmap; | |
380 | struct platform_device *pdev = spdif_priv->pdev; | |
381 | unsigned long csfs = 0; | |
382 | u32 stc, mask, rate; | |
27c647bf | 383 | u8 clk, txclk_df, sysclk_df; |
a2388a49 NC |
384 | int ret; |
385 | ||
386 | switch (sample_rate) { | |
387 | case 32000: | |
388 | rate = SPDIF_TXRATE_32000; | |
389 | csfs = IEC958_AES3_CON_FS_32000; | |
390 | break; | |
391 | case 44100: | |
392 | rate = SPDIF_TXRATE_44100; | |
393 | csfs = IEC958_AES3_CON_FS_44100; | |
394 | break; | |
395 | case 48000: | |
396 | rate = SPDIF_TXRATE_48000; | |
397 | csfs = IEC958_AES3_CON_FS_48000; | |
398 | break; | |
c7dfeed1 AH |
399 | case 96000: |
400 | rate = SPDIF_TXRATE_96000; | |
401 | csfs = IEC958_AES3_CON_FS_96000; | |
402 | break; | |
403 | case 192000: | |
404 | rate = SPDIF_TXRATE_192000; | |
405 | csfs = IEC958_AES3_CON_FS_192000; | |
406 | break; | |
a2388a49 NC |
407 | default: |
408 | dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); | |
409 | return -EINVAL; | |
410 | } | |
411 | ||
412 | clk = spdif_priv->txclk_src[rate]; | |
413 | if (clk >= STC_TXCLK_SRC_MAX) { | |
414 | dev_err(&pdev->dev, "tx clock source is out of range\n"); | |
415 | return -EINVAL; | |
416 | } | |
417 | ||
e41a4a79 NC |
418 | txclk_df = spdif_priv->txclk_df[rate]; |
419 | if (txclk_df == 0) { | |
420 | dev_err(&pdev->dev, "the txclk_df can't be zero\n"); | |
a2388a49 NC |
421 | return -EINVAL; |
422 | } | |
423 | ||
27c647bf NC |
424 | sysclk_df = spdif_priv->sysclk_df[rate]; |
425 | ||
9c6344b3 NC |
426 | /* Don't mess up the clocks from other modules */ |
427 | if (clk != STC_TXCLK_SPDIF_ROOT) | |
428 | goto clk_set_bypass; | |
429 | ||
f490f326 NC |
430 | /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ |
431 | ret = clk_set_rate(spdif_priv->txclk[rate], | |
432 | 64 * sample_rate * txclk_df); | |
a2388a49 NC |
433 | if (ret) { |
434 | dev_err(&pdev->dev, "failed to set tx clock rate\n"); | |
435 | return ret; | |
436 | } | |
437 | ||
9c6344b3 | 438 | clk_set_bypass: |
a2388a49 | 439 | dev_dbg(&pdev->dev, "expected clock rate = %d\n", |
27c647bf | 440 | (64 * sample_rate * txclk_df * sysclk_df)); |
a2388a49 NC |
441 | dev_dbg(&pdev->dev, "actual clock rate = %ld\n", |
442 | clk_get_rate(spdif_priv->txclk[rate])); | |
443 | ||
444 | /* set fs field in consumer channel status */ | |
445 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); | |
446 | ||
447 | /* select clock source and divisor */ | |
f3a30baa NC |
448 | stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | |
449 | STC_TXCLK_DF(txclk_df) | STC_SYSCLK_DF(sysclk_df); | |
450 | mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | | |
451 | STC_TXCLK_DF_MASK | STC_SYSCLK_DF_MASK; | |
a2388a49 NC |
452 | regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); |
453 | ||
527cda78 NC |
454 | dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n", |
455 | spdif_priv->txrate[rate], sample_rate); | |
a2388a49 NC |
456 | |
457 | return 0; | |
458 | } | |
459 | ||
6b4c80f9 MB |
460 | static int fsl_spdif_startup(struct snd_pcm_substream *substream, |
461 | struct snd_soc_dai *cpu_dai) | |
a2388a49 NC |
462 | { |
463 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
464 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | |
465 | struct platform_device *pdev = spdif_priv->pdev; | |
466 | struct regmap *regmap = spdif_priv->regmap; | |
89e0e250 DC |
467 | u32 scr, mask; |
468 | int i; | |
a2388a49 NC |
469 | int ret; |
470 | ||
471 | /* Reset module and interrupts only for first initialization */ | |
472 | if (!cpu_dai->active) { | |
08f7336e NC |
473 | ret = clk_prepare_enable(spdif_priv->coreclk); |
474 | if (ret) { | |
475 | dev_err(&pdev->dev, "failed to enable core clock\n"); | |
476 | return ret; | |
477 | } | |
478 | ||
0bc5680a SW |
479 | if (!IS_ERR(spdif_priv->spbaclk)) { |
480 | ret = clk_prepare_enable(spdif_priv->spbaclk); | |
481 | if (ret) { | |
482 | dev_err(&pdev->dev, "failed to enable spba clock\n"); | |
483 | goto err_spbaclk; | |
484 | } | |
485 | } | |
486 | ||
a2388a49 NC |
487 | ret = spdif_softreset(spdif_priv); |
488 | if (ret) { | |
489 | dev_err(&pdev->dev, "failed to soft reset\n"); | |
08f7336e | 490 | goto err; |
a2388a49 NC |
491 | } |
492 | ||
493 | /* Disable all the interrupts */ | |
494 | regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0); | |
495 | } | |
496 | ||
497 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
498 | scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL | | |
499 | SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP | | |
500 | SCR_TXFIFO_FSEL_IF8; | |
501 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | |
502 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | |
503 | SCR_TXFIFO_FSEL_MASK; | |
fa3be920 FE |
504 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) { |
505 | ret = clk_prepare_enable(spdif_priv->txclk[i]); | |
506 | if (ret) | |
507 | goto disable_txclk; | |
508 | } | |
a2388a49 NC |
509 | } else { |
510 | scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; | |
511 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | |
512 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | |
fa3be920 FE |
513 | ret = clk_prepare_enable(spdif_priv->rxclk); |
514 | if (ret) | |
515 | goto err; | |
a2388a49 NC |
516 | } |
517 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | |
518 | ||
519 | /* Power up SPDIF module */ | |
520 | regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); | |
521 | ||
522 | return 0; | |
08f7336e | 523 | |
fa3be920 FE |
524 | disable_txclk: |
525 | for (i--; i >= 0; i--) | |
526 | clk_disable_unprepare(spdif_priv->txclk[i]); | |
08f7336e | 527 | err: |
0bc5680a SW |
528 | if (!IS_ERR(spdif_priv->spbaclk)) |
529 | clk_disable_unprepare(spdif_priv->spbaclk); | |
530 | err_spbaclk: | |
08f7336e NC |
531 | clk_disable_unprepare(spdif_priv->coreclk); |
532 | ||
533 | return ret; | |
a2388a49 NC |
534 | } |
535 | ||
536 | static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, | |
537 | struct snd_soc_dai *cpu_dai) | |
538 | { | |
539 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
540 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | |
541 | struct regmap *regmap = spdif_priv->regmap; | |
542 | u32 scr, mask, i; | |
543 | ||
544 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
545 | scr = 0; | |
546 | mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | | |
547 | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | | |
548 | SCR_TXFIFO_FSEL_MASK; | |
549 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) | |
550 | clk_disable_unprepare(spdif_priv->txclk[i]); | |
551 | } else { | |
552 | scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; | |
553 | mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| | |
554 | SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; | |
555 | clk_disable_unprepare(spdif_priv->rxclk); | |
556 | } | |
557 | regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); | |
558 | ||
559 | /* Power down SPDIF module only if tx&rx are both inactive */ | |
560 | if (!cpu_dai->active) { | |
561 | spdif_intr_status_clear(spdif_priv); | |
562 | regmap_update_bits(regmap, REG_SPDIF_SCR, | |
563 | SCR_LOW_POWER, SCR_LOW_POWER); | |
0bc5680a SW |
564 | if (!IS_ERR(spdif_priv->spbaclk)) |
565 | clk_disable_unprepare(spdif_priv->spbaclk); | |
08f7336e | 566 | clk_disable_unprepare(spdif_priv->coreclk); |
a2388a49 NC |
567 | } |
568 | } | |
569 | ||
570 | static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, | |
571 | struct snd_pcm_hw_params *params, | |
572 | struct snd_soc_dai *dai) | |
573 | { | |
574 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
575 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | |
576 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
577 | struct platform_device *pdev = spdif_priv->pdev; | |
578 | u32 sample_rate = params_rate(params); | |
579 | int ret = 0; | |
580 | ||
581 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
582 | ret = spdif_set_sample_rate(substream, sample_rate); | |
583 | if (ret) { | |
584 | dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", | |
585 | __func__, sample_rate); | |
586 | return ret; | |
587 | } | |
588 | spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, | |
f3a30baa | 589 | IEC958_AES3_CON_CLOCK_1000PPM); |
a2388a49 NC |
590 | spdif_write_channel_status(spdif_priv); |
591 | } else { | |
592 | /* Setup rx clock source */ | |
593 | ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); | |
594 | } | |
595 | ||
596 | return ret; | |
597 | } | |
598 | ||
599 | static int fsl_spdif_trigger(struct snd_pcm_substream *substream, | |
600 | int cmd, struct snd_soc_dai *dai) | |
601 | { | |
602 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
603 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); | |
604 | struct regmap *regmap = spdif_priv->regmap; | |
f3a30baa NC |
605 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
606 | u32 intr = SIE_INTR_FOR(tx); | |
607 | u32 dmaen = SCR_DMA_xX_EN(tx); | |
a2388a49 NC |
608 | |
609 | switch (cmd) { | |
610 | case SNDRV_PCM_TRIGGER_START: | |
611 | case SNDRV_PCM_TRIGGER_RESUME: | |
612 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | |
613 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr); | |
614 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen); | |
615 | break; | |
616 | case SNDRV_PCM_TRIGGER_STOP: | |
617 | case SNDRV_PCM_TRIGGER_SUSPEND: | |
618 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | |
619 | regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0); | |
620 | regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0); | |
621 | break; | |
622 | default: | |
623 | return -EINVAL; | |
624 | } | |
625 | ||
626 | return 0; | |
627 | } | |
628 | ||
6b4c80f9 | 629 | static struct snd_soc_dai_ops fsl_spdif_dai_ops = { |
a2388a49 NC |
630 | .startup = fsl_spdif_startup, |
631 | .hw_params = fsl_spdif_hw_params, | |
632 | .trigger = fsl_spdif_trigger, | |
633 | .shutdown = fsl_spdif_shutdown, | |
634 | }; | |
635 | ||
636 | ||
637 | /* | |
a2388a49 NC |
638 | * FSL SPDIF IEC958 controller(mixer) functions |
639 | * | |
640 | * Channel status get/put control | |
641 | * User bit value get/put control | |
642 | * Valid bit value get control | |
643 | * DPLL lock status get control | |
644 | * User bit sync mode selection control | |
a2388a49 NC |
645 | */ |
646 | ||
647 | static int fsl_spdif_info(struct snd_kcontrol *kcontrol, | |
648 | struct snd_ctl_elem_info *uinfo) | |
649 | { | |
650 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | |
651 | uinfo->count = 1; | |
652 | ||
653 | return 0; | |
654 | } | |
655 | ||
656 | static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol, | |
657 | struct snd_ctl_elem_value *uvalue) | |
658 | { | |
659 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
660 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
661 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
662 | ||
663 | uvalue->value.iec958.status[0] = ctrl->ch_status[0]; | |
664 | uvalue->value.iec958.status[1] = ctrl->ch_status[1]; | |
665 | uvalue->value.iec958.status[2] = ctrl->ch_status[2]; | |
666 | uvalue->value.iec958.status[3] = ctrl->ch_status[3]; | |
667 | ||
668 | return 0; | |
669 | } | |
670 | ||
671 | static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol, | |
672 | struct snd_ctl_elem_value *uvalue) | |
673 | { | |
674 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
675 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
676 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
677 | ||
678 | ctrl->ch_status[0] = uvalue->value.iec958.status[0]; | |
679 | ctrl->ch_status[1] = uvalue->value.iec958.status[1]; | |
680 | ctrl->ch_status[2] = uvalue->value.iec958.status[2]; | |
681 | ctrl->ch_status[3] = uvalue->value.iec958.status[3]; | |
682 | ||
683 | spdif_write_channel_status(spdif_priv); | |
684 | ||
685 | return 0; | |
686 | } | |
687 | ||
688 | /* Get channel status from SPDIF_RX_CCHAN register */ | |
689 | static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, | |
690 | struct snd_ctl_elem_value *ucontrol) | |
691 | { | |
692 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
693 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
694 | struct regmap *regmap = spdif_priv->regmap; | |
695 | u32 cstatus, val; | |
696 | ||
697 | regmap_read(regmap, REG_SPDIF_SIS, &val); | |
f3a30baa | 698 | if (!(val & INT_CNEW)) |
a2388a49 | 699 | return -EAGAIN; |
a2388a49 NC |
700 | |
701 | regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); | |
702 | ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; | |
703 | ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF; | |
704 | ucontrol->value.iec958.status[2] = cstatus & 0xFF; | |
705 | ||
706 | regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus); | |
707 | ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF; | |
708 | ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF; | |
709 | ucontrol->value.iec958.status[5] = cstatus & 0xFF; | |
710 | ||
711 | /* Clear intr */ | |
712 | regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW); | |
713 | ||
714 | return 0; | |
715 | } | |
716 | ||
717 | /* | |
718 | * Get User bits (subcode) from chip value which readed out | |
719 | * in UChannel register. | |
720 | */ | |
721 | static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, | |
722 | struct snd_ctl_elem_value *ucontrol) | |
723 | { | |
724 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
725 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
726 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
727 | unsigned long flags; | |
f3a30baa | 728 | int ret = -EAGAIN; |
a2388a49 NC |
729 | |
730 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | |
731 | if (ctrl->ready_buf) { | |
732 | int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; | |
733 | memcpy(&ucontrol->value.iec958.subcode[0], | |
734 | &ctrl->subcode[idx], SPDIF_UBITS_SIZE); | |
f3a30baa | 735 | ret = 0; |
a2388a49 NC |
736 | } |
737 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | |
738 | ||
739 | return ret; | |
740 | } | |
741 | ||
dcfcf2c2 | 742 | /* Q-subcode information. The byte size is SPDIF_UBITS_SIZE/8 */ |
a2388a49 NC |
743 | static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, |
744 | struct snd_ctl_elem_info *uinfo) | |
745 | { | |
746 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | |
747 | uinfo->count = SPDIF_QSUB_SIZE; | |
748 | ||
749 | return 0; | |
750 | } | |
751 | ||
752 | /* Get Q subcode from chip value which readed out in QChannel register */ | |
753 | static int fsl_spdif_qget(struct snd_kcontrol *kcontrol, | |
754 | struct snd_ctl_elem_value *ucontrol) | |
755 | { | |
756 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
757 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
758 | struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; | |
759 | unsigned long flags; | |
f3a30baa | 760 | int ret = -EAGAIN; |
a2388a49 NC |
761 | |
762 | spin_lock_irqsave(&ctrl->ctl_lock, flags); | |
763 | if (ctrl->ready_buf) { | |
764 | int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; | |
765 | memcpy(&ucontrol->value.bytes.data[0], | |
766 | &ctrl->qsub[idx], SPDIF_QSUB_SIZE); | |
f3a30baa | 767 | ret = 0; |
a2388a49 NC |
768 | } |
769 | spin_unlock_irqrestore(&ctrl->ctl_lock, flags); | |
770 | ||
771 | return ret; | |
772 | } | |
773 | ||
dcfcf2c2 | 774 | /* Valid bit information */ |
a2388a49 NC |
775 | static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, |
776 | struct snd_ctl_elem_info *uinfo) | |
777 | { | |
778 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |
779 | uinfo->count = 1; | |
780 | uinfo->value.integer.min = 0; | |
781 | uinfo->value.integer.max = 1; | |
782 | ||
783 | return 0; | |
784 | } | |
785 | ||
786 | /* Get valid good bit from interrupt status register */ | |
787 | static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol, | |
788 | struct snd_ctl_elem_value *ucontrol) | |
789 | { | |
790 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
791 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
792 | struct regmap *regmap = spdif_priv->regmap; | |
793 | u32 val; | |
794 | ||
e9b383dc | 795 | regmap_read(regmap, REG_SPDIF_SIS, &val); |
a2388a49 NC |
796 | ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; |
797 | regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); | |
798 | ||
799 | return 0; | |
800 | } | |
801 | ||
dcfcf2c2 | 802 | /* DPLL lock information */ |
a2388a49 NC |
803 | static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, |
804 | struct snd_ctl_elem_info *uinfo) | |
805 | { | |
806 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
807 | uinfo->count = 1; | |
808 | uinfo->value.integer.min = 16000; | |
809 | uinfo->value.integer.max = 96000; | |
810 | ||
811 | return 0; | |
812 | } | |
813 | ||
814 | static u32 gainsel_multi[GAINSEL_MULTI_MAX] = { | |
815 | 24, 16, 12, 8, 6, 4, 3, | |
816 | }; | |
817 | ||
818 | /* Get RX data clock rate given the SPDIF bus_clk */ | |
819 | static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, | |
820 | enum spdif_gainsel gainsel) | |
821 | { | |
822 | struct regmap *regmap = spdif_priv->regmap; | |
823 | struct platform_device *pdev = spdif_priv->pdev; | |
824 | u64 tmpval64, busclk_freq = 0; | |
825 | u32 freqmeas, phaseconf; | |
826 | u8 clksrc; | |
827 | ||
828 | regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas); | |
829 | regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); | |
830 | ||
831 | clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; | |
f3a30baa NC |
832 | |
833 | /* Get bus clock from system */ | |
834 | if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) | |
0b864390 | 835 | busclk_freq = clk_get_rate(spdif_priv->sysclk); |
a2388a49 NC |
836 | |
837 | /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ | |
838 | tmpval64 = (u64) busclk_freq * freqmeas; | |
839 | do_div(tmpval64, gainsel_multi[gainsel] * 1024); | |
840 | do_div(tmpval64, 128 * 1024); | |
841 | ||
842 | dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas); | |
843 | dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq); | |
844 | dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64); | |
845 | ||
846 | return (int)tmpval64; | |
847 | } | |
848 | ||
849 | /* | |
850 | * Get DPLL lock or not info from stable interrupt status register. | |
851 | * User application must use this control to get locked, | |
852 | * then can do next PCM operation | |
853 | */ | |
854 | static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, | |
855 | struct snd_ctl_elem_value *ucontrol) | |
856 | { | |
857 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
858 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
f3a30baa | 859 | int rate = 0; |
a2388a49 NC |
860 | |
861 | if (spdif_priv->dpll_locked) | |
f3a30baa NC |
862 | rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); |
863 | ||
864 | ucontrol->value.integer.value[0] = rate; | |
a2388a49 NC |
865 | |
866 | return 0; | |
867 | } | |
868 | ||
869 | /* User bit sync mode info */ | |
870 | static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, | |
871 | struct snd_ctl_elem_info *uinfo) | |
872 | { | |
873 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | |
874 | uinfo->count = 1; | |
875 | uinfo->value.integer.min = 0; | |
876 | uinfo->value.integer.max = 1; | |
877 | ||
878 | return 0; | |
879 | } | |
880 | ||
881 | /* | |
882 | * User bit sync mode: | |
883 | * 1 CD User channel subcode | |
884 | * 0 Non-CD data | |
885 | */ | |
886 | static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol, | |
887 | struct snd_ctl_elem_value *ucontrol) | |
888 | { | |
889 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
890 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
891 | struct regmap *regmap = spdif_priv->regmap; | |
892 | u32 val; | |
893 | ||
894 | regmap_read(regmap, REG_SPDIF_SRCD, &val); | |
895 | ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0; | |
896 | ||
897 | return 0; | |
898 | } | |
899 | ||
900 | /* | |
901 | * User bit sync mode: | |
902 | * 1 CD User channel subcode | |
903 | * 0 Non-CD data | |
904 | */ | |
905 | static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol, | |
906 | struct snd_ctl_elem_value *ucontrol) | |
907 | { | |
908 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | |
909 | struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); | |
910 | struct regmap *regmap = spdif_priv->regmap; | |
911 | u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET; | |
912 | ||
913 | regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val); | |
914 | ||
915 | return 0; | |
916 | } | |
917 | ||
918 | /* FSL SPDIF IEC958 controller defines */ | |
919 | static struct snd_kcontrol_new fsl_spdif_ctrls[] = { | |
920 | /* Status cchanel controller */ | |
921 | { | |
922 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
923 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | |
924 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
925 | SNDRV_CTL_ELEM_ACCESS_WRITE | | |
926 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
927 | .info = fsl_spdif_info, | |
928 | .get = fsl_spdif_pb_get, | |
929 | .put = fsl_spdif_pb_put, | |
930 | }, | |
931 | { | |
932 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
933 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | |
934 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
935 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
936 | .info = fsl_spdif_info, | |
937 | .get = fsl_spdif_capture_get, | |
938 | }, | |
939 | /* User bits controller */ | |
940 | { | |
941 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
942 | .name = "IEC958 Subcode Capture Default", | |
943 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
944 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
945 | .info = fsl_spdif_info, | |
946 | .get = fsl_spdif_subcode_get, | |
947 | }, | |
948 | { | |
949 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
950 | .name = "IEC958 Q-subcode Capture Default", | |
951 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
952 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
953 | .info = fsl_spdif_qinfo, | |
954 | .get = fsl_spdif_qget, | |
955 | }, | |
956 | /* Valid bit error controller */ | |
957 | { | |
958 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
959 | .name = "IEC958 V-Bit Errors", | |
960 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
961 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
962 | .info = fsl_spdif_vbit_info, | |
963 | .get = fsl_spdif_vbit_get, | |
964 | }, | |
965 | /* DPLL lock info get controller */ | |
966 | { | |
967 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
968 | .name = "RX Sample Rate", | |
969 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
970 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
971 | .info = fsl_spdif_rxrate_info, | |
972 | .get = fsl_spdif_rxrate_get, | |
973 | }, | |
974 | /* User bit sync mode set/get controller */ | |
975 | { | |
976 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | |
977 | .name = "IEC958 USyncMode CDText", | |
978 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | |
979 | SNDRV_CTL_ELEM_ACCESS_WRITE | | |
980 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | |
981 | .info = fsl_spdif_usync_info, | |
982 | .get = fsl_spdif_usync_get, | |
983 | .put = fsl_spdif_usync_put, | |
984 | }, | |
985 | }; | |
986 | ||
987 | static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | |
988 | { | |
989 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | |
990 | ||
05cf482d XL |
991 | snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx, |
992 | &spdif_private->dma_params_rx); | |
a2388a49 NC |
993 | |
994 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | |
995 | ||
996 | return 0; | |
997 | } | |
998 | ||
6b4c80f9 | 999 | static struct snd_soc_dai_driver fsl_spdif_dai = { |
a2388a49 NC |
1000 | .probe = &fsl_spdif_dai_probe, |
1001 | .playback = { | |
75640932 | 1002 | .stream_name = "CPU-Playback", |
a2388a49 NC |
1003 | .channels_min = 2, |
1004 | .channels_max = 2, | |
1005 | .rates = FSL_SPDIF_RATES_PLAYBACK, | |
1006 | .formats = FSL_SPDIF_FORMATS_PLAYBACK, | |
1007 | }, | |
1008 | .capture = { | |
75640932 | 1009 | .stream_name = "CPU-Capture", |
a2388a49 NC |
1010 | .channels_min = 2, |
1011 | .channels_max = 2, | |
1012 | .rates = FSL_SPDIF_RATES_CAPTURE, | |
1013 | .formats = FSL_SPDIF_FORMATS_CAPTURE, | |
1014 | }, | |
1015 | .ops = &fsl_spdif_dai_ops, | |
1016 | }; | |
1017 | ||
1018 | static const struct snd_soc_component_driver fsl_spdif_component = { | |
1019 | .name = "fsl-spdif", | |
1020 | }; | |
1021 | ||
6d22db43 | 1022 | /* FSL SPDIF REGMAP */ |
f9f4fa61 | 1023 | static const struct reg_default fsl_spdif_reg_defaults[] = { |
9f1206dc ZW |
1024 | {REG_SPDIF_SCR, 0x00000400}, |
1025 | {REG_SPDIF_SRCD, 0x00000000}, | |
1026 | {REG_SPDIF_SIE, 0x00000000}, | |
1027 | {REG_SPDIF_STL, 0x00000000}, | |
1028 | {REG_SPDIF_STR, 0x00000000}, | |
1029 | {REG_SPDIF_STCSCH, 0x00000000}, | |
1030 | {REG_SPDIF_STCSCL, 0x00000000}, | |
1031 | {REG_SPDIF_STC, 0x00020f00}, | |
f9f4fa61 | 1032 | }; |
a2388a49 NC |
1033 | |
1034 | static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) | |
1035 | { | |
1036 | switch (reg) { | |
1037 | case REG_SPDIF_SCR: | |
1038 | case REG_SPDIF_SRCD: | |
1039 | case REG_SPDIF_SRPC: | |
1040 | case REG_SPDIF_SIE: | |
1041 | case REG_SPDIF_SIS: | |
1042 | case REG_SPDIF_SRL: | |
1043 | case REG_SPDIF_SRR: | |
1044 | case REG_SPDIF_SRCSH: | |
1045 | case REG_SPDIF_SRCSL: | |
1046 | case REG_SPDIF_SRU: | |
1047 | case REG_SPDIF_SRQ: | |
1048 | case REG_SPDIF_STCSCH: | |
1049 | case REG_SPDIF_STCSCL: | |
1050 | case REG_SPDIF_SRFM: | |
1051 | case REG_SPDIF_STC: | |
1052 | return true; | |
1053 | default: | |
1054 | return false; | |
e19bcb6b | 1055 | } |
a2388a49 NC |
1056 | } |
1057 | ||
f9f4fa61 ZW |
1058 | static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg) |
1059 | { | |
1060 | switch (reg) { | |
1061 | case REG_SPDIF_SRPC: | |
1062 | case REG_SPDIF_SIS: | |
1063 | case REG_SPDIF_SRL: | |
1064 | case REG_SPDIF_SRR: | |
1065 | case REG_SPDIF_SRCSH: | |
1066 | case REG_SPDIF_SRCSL: | |
1067 | case REG_SPDIF_SRU: | |
1068 | case REG_SPDIF_SRQ: | |
f9f4fa61 ZW |
1069 | case REG_SPDIF_SRFM: |
1070 | return true; | |
1071 | default: | |
1072 | return false; | |
1073 | } | |
1074 | } | |
1075 | ||
a2388a49 NC |
1076 | static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) |
1077 | { | |
1078 | switch (reg) { | |
1079 | case REG_SPDIF_SCR: | |
1080 | case REG_SPDIF_SRCD: | |
1081 | case REG_SPDIF_SRPC: | |
1082 | case REG_SPDIF_SIE: | |
1083 | case REG_SPDIF_SIC: | |
1084 | case REG_SPDIF_STL: | |
1085 | case REG_SPDIF_STR: | |
1086 | case REG_SPDIF_STCSCH: | |
1087 | case REG_SPDIF_STCSCL: | |
1088 | case REG_SPDIF_STC: | |
1089 | return true; | |
1090 | default: | |
1091 | return false; | |
e19bcb6b | 1092 | } |
a2388a49 NC |
1093 | } |
1094 | ||
66491507 | 1095 | static const struct regmap_config fsl_spdif_regmap_config = { |
a2388a49 NC |
1096 | .reg_bits = 32, |
1097 | .reg_stride = 4, | |
1098 | .val_bits = 32, | |
1099 | ||
1100 | .max_register = REG_SPDIF_STC, | |
f9f4fa61 ZW |
1101 | .reg_defaults = fsl_spdif_reg_defaults, |
1102 | .num_reg_defaults = ARRAY_SIZE(fsl_spdif_reg_defaults), | |
a2388a49 | 1103 | .readable_reg = fsl_spdif_readable_reg, |
f9f4fa61 | 1104 | .volatile_reg = fsl_spdif_volatile_reg, |
a2388a49 | 1105 | .writeable_reg = fsl_spdif_writeable_reg, |
f9f4fa61 | 1106 | .cache_type = REGCACHE_RBTREE, |
a2388a49 NC |
1107 | }; |
1108 | ||
1109 | static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, | |
1110 | struct clk *clk, u64 savesub, | |
9c6344b3 | 1111 | enum spdif_txrate index, bool round) |
a2388a49 | 1112 | { |
c7dfeed1 | 1113 | const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
81efec85 | 1114 | bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); |
a2388a49 | 1115 | u64 rate_ideal, rate_actual, sub; |
27c647bf NC |
1116 | u32 sysclk_dfmin, sysclk_dfmax; |
1117 | u32 txclk_df, sysclk_df, arate; | |
1118 | ||
1119 | /* The sysclk has an extra divisor [2, 512] */ | |
1120 | sysclk_dfmin = is_sysclk ? 2 : 1; | |
1121 | sysclk_dfmax = is_sysclk ? 512 : 1; | |
1122 | ||
1123 | for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { | |
1124 | for (txclk_df = 1; txclk_df <= 128; txclk_df++) { | |
f490f326 | 1125 | rate_ideal = rate[index] * txclk_df * 64; |
27c647bf NC |
1126 | if (round) |
1127 | rate_actual = clk_round_rate(clk, rate_ideal); | |
1128 | else | |
1129 | rate_actual = clk_get_rate(clk); | |
1130 | ||
1131 | arate = rate_actual / 64; | |
1132 | arate /= txclk_df * sysclk_df; | |
1133 | ||
1134 | if (arate == rate[index]) { | |
1135 | /* We are lucky */ | |
1136 | savesub = 0; | |
1137 | spdif_priv->txclk_df[index] = txclk_df; | |
1138 | spdif_priv->sysclk_df[index] = sysclk_df; | |
527cda78 | 1139 | spdif_priv->txrate[index] = arate; |
27c647bf NC |
1140 | goto out; |
1141 | } else if (arate / rate[index] == 1) { | |
1142 | /* A little bigger than expect */ | |
c89c7e94 | 1143 | sub = (u64)(arate - rate[index]) * 100000; |
27c647bf NC |
1144 | do_div(sub, rate[index]); |
1145 | if (sub >= savesub) | |
1146 | continue; | |
a2388a49 | 1147 | savesub = sub; |
e41a4a79 | 1148 | spdif_priv->txclk_df[index] = txclk_df; |
27c647bf | 1149 | spdif_priv->sysclk_df[index] = sysclk_df; |
527cda78 | 1150 | spdif_priv->txrate[index] = arate; |
27c647bf NC |
1151 | } else if (rate[index] / arate == 1) { |
1152 | /* A little smaller than expect */ | |
c89c7e94 | 1153 | sub = (u64)(rate[index] - arate) * 100000; |
27c647bf NC |
1154 | do_div(sub, rate[index]); |
1155 | if (sub >= savesub) | |
1156 | continue; | |
a2388a49 | 1157 | savesub = sub; |
e41a4a79 | 1158 | spdif_priv->txclk_df[index] = txclk_df; |
27c647bf | 1159 | spdif_priv->sysclk_df[index] = sysclk_df; |
527cda78 | 1160 | spdif_priv->txrate[index] = arate; |
a2388a49 NC |
1161 | } |
1162 | } | |
1163 | } | |
1164 | ||
27c647bf | 1165 | out: |
a2388a49 NC |
1166 | return savesub; |
1167 | } | |
1168 | ||
1169 | static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, | |
1170 | enum spdif_txrate index) | |
1171 | { | |
c7dfeed1 | 1172 | const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; |
a2388a49 NC |
1173 | struct platform_device *pdev = spdif_priv->pdev; |
1174 | struct device *dev = &pdev->dev; | |
1175 | u64 savesub = 100000, ret; | |
1176 | struct clk *clk; | |
1177 | char tmp[16]; | |
1178 | int i; | |
1179 | ||
1180 | for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { | |
1181 | sprintf(tmp, "rxtx%d", i); | |
1182 | clk = devm_clk_get(&pdev->dev, tmp); | |
1183 | if (IS_ERR(clk)) { | |
1184 | dev_err(dev, "no rxtx%d clock in devicetree\n", i); | |
1185 | return PTR_ERR(clk); | |
1186 | } | |
1187 | if (!clk_get_rate(clk)) | |
1188 | continue; | |
1189 | ||
9c6344b3 NC |
1190 | ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, |
1191 | i == STC_TXCLK_SPDIF_ROOT); | |
a2388a49 NC |
1192 | if (savesub == ret) |
1193 | continue; | |
1194 | ||
1195 | savesub = ret; | |
1196 | spdif_priv->txclk[index] = clk; | |
1197 | spdif_priv->txclk_src[index] = i; | |
1198 | ||
1199 | /* To quick catch a divisor, we allow a 0.1% deviation */ | |
1200 | if (savesub < 100) | |
1201 | break; | |
1202 | } | |
1203 | ||
8a309d71 | 1204 | dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", |
a2388a49 | 1205 | spdif_priv->txclk_src[index], rate[index]); |
e41a4a79 NC |
1206 | dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", |
1207 | spdif_priv->txclk_df[index], rate[index]); | |
81efec85 | 1208 | if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk)) |
27c647bf NC |
1209 | dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", |
1210 | spdif_priv->sysclk_df[index], rate[index]); | |
527cda78 NC |
1211 | dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", |
1212 | rate[index], spdif_priv->txrate[index]); | |
a2388a49 NC |
1213 | |
1214 | return 0; | |
1215 | } | |
1216 | ||
1217 | static int fsl_spdif_probe(struct platform_device *pdev) | |
1218 | { | |
1219 | struct device_node *np = pdev->dev.of_node; | |
1220 | struct fsl_spdif_priv *spdif_priv; | |
1221 | struct spdif_mixer_control *ctrl; | |
1222 | struct resource *res; | |
1223 | void __iomem *regs; | |
1224 | int irq, ret, i; | |
1225 | ||
1226 | if (!np) | |
1227 | return -ENODEV; | |
1228 | ||
7c27ba46 | 1229 | spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); |
a2388a49 NC |
1230 | if (!spdif_priv) |
1231 | return -ENOMEM; | |
1232 | ||
a2388a49 NC |
1233 | spdif_priv->pdev = pdev; |
1234 | ||
1235 | /* Initialize this copy of the CPU DAI driver structure */ | |
1236 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | |
7c27ba46 | 1237 | spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); |
a2388a49 NC |
1238 | |
1239 | /* Get the addresses and IRQ */ | |
1240 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
a2388a49 | 1241 | regs = devm_ioremap_resource(&pdev->dev, res); |
bfd7d1aa | 1242 | if (IS_ERR(regs)) |
a2388a49 | 1243 | return PTR_ERR(regs); |
a2388a49 NC |
1244 | |
1245 | spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, | |
1246 | "core", regs, &fsl_spdif_regmap_config); | |
1247 | if (IS_ERR(spdif_priv->regmap)) { | |
1248 | dev_err(&pdev->dev, "regmap init failed\n"); | |
1249 | return PTR_ERR(spdif_priv->regmap); | |
1250 | } | |
1251 | ||
1252 | irq = platform_get_irq(pdev, 0); | |
1253 | if (irq < 0) { | |
b968d83f | 1254 | dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); |
a2388a49 NC |
1255 | return irq; |
1256 | } | |
1257 | ||
1258 | ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, | |
7c27ba46 | 1259 | dev_name(&pdev->dev), spdif_priv); |
a2388a49 NC |
1260 | if (ret) { |
1261 | dev_err(&pdev->dev, "could not claim irq %u\n", irq); | |
1262 | return ret; | |
1263 | } | |
1264 | ||
0b864390 NC |
1265 | /* Get system clock for rx clock rate calculation */ |
1266 | spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5"); | |
1267 | if (IS_ERR(spdif_priv->sysclk)) { | |
1268 | dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n"); | |
1269 | return PTR_ERR(spdif_priv->sysclk); | |
1270 | } | |
1271 | ||
08f7336e NC |
1272 | /* Get core clock for data register access via DMA */ |
1273 | spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core"); | |
1274 | if (IS_ERR(spdif_priv->coreclk)) { | |
1275 | dev_err(&pdev->dev, "no core clock in devicetree\n"); | |
1276 | return PTR_ERR(spdif_priv->coreclk); | |
1277 | } | |
1278 | ||
0bc5680a SW |
1279 | spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); |
1280 | if (IS_ERR(spdif_priv->spbaclk)) | |
1281 | dev_warn(&pdev->dev, "no spba clock in devicetree\n"); | |
1282 | ||
a2388a49 NC |
1283 | /* Select clock source for rx/tx clock */ |
1284 | spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); | |
1285 | if (IS_ERR(spdif_priv->rxclk)) { | |
1286 | dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); | |
1287 | return PTR_ERR(spdif_priv->rxclk); | |
1288 | } | |
1289 | spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; | |
1290 | ||
1291 | for (i = 0; i < SPDIF_TXRATE_MAX; i++) { | |
1292 | ret = fsl_spdif_probe_txclk(spdif_priv, i); | |
1293 | if (ret) | |
1294 | return ret; | |
1295 | } | |
1296 | ||
1297 | /* Initial spinlock for control data */ | |
1298 | ctrl = &spdif_priv->fsl_spdif_control; | |
1299 | spin_lock_init(&ctrl->ctl_lock); | |
1300 | ||
1301 | /* Init tx channel status default value */ | |
f3a30baa NC |
1302 | ctrl->ch_status[0] = IEC958_AES0_CON_NOT_COPYRIGHT | |
1303 | IEC958_AES0_CON_EMPHASIS_5015; | |
a2388a49 NC |
1304 | ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; |
1305 | ctrl->ch_status[2] = 0x00; | |
f3a30baa NC |
1306 | ctrl->ch_status[3] = IEC958_AES3_CON_FS_44100 | |
1307 | IEC958_AES3_CON_CLOCK_1000PPM; | |
a2388a49 NC |
1308 | |
1309 | spdif_priv->dpll_locked = false; | |
1310 | ||
1311 | spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; | |
1312 | spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; | |
1313 | spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; | |
1314 | spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; | |
1315 | ||
1316 | /* Register with ASoC */ | |
1317 | dev_set_drvdata(&pdev->dev, spdif_priv); | |
1318 | ||
256218ae SK |
1319 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, |
1320 | &spdif_priv->cpu_dai_drv, 1); | |
a2388a49 NC |
1321 | if (ret) { |
1322 | dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); | |
5af407cd | 1323 | return ret; |
a2388a49 NC |
1324 | } |
1325 | ||
0d69e0dd | 1326 | ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); |
256218ae | 1327 | if (ret) |
a2388a49 | 1328 | dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); |
a2388a49 NC |
1329 | |
1330 | return ret; | |
1331 | } | |
1332 | ||
f9f4fa61 ZW |
1333 | #ifdef CONFIG_PM_SLEEP |
1334 | static int fsl_spdif_suspend(struct device *dev) | |
1335 | { | |
1336 | struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); | |
1337 | ||
1338 | regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, | |
1339 | &spdif_priv->regcache_srpc); | |
1340 | ||
1341 | regcache_cache_only(spdif_priv->regmap, true); | |
1342 | regcache_mark_dirty(spdif_priv->regmap); | |
1343 | ||
1344 | return 0; | |
1345 | } | |
1346 | ||
1347 | static int fsl_spdif_resume(struct device *dev) | |
1348 | { | |
1349 | struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); | |
1350 | ||
1351 | regcache_cache_only(spdif_priv->regmap, false); | |
1352 | ||
1353 | regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, | |
1354 | SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, | |
1355 | spdif_priv->regcache_srpc); | |
1356 | ||
1357 | return regcache_sync(spdif_priv->regmap); | |
1358 | } | |
1359 | #endif /* CONFIG_PM_SLEEP */ | |
1360 | ||
1361 | static const struct dev_pm_ops fsl_spdif_pm = { | |
1362 | SET_SYSTEM_SLEEP_PM_OPS(fsl_spdif_suspend, fsl_spdif_resume) | |
1363 | }; | |
1364 | ||
a2388a49 NC |
1365 | static const struct of_device_id fsl_spdif_dt_ids[] = { |
1366 | { .compatible = "fsl,imx35-spdif", }, | |
1014fad0 | 1367 | { .compatible = "fsl,vf610-spdif", }, |
a2388a49 NC |
1368 | {} |
1369 | }; | |
1370 | MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); | |
1371 | ||
1372 | static struct platform_driver fsl_spdif_driver = { | |
1373 | .driver = { | |
1374 | .name = "fsl-spdif-dai", | |
a2388a49 | 1375 | .of_match_table = fsl_spdif_dt_ids, |
f9f4fa61 | 1376 | .pm = &fsl_spdif_pm, |
a2388a49 NC |
1377 | }, |
1378 | .probe = fsl_spdif_probe, | |
a2388a49 NC |
1379 | }; |
1380 | ||
1381 | module_platform_driver(fsl_spdif_driver); | |
1382 | ||
1383 | MODULE_AUTHOR("Freescale Semiconductor, Inc."); | |
1384 | MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver"); | |
1385 | MODULE_LICENSE("GPL v2"); | |
1386 | MODULE_ALIAS("platform:fsl-spdif-dai"); |