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