diff options
Diffstat (limited to 'sound/soc/stm/stm32_spdifrx.c')
-rw-r--r-- | sound/soc/stm/stm32_spdifrx.c | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c new file mode 100644 index 000000000000..4e4250bdb75a --- /dev/null +++ b/sound/soc/stm/stm32_spdifrx.c | |||
@@ -0,0 +1,998 @@ | |||
1 | /* | ||
2 | * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. | ||
3 | * | ||
4 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
5 | * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. | ||
6 | * | ||
7 | * License terms: GPL V2.0. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more | ||
16 | * details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clk.h> | ||
20 | #include <linux/completion.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of_platform.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <linux/reset.h> | ||
26 | |||
27 | #include <sound/dmaengine_pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | |||
30 | /* SPDIF-rx Register Map */ | ||
31 | #define STM32_SPDIFRX_CR 0x00 | ||
32 | #define STM32_SPDIFRX_IMR 0x04 | ||
33 | #define STM32_SPDIFRX_SR 0x08 | ||
34 | #define STM32_SPDIFRX_IFCR 0x0C | ||
35 | #define STM32_SPDIFRX_DR 0x10 | ||
36 | #define STM32_SPDIFRX_CSR 0x14 | ||
37 | #define STM32_SPDIFRX_DIR 0x18 | ||
38 | |||
39 | /* Bit definition for SPDIF_CR register */ | ||
40 | #define SPDIFRX_CR_SPDIFEN_SHIFT 0 | ||
41 | #define SPDIFRX_CR_SPDIFEN_MASK GENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) | ||
42 | #define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) | ||
43 | |||
44 | #define SPDIFRX_CR_RXDMAEN BIT(2) | ||
45 | #define SPDIFRX_CR_RXSTEO BIT(3) | ||
46 | |||
47 | #define SPDIFRX_CR_DRFMT_SHIFT 4 | ||
48 | #define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) | ||
49 | #define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) | ||
50 | |||
51 | #define SPDIFRX_CR_PMSK BIT(6) | ||
52 | #define SPDIFRX_CR_VMSK BIT(7) | ||
53 | #define SPDIFRX_CR_CUMSK BIT(8) | ||
54 | #define SPDIFRX_CR_PTMSK BIT(9) | ||
55 | #define SPDIFRX_CR_CBDMAEN BIT(10) | ||
56 | #define SPDIFRX_CR_CHSEL_SHIFT 11 | ||
57 | #define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) | ||
58 | |||
59 | #define SPDIFRX_CR_NBTR_SHIFT 12 | ||
60 | #define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) | ||
61 | #define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) | ||
62 | |||
63 | #define SPDIFRX_CR_WFA BIT(14) | ||
64 | |||
65 | #define SPDIFRX_CR_INSEL_SHIFT 16 | ||
66 | #define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) | ||
67 | #define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) | ||
68 | |||
69 | #define SPDIFRX_CR_CKSEN_SHIFT 20 | ||
70 | #define SPDIFRX_CR_CKSEN BIT(20) | ||
71 | #define SPDIFRX_CR_CKSBKPEN BIT(21) | ||
72 | |||
73 | /* Bit definition for SPDIFRX_IMR register */ | ||
74 | #define SPDIFRX_IMR_RXNEI BIT(0) | ||
75 | #define SPDIFRX_IMR_CSRNEIE BIT(1) | ||
76 | #define SPDIFRX_IMR_PERRIE BIT(2) | ||
77 | #define SPDIFRX_IMR_OVRIE BIT(3) | ||
78 | #define SPDIFRX_IMR_SBLKIE BIT(4) | ||
79 | #define SPDIFRX_IMR_SYNCDIE BIT(5) | ||
80 | #define SPDIFRX_IMR_IFEIE BIT(6) | ||
81 | |||
82 | #define SPDIFRX_XIMR_MASK GENMASK(6, 0) | ||
83 | |||
84 | /* Bit definition for SPDIFRX_SR register */ | ||
85 | #define SPDIFRX_SR_RXNE BIT(0) | ||
86 | #define SPDIFRX_SR_CSRNE BIT(1) | ||
87 | #define SPDIFRX_SR_PERR BIT(2) | ||
88 | #define SPDIFRX_SR_OVR BIT(3) | ||
89 | #define SPDIFRX_SR_SBD BIT(4) | ||
90 | #define SPDIFRX_SR_SYNCD BIT(5) | ||
91 | #define SPDIFRX_SR_FERR BIT(6) | ||
92 | #define SPDIFRX_SR_SERR BIT(7) | ||
93 | #define SPDIFRX_SR_TERR BIT(8) | ||
94 | |||
95 | #define SPDIFRX_SR_WIDTH5_SHIFT 16 | ||
96 | #define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) | ||
97 | #define SPDIFRX_SR_WIDTH5SET(x) ((x) << SPDIFRX_SR_WIDTH5_SHIFT) | ||
98 | |||
99 | /* Bit definition for SPDIFRX_IFCR register */ | ||
100 | #define SPDIFRX_IFCR_PERRCF BIT(2) | ||
101 | #define SPDIFRX_IFCR_OVRCF BIT(3) | ||
102 | #define SPDIFRX_IFCR_SBDCF BIT(4) | ||
103 | #define SPDIFRX_IFCR_SYNCDCF BIT(5) | ||
104 | |||
105 | #define SPDIFRX_XIFCR_MASK GENMASK(5, 2) | ||
106 | |||
107 | /* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */ | ||
108 | #define SPDIFRX_DR0_DR_SHIFT 0 | ||
109 | #define SPDIFRX_DR0_DR_MASK GENMASK(23, SPDIFRX_DR0_DR_SHIFT) | ||
110 | #define SPDIFRX_DR0_DRSET(x) ((x) << SPDIFRX_DR0_DR_SHIFT) | ||
111 | |||
112 | #define SPDIFRX_DR0_PE BIT(24) | ||
113 | |||
114 | #define SPDIFRX_DR0_V BIT(25) | ||
115 | #define SPDIFRX_DR0_U BIT(26) | ||
116 | #define SPDIFRX_DR0_C BIT(27) | ||
117 | |||
118 | #define SPDIFRX_DR0_PT_SHIFT 28 | ||
119 | #define SPDIFRX_DR0_PT_MASK GENMASK(29, SPDIFRX_DR0_PT_SHIFT) | ||
120 | #define SPDIFRX_DR0_PTSET(x) ((x) << SPDIFRX_DR0_PT_SHIFT) | ||
121 | |||
122 | /* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */ | ||
123 | #define SPDIFRX_DR1_PE BIT(0) | ||
124 | #define SPDIFRX_DR1_V BIT(1) | ||
125 | #define SPDIFRX_DR1_U BIT(2) | ||
126 | #define SPDIFRX_DR1_C BIT(3) | ||
127 | |||
128 | #define SPDIFRX_DR1_PT_SHIFT 4 | ||
129 | #define SPDIFRX_DR1_PT_MASK GENMASK(5, SPDIFRX_DR1_PT_SHIFT) | ||
130 | #define SPDIFRX_DR1_PTSET(x) ((x) << SPDIFRX_DR1_PT_SHIFT) | ||
131 | |||
132 | #define SPDIFRX_DR1_DR_SHIFT 8 | ||
133 | #define SPDIFRX_DR1_DR_MASK GENMASK(31, SPDIFRX_DR1_DR_SHIFT) | ||
134 | #define SPDIFRX_DR1_DRSET(x) ((x) << SPDIFRX_DR1_DR_SHIFT) | ||
135 | |||
136 | /* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */ | ||
137 | #define SPDIFRX_DR1_DRNL1_SHIFT 0 | ||
138 | #define SPDIFRX_DR1_DRNL1_MASK GENMASK(15, SPDIFRX_DR1_DRNL1_SHIFT) | ||
139 | #define SPDIFRX_DR1_DRNL1SET(x) ((x) << SPDIFRX_DR1_DRNL1_SHIFT) | ||
140 | |||
141 | #define SPDIFRX_DR1_DRNL2_SHIFT 16 | ||
142 | #define SPDIFRX_DR1_DRNL2_MASK GENMASK(31, SPDIFRX_DR1_DRNL2_SHIFT) | ||
143 | #define SPDIFRX_DR1_DRNL2SET(x) ((x) << SPDIFRX_DR1_DRNL2_SHIFT) | ||
144 | |||
145 | /* Bit definition for SPDIFRX_CSR register */ | ||
146 | #define SPDIFRX_CSR_USR_SHIFT 0 | ||
147 | #define SPDIFRX_CSR_USR_MASK GENMASK(15, SPDIFRX_CSR_USR_SHIFT) | ||
148 | #define SPDIFRX_CSR_USRGET(x) (((x) & SPDIFRX_CSR_USR_MASK)\ | ||
149 | >> SPDIFRX_CSR_USR_SHIFT) | ||
150 | |||
151 | #define SPDIFRX_CSR_CS_SHIFT 16 | ||
152 | #define SPDIFRX_CSR_CS_MASK GENMASK(23, SPDIFRX_CSR_CS_SHIFT) | ||
153 | #define SPDIFRX_CSR_CSGET(x) (((x) & SPDIFRX_CSR_CS_MASK)\ | ||
154 | >> SPDIFRX_CSR_CS_SHIFT) | ||
155 | |||
156 | #define SPDIFRX_CSR_SOB BIT(24) | ||
157 | |||
158 | /* Bit definition for SPDIFRX_DIR register */ | ||
159 | #define SPDIFRX_DIR_THI_SHIFT 0 | ||
160 | #define SPDIFRX_DIR_THI_MASK GENMASK(12, SPDIFRX_DIR_THI_SHIFT) | ||
161 | #define SPDIFRX_DIR_THI_SET(x) ((x) << SPDIFRX_DIR_THI_SHIFT) | ||
162 | |||
163 | #define SPDIFRX_DIR_TLO_SHIFT 16 | ||
164 | #define SPDIFRX_DIR_TLO_MASK GENMASK(28, SPDIFRX_DIR_TLO_SHIFT) | ||
165 | #define SPDIFRX_DIR_TLO_SET(x) ((x) << SPDIFRX_DIR_TLO_SHIFT) | ||
166 | |||
167 | #define SPDIFRX_SPDIFEN_DISABLE 0x0 | ||
168 | #define SPDIFRX_SPDIFEN_SYNC 0x1 | ||
169 | #define SPDIFRX_SPDIFEN_ENABLE 0x3 | ||
170 | |||
171 | #define SPDIFRX_IN1 0x1 | ||
172 | #define SPDIFRX_IN2 0x2 | ||
173 | #define SPDIFRX_IN3 0x3 | ||
174 | #define SPDIFRX_IN4 0x4 | ||
175 | #define SPDIFRX_IN5 0x5 | ||
176 | #define SPDIFRX_IN6 0x6 | ||
177 | #define SPDIFRX_IN7 0x7 | ||
178 | #define SPDIFRX_IN8 0x8 | ||
179 | |||
180 | #define SPDIFRX_NBTR_NONE 0x0 | ||
181 | #define SPDIFRX_NBTR_3 0x1 | ||
182 | #define SPDIFRX_NBTR_15 0x2 | ||
183 | #define SPDIFRX_NBTR_63 0x3 | ||
184 | |||
185 | #define SPDIFRX_DRFMT_RIGHT 0x0 | ||
186 | #define SPDIFRX_DRFMT_LEFT 0x1 | ||
187 | #define SPDIFRX_DRFMT_PACKED 0x2 | ||
188 | |||
189 | /* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */ | ||
190 | #define SPDIFRX_CS_BYTES_NB 24 | ||
191 | #define SPDIFRX_UB_BYTES_NB 48 | ||
192 | |||
193 | /* | ||
194 | * CSR register is retrieved as a 32 bits word | ||
195 | * It contains 1 channel status byte and 2 user data bytes | ||
196 | * 2 S/PDIF frames are acquired to get all CS/UB bits | ||
197 | */ | ||
198 | #define SPDIFRX_CSR_BUF_LENGTH (SPDIFRX_CS_BYTES_NB * 4 * 2) | ||
199 | |||
200 | /** | ||
201 | * struct stm32_spdifrx_data - private data of SPDIFRX | ||
202 | * @pdev: device data pointer | ||
203 | * @base: mmio register base virtual address | ||
204 | * @regmap: SPDIFRX register map pointer | ||
205 | * @regmap_conf: SPDIFRX register map configuration pointer | ||
206 | * @cs_completion: channel status retrieving completion | ||
207 | * @kclk: kernel clock feeding the SPDIFRX clock generator | ||
208 | * @dma_params: dma configuration data for rx channel | ||
209 | * @substream: PCM substream data pointer | ||
210 | * @dmab: dma buffer info pointer | ||
211 | * @ctrl_chan: dma channel for S/PDIF control bits | ||
212 | * @desc:dma async transaction descriptor | ||
213 | * @slave_config: dma slave channel runtime config pointer | ||
214 | * @phys_addr: SPDIFRX registers physical base address | ||
215 | * @lock: synchronization enabling lock | ||
216 | * @cs: channel status buffer | ||
217 | * @ub: user data buffer | ||
218 | * @irq: SPDIFRX interrupt line | ||
219 | * @refcount: keep count of opened DMA channels | ||
220 | */ | ||
221 | struct stm32_spdifrx_data { | ||
222 | struct platform_device *pdev; | ||
223 | void __iomem *base; | ||
224 | struct regmap *regmap; | ||
225 | const struct regmap_config *regmap_conf; | ||
226 | struct completion cs_completion; | ||
227 | struct clk *kclk; | ||
228 | struct snd_dmaengine_dai_dma_data dma_params; | ||
229 | struct snd_pcm_substream *substream; | ||
230 | struct snd_dma_buffer *dmab; | ||
231 | struct dma_chan *ctrl_chan; | ||
232 | struct dma_async_tx_descriptor *desc; | ||
233 | struct dma_slave_config slave_config; | ||
234 | dma_addr_t phys_addr; | ||
235 | spinlock_t lock; /* Sync enabling lock */ | ||
236 | unsigned char cs[SPDIFRX_CS_BYTES_NB]; | ||
237 | unsigned char ub[SPDIFRX_UB_BYTES_NB]; | ||
238 | int irq; | ||
239 | int refcount; | ||
240 | }; | ||
241 | |||
242 | static void stm32_spdifrx_dma_complete(void *data) | ||
243 | { | ||
244 | struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data; | ||
245 | struct platform_device *pdev = spdifrx->pdev; | ||
246 | u32 *p_start = (u32 *)spdifrx->dmab->area; | ||
247 | u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1; | ||
248 | u32 *ptr = p_start; | ||
249 | u16 *ub_ptr = (short *)spdifrx->ub; | ||
250 | int i = 0; | ||
251 | |||
252 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
253 | SPDIFRX_CR_CBDMAEN, | ||
254 | (unsigned int)~SPDIFRX_CR_CBDMAEN); | ||
255 | |||
256 | if (!spdifrx->dmab->area) | ||
257 | return; | ||
258 | |||
259 | while (ptr <= p_end) { | ||
260 | if (*ptr & SPDIFRX_CSR_SOB) | ||
261 | break; | ||
262 | ptr++; | ||
263 | } | ||
264 | |||
265 | if (ptr > p_end) { | ||
266 | dev_err(&pdev->dev, "Start of S/PDIF block not found\n"); | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | while (i < SPDIFRX_CS_BYTES_NB) { | ||
271 | spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr); | ||
272 | *ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++); | ||
273 | if (ptr > p_end) { | ||
274 | dev_err(&pdev->dev, "Failed to get channel status\n"); | ||
275 | return; | ||
276 | } | ||
277 | i++; | ||
278 | } | ||
279 | |||
280 | complete(&spdifrx->cs_completion); | ||
281 | } | ||
282 | |||
283 | static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx) | ||
284 | { | ||
285 | dma_cookie_t cookie; | ||
286 | int err; | ||
287 | |||
288 | spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan, | ||
289 | spdifrx->dmab->addr, | ||
290 | SPDIFRX_CSR_BUF_LENGTH, | ||
291 | DMA_DEV_TO_MEM, | ||
292 | DMA_CTRL_ACK); | ||
293 | if (!spdifrx->desc) | ||
294 | return -EINVAL; | ||
295 | |||
296 | spdifrx->desc->callback = stm32_spdifrx_dma_complete; | ||
297 | spdifrx->desc->callback_param = spdifrx; | ||
298 | cookie = dmaengine_submit(spdifrx->desc); | ||
299 | err = dma_submit_error(cookie); | ||
300 | if (err) | ||
301 | return -EINVAL; | ||
302 | |||
303 | dma_async_issue_pending(spdifrx->ctrl_chan); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) | ||
309 | { | ||
310 | dmaengine_terminate_async(spdifrx->ctrl_chan); | ||
311 | } | ||
312 | |||
313 | static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) | ||
314 | { | ||
315 | int cr, cr_mask, imr, ret; | ||
316 | |||
317 | /* Enable IRQs */ | ||
318 | imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; | ||
319 | ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, imr, imr); | ||
320 | if (ret) | ||
321 | return ret; | ||
322 | |||
323 | spin_lock(&spdifrx->lock); | ||
324 | |||
325 | spdifrx->refcount++; | ||
326 | |||
327 | regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); | ||
328 | |||
329 | if (!(cr & SPDIFRX_CR_SPDIFEN_MASK)) { | ||
330 | /* | ||
331 | * Start sync if SPDIFRX is still in idle state. | ||
332 | * SPDIFRX reception enabled when sync done | ||
333 | */ | ||
334 | dev_dbg(&spdifrx->pdev->dev, "start synchronization\n"); | ||
335 | |||
336 | /* | ||
337 | * SPDIFRX configuration: | ||
338 | * Wait for activity before starting sync process. This avoid | ||
339 | * to issue sync errors when spdif signal is missing on input. | ||
340 | * Preamble, CS, user, validity and parity error bits not copied | ||
341 | * to DR register. | ||
342 | */ | ||
343 | cr = SPDIFRX_CR_WFA | SPDIFRX_CR_PMSK | SPDIFRX_CR_VMSK | | ||
344 | SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; | ||
345 | cr_mask = cr; | ||
346 | |||
347 | cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); | ||
348 | cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; | ||
349 | ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
350 | cr_mask, cr); | ||
351 | if (ret < 0) | ||
352 | dev_err(&spdifrx->pdev->dev, | ||
353 | "Failed to start synchronization\n"); | ||
354 | } | ||
355 | |||
356 | spin_unlock(&spdifrx->lock); | ||
357 | |||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) | ||
362 | { | ||
363 | int cr, cr_mask, reg; | ||
364 | |||
365 | spin_lock(&spdifrx->lock); | ||
366 | |||
367 | if (--spdifrx->refcount) { | ||
368 | spin_unlock(&spdifrx->lock); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); | ||
373 | cr_mask = SPDIFRX_CR_SPDIFEN_MASK | SPDIFRX_CR_RXDMAEN; | ||
374 | |||
375 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, cr_mask, cr); | ||
376 | |||
377 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, | ||
378 | SPDIFRX_XIMR_MASK, 0); | ||
379 | |||
380 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, | ||
381 | SPDIFRX_XIFCR_MASK, SPDIFRX_XIFCR_MASK); | ||
382 | |||
383 | /* dummy read to clear CSRNE and RXNE in status register */ | ||
384 | regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); | ||
385 | regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); | ||
386 | |||
387 | spin_unlock(&spdifrx->lock); | ||
388 | } | ||
389 | |||
390 | static int stm32_spdifrx_dma_ctrl_register(struct device *dev, | ||
391 | struct stm32_spdifrx_data *spdifrx) | ||
392 | { | ||
393 | int ret; | ||
394 | |||
395 | spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), | ||
396 | GFP_KERNEL); | ||
397 | if (!spdifrx->dmab) | ||
398 | return -ENOMEM; | ||
399 | |||
400 | spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; | ||
401 | spdifrx->dmab->dev.dev = dev; | ||
402 | ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, | ||
403 | SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); | ||
404 | if (ret < 0) { | ||
405 | dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); | ||
410 | if (!spdifrx->ctrl_chan) { | ||
411 | dev_err(dev, "dma_request_slave_channel failed\n"); | ||
412 | return -EINVAL; | ||
413 | } | ||
414 | |||
415 | spdifrx->slave_config.direction = DMA_DEV_TO_MEM; | ||
416 | spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + | ||
417 | STM32_SPDIFRX_CSR); | ||
418 | spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; | ||
419 | spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
420 | spdifrx->slave_config.src_maxburst = 1; | ||
421 | |||
422 | ret = dmaengine_slave_config(spdifrx->ctrl_chan, | ||
423 | &spdifrx->slave_config); | ||
424 | if (ret < 0) { | ||
425 | dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); | ||
426 | dma_release_channel(spdifrx->ctrl_chan); | ||
427 | spdifrx->ctrl_chan = NULL; | ||
428 | } | ||
429 | |||
430 | return ret; | ||
431 | }; | ||
432 | |||
433 | static const char * const spdifrx_enum_input[] = { | ||
434 | "in0", "in1", "in2", "in3" | ||
435 | }; | ||
436 | |||
437 | /* By default CS bits are retrieved from channel A */ | ||
438 | static const char * const spdifrx_enum_cs_channel[] = { | ||
439 | "A", "B" | ||
440 | }; | ||
441 | |||
442 | static SOC_ENUM_SINGLE_DECL(ctrl_enum_input, | ||
443 | STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT, | ||
444 | spdifrx_enum_input); | ||
445 | |||
446 | static SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel, | ||
447 | STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT, | ||
448 | spdifrx_enum_cs_channel); | ||
449 | |||
450 | static int stm32_spdifrx_info(struct snd_kcontrol *kcontrol, | ||
451 | struct snd_ctl_elem_info *uinfo) | ||
452 | { | ||
453 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
454 | uinfo->count = 1; | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol, | ||
460 | struct snd_ctl_elem_info *uinfo) | ||
461 | { | ||
462 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
463 | uinfo->count = 1; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) | ||
469 | { | ||
470 | int ret = 0; | ||
471 | |||
472 | memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); | ||
473 | memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); | ||
474 | |||
475 | ret = stm32_spdifrx_dma_ctrl_start(spdifrx); | ||
476 | if (ret < 0) | ||
477 | return ret; | ||
478 | |||
479 | ret = clk_prepare_enable(spdifrx->kclk); | ||
480 | if (ret) { | ||
481 | dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); | ||
482 | return ret; | ||
483 | } | ||
484 | |||
485 | ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
486 | SPDIFRX_CR_CBDMAEN, SPDIFRX_CR_CBDMAEN); | ||
487 | if (ret < 0) | ||
488 | goto end; | ||
489 | |||
490 | ret = stm32_spdifrx_start_sync(spdifrx); | ||
491 | if (ret < 0) | ||
492 | goto end; | ||
493 | |||
494 | if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, | ||
495 | msecs_to_jiffies(100)) | ||
496 | <= 0) { | ||
497 | dev_err(&spdifrx->pdev->dev, "Failed to get control data\n"); | ||
498 | ret = -EAGAIN; | ||
499 | } | ||
500 | |||
501 | stm32_spdifrx_stop(spdifrx); | ||
502 | stm32_spdifrx_dma_ctrl_stop(spdifrx); | ||
503 | |||
504 | end: | ||
505 | clk_disable_unprepare(spdifrx->kclk); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | static int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol, | ||
511 | struct snd_ctl_elem_value *ucontrol) | ||
512 | { | ||
513 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
514 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
515 | |||
516 | stm32_spdifrx_get_ctrl_data(spdifrx); | ||
517 | |||
518 | ucontrol->value.iec958.status[0] = spdifrx->cs[0]; | ||
519 | ucontrol->value.iec958.status[1] = spdifrx->cs[1]; | ||
520 | ucontrol->value.iec958.status[2] = spdifrx->cs[2]; | ||
521 | ucontrol->value.iec958.status[3] = spdifrx->cs[3]; | ||
522 | ucontrol->value.iec958.status[4] = spdifrx->cs[4]; | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol, | ||
528 | struct snd_ctl_elem_value *ucontrol) | ||
529 | { | ||
530 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); | ||
531 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
532 | |||
533 | stm32_spdifrx_get_ctrl_data(spdifrx); | ||
534 | |||
535 | ucontrol->value.iec958.status[0] = spdifrx->ub[0]; | ||
536 | ucontrol->value.iec958.status[1] = spdifrx->ub[1]; | ||
537 | ucontrol->value.iec958.status[2] = spdifrx->ub[2]; | ||
538 | ucontrol->value.iec958.status[3] = spdifrx->ub[3]; | ||
539 | ucontrol->value.iec958.status[4] = spdifrx->ub[4]; | ||
540 | |||
541 | return 0; | ||
542 | } | ||
543 | |||
544 | static struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] = { | ||
545 | /* Channel status control */ | ||
546 | { | ||
547 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
548 | .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), | ||
549 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
550 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
551 | .info = stm32_spdifrx_info, | ||
552 | .get = stm32_spdifrx_capture_get, | ||
553 | }, | ||
554 | /* User bits control */ | ||
555 | { | ||
556 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
557 | .name = "IEC958 User Bit Capture Default", | ||
558 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
559 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
560 | .info = stm32_spdifrx_ub_info, | ||
561 | .get = stm32_spdif_user_bits_get, | ||
562 | }, | ||
563 | }; | ||
564 | |||
565 | static struct snd_kcontrol_new stm32_spdifrx_ctrls[] = { | ||
566 | SOC_ENUM("SPDIFRX input", ctrl_enum_input), | ||
567 | SOC_ENUM("SPDIFRX CS channel", ctrl_enum_cs_channel), | ||
568 | }; | ||
569 | |||
570 | static int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai) | ||
571 | { | ||
572 | int ret; | ||
573 | |||
574 | ret = snd_soc_add_dai_controls(cpu_dai, stm32_spdifrx_iec_ctrls, | ||
575 | ARRAY_SIZE(stm32_spdifrx_iec_ctrls)); | ||
576 | if (ret < 0) | ||
577 | return ret; | ||
578 | |||
579 | return snd_soc_add_component_controls(cpu_dai->component, | ||
580 | stm32_spdifrx_ctrls, | ||
581 | ARRAY_SIZE(stm32_spdifrx_ctrls)); | ||
582 | } | ||
583 | |||
584 | static int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai) | ||
585 | { | ||
586 | struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(cpu_dai->dev); | ||
587 | |||
588 | spdifrx->dma_params.addr = (dma_addr_t)(spdifrx->phys_addr + | ||
589 | STM32_SPDIFRX_DR); | ||
590 | spdifrx->dma_params.maxburst = 1; | ||
591 | |||
592 | snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); | ||
593 | |||
594 | return stm32_spdifrx_dai_register_ctrls(cpu_dai); | ||
595 | } | ||
596 | |||
597 | static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) | ||
598 | { | ||
599 | switch (reg) { | ||
600 | case STM32_SPDIFRX_CR: | ||
601 | case STM32_SPDIFRX_IMR: | ||
602 | case STM32_SPDIFRX_SR: | ||
603 | case STM32_SPDIFRX_IFCR: | ||
604 | case STM32_SPDIFRX_DR: | ||
605 | case STM32_SPDIFRX_CSR: | ||
606 | case STM32_SPDIFRX_DIR: | ||
607 | return true; | ||
608 | default: | ||
609 | return false; | ||
610 | } | ||
611 | } | ||
612 | |||
613 | static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) | ||
614 | { | ||
615 | if (reg == STM32_SPDIFRX_DR) | ||
616 | return true; | ||
617 | |||
618 | return false; | ||
619 | } | ||
620 | |||
621 | static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) | ||
622 | { | ||
623 | switch (reg) { | ||
624 | case STM32_SPDIFRX_CR: | ||
625 | case STM32_SPDIFRX_IMR: | ||
626 | case STM32_SPDIFRX_IFCR: | ||
627 | return true; | ||
628 | default: | ||
629 | return false; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { | ||
634 | .reg_bits = 32, | ||
635 | .reg_stride = 4, | ||
636 | .val_bits = 32, | ||
637 | .max_register = STM32_SPDIFRX_DIR, | ||
638 | .readable_reg = stm32_spdifrx_readable_reg, | ||
639 | .volatile_reg = stm32_spdifrx_volatile_reg, | ||
640 | .writeable_reg = stm32_spdifrx_writeable_reg, | ||
641 | .fast_io = true, | ||
642 | }; | ||
643 | |||
644 | static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) | ||
645 | { | ||
646 | struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; | ||
647 | struct snd_pcm_substream *substream = spdifrx->substream; | ||
648 | struct platform_device *pdev = spdifrx->pdev; | ||
649 | unsigned int cr, mask, sr, imr; | ||
650 | unsigned int flags; | ||
651 | int err = 0, err_xrun = 0; | ||
652 | |||
653 | regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); | ||
654 | regmap_read(spdifrx->regmap, STM32_SPDIFRX_IMR, &imr); | ||
655 | |||
656 | mask = imr & SPDIFRX_XIMR_MASK; | ||
657 | /* SERR, TERR, FERR IRQs are generated if IFEIE is set */ | ||
658 | if (mask & SPDIFRX_IMR_IFEIE) | ||
659 | mask |= (SPDIFRX_IMR_IFEIE << 1) | (SPDIFRX_IMR_IFEIE << 2); | ||
660 | |||
661 | flags = sr & mask; | ||
662 | if (!flags) { | ||
663 | dev_err(&pdev->dev, "Unexpected IRQ. rflags=%#x, imr=%#x\n", | ||
664 | sr, imr); | ||
665 | return IRQ_NONE; | ||
666 | } | ||
667 | |||
668 | /* Clear IRQs */ | ||
669 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, | ||
670 | SPDIFRX_XIFCR_MASK, flags); | ||
671 | |||
672 | if (flags & SPDIFRX_SR_PERR) { | ||
673 | dev_dbg(&pdev->dev, "Parity error\n"); | ||
674 | err_xrun = 1; | ||
675 | } | ||
676 | |||
677 | if (flags & SPDIFRX_SR_OVR) { | ||
678 | dev_dbg(&pdev->dev, "Overrun error\n"); | ||
679 | err_xrun = 1; | ||
680 | } | ||
681 | |||
682 | if (flags & SPDIFRX_SR_SBD) | ||
683 | dev_dbg(&pdev->dev, "Synchronization block detected\n"); | ||
684 | |||
685 | if (flags & SPDIFRX_SR_SYNCD) { | ||
686 | dev_dbg(&pdev->dev, "Synchronization done\n"); | ||
687 | |||
688 | /* Enable spdifrx */ | ||
689 | cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_ENABLE); | ||
690 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
691 | SPDIFRX_CR_SPDIFEN_MASK, cr); | ||
692 | } | ||
693 | |||
694 | if (flags & SPDIFRX_SR_FERR) { | ||
695 | dev_dbg(&pdev->dev, "Frame error\n"); | ||
696 | err = 1; | ||
697 | } | ||
698 | |||
699 | if (flags & SPDIFRX_SR_SERR) { | ||
700 | dev_dbg(&pdev->dev, "Synchronization error\n"); | ||
701 | err = 1; | ||
702 | } | ||
703 | |||
704 | if (flags & SPDIFRX_SR_TERR) { | ||
705 | dev_dbg(&pdev->dev, "Timeout error\n"); | ||
706 | err = 1; | ||
707 | } | ||
708 | |||
709 | if (err) { | ||
710 | /* SPDIFRX in STATE_STOP. Disable SPDIFRX to clear errors */ | ||
711 | cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); | ||
712 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
713 | SPDIFRX_CR_SPDIFEN_MASK, cr); | ||
714 | |||
715 | if (substream) | ||
716 | snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); | ||
717 | |||
718 | return IRQ_HANDLED; | ||
719 | } | ||
720 | |||
721 | if (err_xrun && substream) | ||
722 | snd_pcm_stop_xrun(substream); | ||
723 | |||
724 | return IRQ_HANDLED; | ||
725 | } | ||
726 | |||
727 | static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, | ||
728 | struct snd_soc_dai *cpu_dai) | ||
729 | { | ||
730 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
731 | int ret; | ||
732 | |||
733 | spdifrx->substream = substream; | ||
734 | |||
735 | ret = clk_prepare_enable(spdifrx->kclk); | ||
736 | if (ret) | ||
737 | dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); | ||
738 | |||
739 | return ret; | ||
740 | } | ||
741 | |||
742 | static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, | ||
743 | struct snd_pcm_hw_params *params, | ||
744 | struct snd_soc_dai *cpu_dai) | ||
745 | { | ||
746 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
747 | int data_size = params_width(params); | ||
748 | int fmt; | ||
749 | |||
750 | switch (data_size) { | ||
751 | case 16: | ||
752 | fmt = SPDIFRX_DRFMT_PACKED; | ||
753 | spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
754 | break; | ||
755 | case 32: | ||
756 | fmt = SPDIFRX_DRFMT_LEFT; | ||
757 | spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
758 | break; | ||
759 | default: | ||
760 | dev_err(&spdifrx->pdev->dev, "Unexpected data format\n"); | ||
761 | return -EINVAL; | ||
762 | } | ||
763 | |||
764 | snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); | ||
765 | |||
766 | return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
767 | SPDIFRX_CR_DRFMT_MASK, | ||
768 | SPDIFRX_CR_DRFMTSET(fmt)); | ||
769 | } | ||
770 | |||
771 | static int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, | ||
772 | struct snd_soc_dai *cpu_dai) | ||
773 | { | ||
774 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
775 | int ret = 0; | ||
776 | |||
777 | switch (cmd) { | ||
778 | case SNDRV_PCM_TRIGGER_START: | ||
779 | case SNDRV_PCM_TRIGGER_RESUME: | ||
780 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
781 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, | ||
782 | SPDIFRX_IMR_OVRIE, SPDIFRX_IMR_OVRIE); | ||
783 | |||
784 | regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, | ||
785 | SPDIFRX_CR_RXDMAEN, SPDIFRX_CR_RXDMAEN); | ||
786 | |||
787 | ret = stm32_spdifrx_start_sync(spdifrx); | ||
788 | break; | ||
789 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
790 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
791 | case SNDRV_PCM_TRIGGER_STOP: | ||
792 | stm32_spdifrx_stop(spdifrx); | ||
793 | break; | ||
794 | default: | ||
795 | return -EINVAL; | ||
796 | } | ||
797 | |||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, | ||
802 | struct snd_soc_dai *cpu_dai) | ||
803 | { | ||
804 | struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); | ||
805 | |||
806 | spdifrx->substream = NULL; | ||
807 | clk_disable_unprepare(spdifrx->kclk); | ||
808 | } | ||
809 | |||
810 | static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { | ||
811 | .startup = stm32_spdifrx_startup, | ||
812 | .hw_params = stm32_spdifrx_hw_params, | ||
813 | .trigger = stm32_spdifrx_trigger, | ||
814 | .shutdown = stm32_spdifrx_shutdown, | ||
815 | }; | ||
816 | |||
817 | static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { | ||
818 | { | ||
819 | .name = "spdifrx-capture-cpu-dai", | ||
820 | .probe = stm32_spdifrx_dai_probe, | ||
821 | .capture = { | ||
822 | .stream_name = "CPU-Capture", | ||
823 | .channels_min = 1, | ||
824 | .channels_max = 2, | ||
825 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
826 | .formats = SNDRV_PCM_FMTBIT_S32_LE | | ||
827 | SNDRV_PCM_FMTBIT_S16_LE, | ||
828 | }, | ||
829 | .ops = &stm32_spdifrx_pcm_dai_ops, | ||
830 | } | ||
831 | }; | ||
832 | |||
833 | static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { | ||
834 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, | ||
835 | .buffer_bytes_max = 8 * PAGE_SIZE, | ||
836 | .period_bytes_max = 2048, /* MDMA constraint */ | ||
837 | .periods_min = 2, | ||
838 | .periods_max = 8, | ||
839 | }; | ||
840 | |||
841 | static const struct snd_soc_component_driver stm32_spdifrx_component = { | ||
842 | .name = "stm32-spdifrx", | ||
843 | }; | ||
844 | |||
845 | static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = { | ||
846 | .pcm_hardware = &stm32_spdifrx_pcm_hw, | ||
847 | .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, | ||
848 | }; | ||
849 | |||
850 | static const struct of_device_id stm32_spdifrx_ids[] = { | ||
851 | { | ||
852 | .compatible = "st,stm32h7-spdifrx", | ||
853 | .data = &stm32_h7_spdifrx_regmap_conf | ||
854 | }, | ||
855 | {} | ||
856 | }; | ||
857 | |||
858 | static int stm_spdifrx_parse_of(struct platform_device *pdev, | ||
859 | struct stm32_spdifrx_data *spdifrx) | ||
860 | { | ||
861 | struct device_node *np = pdev->dev.of_node; | ||
862 | const struct of_device_id *of_id; | ||
863 | struct resource *res; | ||
864 | |||
865 | if (!np) | ||
866 | return -ENODEV; | ||
867 | |||
868 | of_id = of_match_device(stm32_spdifrx_ids, &pdev->dev); | ||
869 | if (of_id) | ||
870 | spdifrx->regmap_conf = | ||
871 | (const struct regmap_config *)of_id->data; | ||
872 | else | ||
873 | return -EINVAL; | ||
874 | |||
875 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
876 | spdifrx->base = devm_ioremap_resource(&pdev->dev, res); | ||
877 | if (IS_ERR(spdifrx->base)) | ||
878 | return PTR_ERR(spdifrx->base); | ||
879 | |||
880 | spdifrx->phys_addr = res->start; | ||
881 | |||
882 | spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); | ||
883 | if (IS_ERR(spdifrx->kclk)) { | ||
884 | dev_err(&pdev->dev, "Could not get kclk\n"); | ||
885 | return PTR_ERR(spdifrx->kclk); | ||
886 | } | ||
887 | |||
888 | spdifrx->irq = platform_get_irq(pdev, 0); | ||
889 | if (spdifrx->irq < 0) { | ||
890 | dev_err(&pdev->dev, "No irq for node %s\n", pdev->name); | ||
891 | return spdifrx->irq; | ||
892 | } | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static int stm32_spdifrx_probe(struct platform_device *pdev) | ||
898 | { | ||
899 | struct stm32_spdifrx_data *spdifrx; | ||
900 | struct reset_control *rst; | ||
901 | const struct snd_dmaengine_pcm_config *pcm_config = NULL; | ||
902 | int ret; | ||
903 | |||
904 | spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); | ||
905 | if (!spdifrx) | ||
906 | return -ENOMEM; | ||
907 | |||
908 | spdifrx->pdev = pdev; | ||
909 | init_completion(&spdifrx->cs_completion); | ||
910 | spin_lock_init(&spdifrx->lock); | ||
911 | |||
912 | platform_set_drvdata(pdev, spdifrx); | ||
913 | |||
914 | ret = stm_spdifrx_parse_of(pdev, spdifrx); | ||
915 | if (ret) | ||
916 | return ret; | ||
917 | |||
918 | spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", | ||
919 | spdifrx->base, | ||
920 | spdifrx->regmap_conf); | ||
921 | if (IS_ERR(spdifrx->regmap)) { | ||
922 | dev_err(&pdev->dev, "Regmap init failed\n"); | ||
923 | return PTR_ERR(spdifrx->regmap); | ||
924 | } | ||
925 | |||
926 | ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, | ||
927 | dev_name(&pdev->dev), spdifrx); | ||
928 | if (ret) { | ||
929 | dev_err(&pdev->dev, "IRQ request returned %d\n", ret); | ||
930 | return ret; | ||
931 | } | ||
932 | |||
933 | rst = devm_reset_control_get(&pdev->dev, NULL); | ||
934 | if (!IS_ERR(rst)) { | ||
935 | reset_control_assert(rst); | ||
936 | udelay(2); | ||
937 | reset_control_deassert(rst); | ||
938 | } | ||
939 | |||
940 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
941 | &stm32_spdifrx_component, | ||
942 | stm32_spdifrx_dai, | ||
943 | ARRAY_SIZE(stm32_spdifrx_dai)); | ||
944 | if (ret) | ||
945 | return ret; | ||
946 | |||
947 | ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); | ||
948 | if (ret) | ||
949 | goto error; | ||
950 | |||
951 | pcm_config = &stm32_spdifrx_pcm_config; | ||
952 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); | ||
953 | if (ret) { | ||
954 | dev_err(&pdev->dev, "PCM DMA register returned %d\n", ret); | ||
955 | goto error; | ||
956 | } | ||
957 | |||
958 | return 0; | ||
959 | |||
960 | error: | ||
961 | if (spdifrx->ctrl_chan) | ||
962 | dma_release_channel(spdifrx->ctrl_chan); | ||
963 | if (spdifrx->dmab) | ||
964 | snd_dma_free_pages(spdifrx->dmab); | ||
965 | |||
966 | return ret; | ||
967 | } | ||
968 | |||
969 | static int stm32_spdifrx_remove(struct platform_device *pdev) | ||
970 | { | ||
971 | struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); | ||
972 | |||
973 | if (spdifrx->ctrl_chan) | ||
974 | dma_release_channel(spdifrx->ctrl_chan); | ||
975 | |||
976 | if (spdifrx->dmab) | ||
977 | snd_dma_free_pages(spdifrx->dmab); | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); | ||
983 | |||
984 | static struct platform_driver stm32_spdifrx_driver = { | ||
985 | .driver = { | ||
986 | .name = "st,stm32-spdifrx", | ||
987 | .of_match_table = stm32_spdifrx_ids, | ||
988 | }, | ||
989 | .probe = stm32_spdifrx_probe, | ||
990 | .remove = stm32_spdifrx_remove, | ||
991 | }; | ||
992 | |||
993 | module_platform_driver(stm32_spdifrx_driver); | ||
994 | |||
995 | MODULE_DESCRIPTION("STM32 Soc spdifrx Interface"); | ||
996 | MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); | ||
997 | MODULE_ALIAS("platform:stm32-spdifrx"); | ||
998 | MODULE_LICENSE("GPL v2"); | ||