xref: /OK3568_Linux_fs/kernel/sound/soc/sh/rcar/ssiu.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Renesas R-Car SSIU support
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include "rsnd.h"
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #define SSIU_NAME "ssiu"
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun struct rsnd_ssiu {
12*4882a593Smuzhiyun 	struct rsnd_mod mod;
13*4882a593Smuzhiyun 	u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
14*4882a593Smuzhiyun 	unsigned int usrcnt;
15*4882a593Smuzhiyun 	int id;
16*4882a593Smuzhiyun 	int id_sub;
17*4882a593Smuzhiyun };
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun /* SSI_MODE */
20*4882a593Smuzhiyun #define TDM_EXT		(1 << 0)
21*4882a593Smuzhiyun #define TDM_SPLIT	(1 << 8)
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
24*4882a593Smuzhiyun #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
25*4882a593Smuzhiyun #define for_each_rsnd_ssiu(pos, priv, i)				\
26*4882a593Smuzhiyun 	for (i = 0;							\
27*4882a593Smuzhiyun 	     (i < rsnd_ssiu_nr(priv)) &&				\
28*4882a593Smuzhiyun 		     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));	\
29*4882a593Smuzhiyun 	     i++)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  *	SSI	Gen2		Gen3
33*4882a593Smuzhiyun  *	0	BUSIF0-3	BUSIF0-7
34*4882a593Smuzhiyun  *	1	BUSIF0-3	BUSIF0-7
35*4882a593Smuzhiyun  *	2	BUSIF0-3	BUSIF0-7
36*4882a593Smuzhiyun  *	3	BUSIF0		BUSIF0-7
37*4882a593Smuzhiyun  *	4	BUSIF0		BUSIF0-7
38*4882a593Smuzhiyun  *	5	BUSIF0		BUSIF0
39*4882a593Smuzhiyun  *	6	BUSIF0		BUSIF0
40*4882a593Smuzhiyun  *	7	BUSIF0		BUSIF0
41*4882a593Smuzhiyun  *	8	BUSIF0		BUSIF0
42*4882a593Smuzhiyun  *	9	BUSIF0-3	BUSIF0-7
43*4882a593Smuzhiyun  *	total	22		52
44*4882a593Smuzhiyun  */
45*4882a593Smuzhiyun static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
46*4882a593Smuzhiyun static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
47*4882a593Smuzhiyun 
rsnd_ssiu_get_status(struct rsnd_mod * mod,struct rsnd_dai_stream * io,enum rsnd_mod_type type)48*4882a593Smuzhiyun static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
49*4882a593Smuzhiyun 				 struct rsnd_dai_stream *io,
50*4882a593Smuzhiyun 				 enum rsnd_mod_type type)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
53*4882a593Smuzhiyun 	int busif = rsnd_mod_id_sub(mod);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	return &ssiu->busif_status[busif];
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
rsnd_ssiu_init(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)58*4882a593Smuzhiyun static int rsnd_ssiu_init(struct rsnd_mod *mod,
59*4882a593Smuzhiyun 			  struct rsnd_dai_stream *io,
60*4882a593Smuzhiyun 			  struct rsnd_priv *priv)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
63*4882a593Smuzhiyun 	u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
64*4882a593Smuzhiyun 	int use_busif = rsnd_ssi_use_busif(io);
65*4882a593Smuzhiyun 	int id = rsnd_mod_id(mod);
66*4882a593Smuzhiyun 	int is_clk_master = rsnd_rdai_is_clk_master(rdai);
67*4882a593Smuzhiyun 	u32 val1, val2;
68*4882a593Smuzhiyun 	int i;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	/* clear status */
71*4882a593Smuzhiyun 	switch (id) {
72*4882a593Smuzhiyun 	case 0:
73*4882a593Smuzhiyun 	case 1:
74*4882a593Smuzhiyun 	case 2:
75*4882a593Smuzhiyun 	case 3:
76*4882a593Smuzhiyun 	case 4:
77*4882a593Smuzhiyun 		for (i = 0; i < 4; i++)
78*4882a593Smuzhiyun 			rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
79*4882a593Smuzhiyun 		break;
80*4882a593Smuzhiyun 	case 9:
81*4882a593Smuzhiyun 		for (i = 0; i < 4; i++)
82*4882a593Smuzhiyun 			rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
83*4882a593Smuzhiyun 		break;
84*4882a593Smuzhiyun 	}
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	/*
87*4882a593Smuzhiyun 	 * SSI_MODE0
88*4882a593Smuzhiyun 	 */
89*4882a593Smuzhiyun 	rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	/*
92*4882a593Smuzhiyun 	 * SSI_MODE1 / SSI_MODE2
93*4882a593Smuzhiyun 	 *
94*4882a593Smuzhiyun 	 * FIXME
95*4882a593Smuzhiyun 	 * sharing/multi with SSI0 are mainly supported
96*4882a593Smuzhiyun 	 */
97*4882a593Smuzhiyun 	val1 = rsnd_mod_read(mod, SSI_MODE1);
98*4882a593Smuzhiyun 	val2 = rsnd_mod_read(mod, SSI_MODE2);
99*4882a593Smuzhiyun 	if (rsnd_ssi_is_pin_sharing(io)) {
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 		ssis |= (1 << id);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	} else if (ssis) {
104*4882a593Smuzhiyun 		/*
105*4882a593Smuzhiyun 		 * Multi SSI
106*4882a593Smuzhiyun 		 *
107*4882a593Smuzhiyun 		 * set synchronized bit here
108*4882a593Smuzhiyun 		 */
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 		/* SSI4 is synchronized with SSI3 */
111*4882a593Smuzhiyun 		if (ssis & (1 << 4))
112*4882a593Smuzhiyun 			val1 |= (1 << 20);
113*4882a593Smuzhiyun 		/* SSI012 are synchronized */
114*4882a593Smuzhiyun 		if (ssis == 0x0006)
115*4882a593Smuzhiyun 			val1 |= (1 << 4);
116*4882a593Smuzhiyun 		/* SSI0129 are synchronized */
117*4882a593Smuzhiyun 		if (ssis == 0x0206)
118*4882a593Smuzhiyun 			val2 |= (1 << 4);
119*4882a593Smuzhiyun 	}
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/* SSI1 is sharing pin with SSI0 */
122*4882a593Smuzhiyun 	if (ssis & (1 << 1))
123*4882a593Smuzhiyun 		val1 |= is_clk_master ? 0x2 : 0x1;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* SSI2 is sharing pin with SSI0 */
126*4882a593Smuzhiyun 	if (ssis & (1 << 2))
127*4882a593Smuzhiyun 		val1 |= is_clk_master ?	0x2 << 2 :
128*4882a593Smuzhiyun 					0x1 << 2;
129*4882a593Smuzhiyun 	/* SSI4 is sharing pin with SSI3 */
130*4882a593Smuzhiyun 	if (ssis & (1 << 4))
131*4882a593Smuzhiyun 		val1 |= is_clk_master ? 0x2 << 16 :
132*4882a593Smuzhiyun 					0x1 << 16;
133*4882a593Smuzhiyun 	/* SSI9 is sharing pin with SSI0 */
134*4882a593Smuzhiyun 	if (ssis & (1 << 9))
135*4882a593Smuzhiyun 		val2 |= is_clk_master ? 0x2 : 0x1;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
138*4882a593Smuzhiyun 	rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return 0;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
144*4882a593Smuzhiyun 	.name		= SSIU_NAME,
145*4882a593Smuzhiyun 	.init		= rsnd_ssiu_init,
146*4882a593Smuzhiyun 	.get_status	= rsnd_ssiu_get_status,
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun 
rsnd_ssiu_init_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)149*4882a593Smuzhiyun static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
150*4882a593Smuzhiyun 			       struct rsnd_dai_stream *io,
151*4882a593Smuzhiyun 			       struct rsnd_priv *priv)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
154*4882a593Smuzhiyun 	u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
155*4882a593Smuzhiyun 	u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
156*4882a593Smuzhiyun 	int ret;
157*4882a593Smuzhiyun 	u32 mode = 0;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	ret = rsnd_ssiu_init(mod, io, priv);
160*4882a593Smuzhiyun 	if (ret < 0)
161*4882a593Smuzhiyun 		return ret;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	ssiu->usrcnt++;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/*
166*4882a593Smuzhiyun 	 * TDM Extend/Split Mode
167*4882a593Smuzhiyun 	 * see
168*4882a593Smuzhiyun 	 *	rsnd_ssi_config_init()
169*4882a593Smuzhiyun 	 */
170*4882a593Smuzhiyun 	if (rsnd_runtime_is_tdm(io))
171*4882a593Smuzhiyun 		mode = TDM_EXT;
172*4882a593Smuzhiyun 	else if (rsnd_runtime_is_tdm_split(io))
173*4882a593Smuzhiyun 		mode = TDM_SPLIT;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	rsnd_mod_write(mod, SSI_MODE, mode);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	if (rsnd_ssi_use_busif(io)) {
178*4882a593Smuzhiyun 		int id = rsnd_mod_id(mod);
179*4882a593Smuzhiyun 		int busif = rsnd_mod_id_sub(mod);
180*4882a593Smuzhiyun 		enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 		if ((id == 9) && (busif >= 4)) {
183*4882a593Smuzhiyun 			adinr_reg = SSI9_BUSIF_ADINR(busif);
184*4882a593Smuzhiyun 			mode_reg = SSI9_BUSIF_MODE(busif);
185*4882a593Smuzhiyun 			dalign_reg = SSI9_BUSIF_DALIGN(busif);
186*4882a593Smuzhiyun 		} else {
187*4882a593Smuzhiyun 			adinr_reg = SSI_BUSIF_ADINR(busif);
188*4882a593Smuzhiyun 			mode_reg = SSI_BUSIF_MODE(busif);
189*4882a593Smuzhiyun 			dalign_reg = SSI_BUSIF_DALIGN(busif);
190*4882a593Smuzhiyun 		}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 		rsnd_mod_write(mod, adinr_reg,
193*4882a593Smuzhiyun 			       rsnd_get_adinr_bit(mod, io) |
194*4882a593Smuzhiyun 			       (rsnd_io_is_play(io) ?
195*4882a593Smuzhiyun 				rsnd_runtime_channel_after_ctu(io) :
196*4882a593Smuzhiyun 				rsnd_runtime_channel_original(io)));
197*4882a593Smuzhiyun 		rsnd_mod_write(mod, mode_reg,
198*4882a593Smuzhiyun 			       rsnd_get_busif_shift(io, mod) | 1);
199*4882a593Smuzhiyun 		rsnd_mod_write(mod, dalign_reg,
200*4882a593Smuzhiyun 			       rsnd_get_dalign(mod, io));
201*4882a593Smuzhiyun 	}
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (has_hdmi0 || has_hdmi1) {
204*4882a593Smuzhiyun 		enum rsnd_mod_type rsnd_ssi_array[] = {
205*4882a593Smuzhiyun 			RSND_MOD_SSIM1,
206*4882a593Smuzhiyun 			RSND_MOD_SSIM2,
207*4882a593Smuzhiyun 			RSND_MOD_SSIM3,
208*4882a593Smuzhiyun 		};
209*4882a593Smuzhiyun 		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
210*4882a593Smuzhiyun 		struct rsnd_mod *pos;
211*4882a593Smuzhiyun 		u32 val;
212*4882a593Smuzhiyun 		int i, shift;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		i = rsnd_mod_id(ssi_mod);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 		/* output all same SSI as default */
217*4882a593Smuzhiyun 		val =	i << 16 |
218*4882a593Smuzhiyun 			i << 20 |
219*4882a593Smuzhiyun 			i << 24 |
220*4882a593Smuzhiyun 			i << 28 |
221*4882a593Smuzhiyun 			i;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 		for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
224*4882a593Smuzhiyun 			shift	= (i * 4) + 20;
225*4882a593Smuzhiyun 			val	= (val & ~(0xF << shift)) |
226*4882a593Smuzhiyun 				rsnd_mod_id(pos) << shift;
227*4882a593Smuzhiyun 		}
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		if (has_hdmi0)
230*4882a593Smuzhiyun 			rsnd_mod_write(mod, HDMI0_SEL, val);
231*4882a593Smuzhiyun 		if (has_hdmi1)
232*4882a593Smuzhiyun 			rsnd_mod_write(mod, HDMI1_SEL, val);
233*4882a593Smuzhiyun 	}
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	return 0;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
rsnd_ssiu_start_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)238*4882a593Smuzhiyun static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
239*4882a593Smuzhiyun 				struct rsnd_dai_stream *io,
240*4882a593Smuzhiyun 				struct rsnd_priv *priv)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	int busif = rsnd_mod_id_sub(mod);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (!rsnd_ssi_use_busif(io))
245*4882a593Smuzhiyun 		return 0;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (rsnd_ssi_multi_secondaries_runtime(io))
250*4882a593Smuzhiyun 		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return 0;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
rsnd_ssiu_stop_gen2(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)255*4882a593Smuzhiyun static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
256*4882a593Smuzhiyun 			       struct rsnd_dai_stream *io,
257*4882a593Smuzhiyun 			       struct rsnd_priv *priv)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
260*4882a593Smuzhiyun 	int busif = rsnd_mod_id_sub(mod);
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	if (!rsnd_ssi_use_busif(io))
263*4882a593Smuzhiyun 		return 0;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	if (--ssiu->usrcnt)
268*4882a593Smuzhiyun 		return 0;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	if (rsnd_ssi_multi_secondaries_runtime(io))
271*4882a593Smuzhiyun 		rsnd_mod_write(mod, SSI_CONTROL, 0);
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun 
rsnd_ssiu_id(struct rsnd_mod * mod)276*4882a593Smuzhiyun static int rsnd_ssiu_id(struct rsnd_mod *mod)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* see rsnd_ssiu_probe() */
281*4882a593Smuzhiyun 	return ssiu->id;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
rsnd_ssiu_id_sub(struct rsnd_mod * mod)284*4882a593Smuzhiyun static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	/* see rsnd_ssiu_probe() */
289*4882a593Smuzhiyun 	return ssiu->id_sub;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun 
rsnd_ssiu_dma_req(struct rsnd_dai_stream * io,struct rsnd_mod * mod)292*4882a593Smuzhiyun static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
293*4882a593Smuzhiyun 					  struct rsnd_mod *mod)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
296*4882a593Smuzhiyun 	int is_play = rsnd_io_is_play(io);
297*4882a593Smuzhiyun 	char *name;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	/*
300*4882a593Smuzhiyun 	 * It should use "rcar_sound,ssiu" on DT.
301*4882a593Smuzhiyun 	 * But, we need to keep compatibility for old version.
302*4882a593Smuzhiyun 	 *
303*4882a593Smuzhiyun 	 * If it has "rcar_sound.ssiu", it will be used.
304*4882a593Smuzhiyun 	 * If not, "rcar_sound.ssi" will be used.
305*4882a593Smuzhiyun 	 * see
306*4882a593Smuzhiyun 	 *	rsnd_ssi_dma_req()
307*4882a593Smuzhiyun 	 *	rsnd_dma_of_path()
308*4882a593Smuzhiyun 	 */
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	name = is_play ? "rx" : "tx";
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
313*4882a593Smuzhiyun 					mod, name);
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
317*4882a593Smuzhiyun 	.name		= SSIU_NAME,
318*4882a593Smuzhiyun 	.dma_req	= rsnd_ssiu_dma_req,
319*4882a593Smuzhiyun 	.init		= rsnd_ssiu_init_gen2,
320*4882a593Smuzhiyun 	.start		= rsnd_ssiu_start_gen2,
321*4882a593Smuzhiyun 	.stop		= rsnd_ssiu_stop_gen2,
322*4882a593Smuzhiyun 	.get_status	= rsnd_ssiu_get_status,
323*4882a593Smuzhiyun };
324*4882a593Smuzhiyun 
rsnd_ssiu_mod_get(struct rsnd_priv * priv,int id)325*4882a593Smuzhiyun static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun 	if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
328*4882a593Smuzhiyun 		id = 0;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun 
rsnd_parse_connect_ssiu_compatible(struct rsnd_priv * priv,struct rsnd_dai_stream * io)333*4882a593Smuzhiyun static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
334*4882a593Smuzhiyun 					       struct rsnd_dai_stream *io)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
337*4882a593Smuzhiyun 	struct rsnd_mod *mod;
338*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu;
339*4882a593Smuzhiyun 	int i;
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (!ssi_mod)
342*4882a593Smuzhiyun 		return;
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	/* select BUSIF0 */
345*4882a593Smuzhiyun 	for_each_rsnd_ssiu(ssiu, priv, i) {
346*4882a593Smuzhiyun 		mod = rsnd_mod_get(ssiu);
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 		if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
349*4882a593Smuzhiyun 		    (rsnd_mod_id_sub(mod) == 0)) {
350*4882a593Smuzhiyun 			rsnd_dai_connect(mod, io, mod->type);
351*4882a593Smuzhiyun 			return;
352*4882a593Smuzhiyun 		}
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
rsnd_parse_connect_ssiu(struct rsnd_dai * rdai,struct device_node * playback,struct device_node * capture)356*4882a593Smuzhiyun void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
357*4882a593Smuzhiyun 			     struct device_node *playback,
358*4882a593Smuzhiyun 			     struct device_node *capture)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
361*4882a593Smuzhiyun 	struct device_node *node = rsnd_ssiu_of_node(priv);
362*4882a593Smuzhiyun 	struct device_node *np;
363*4882a593Smuzhiyun 	struct rsnd_mod *mod;
364*4882a593Smuzhiyun 	struct rsnd_dai_stream *io_p = &rdai->playback;
365*4882a593Smuzhiyun 	struct rsnd_dai_stream *io_c = &rdai->capture;
366*4882a593Smuzhiyun 	int i;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* use rcar_sound,ssiu if exist */
369*4882a593Smuzhiyun 	if (node) {
370*4882a593Smuzhiyun 		i = 0;
371*4882a593Smuzhiyun 		for_each_child_of_node(node, np) {
372*4882a593Smuzhiyun 			mod = rsnd_ssiu_mod_get(priv, i);
373*4882a593Smuzhiyun 			if (np == playback)
374*4882a593Smuzhiyun 				rsnd_dai_connect(mod, io_p, mod->type);
375*4882a593Smuzhiyun 			if (np == capture)
376*4882a593Smuzhiyun 				rsnd_dai_connect(mod, io_c, mod->type);
377*4882a593Smuzhiyun 			i++;
378*4882a593Smuzhiyun 		}
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 		of_node_put(node);
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	/* Keep DT compatibility */
384*4882a593Smuzhiyun 	if (!rsnd_io_to_mod_ssiu(io_p))
385*4882a593Smuzhiyun 		rsnd_parse_connect_ssiu_compatible(priv, io_p);
386*4882a593Smuzhiyun 	if (!rsnd_io_to_mod_ssiu(io_c))
387*4882a593Smuzhiyun 		rsnd_parse_connect_ssiu_compatible(priv, io_c);
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
rsnd_ssiu_probe(struct rsnd_priv * priv)390*4882a593Smuzhiyun int rsnd_ssiu_probe(struct rsnd_priv *priv)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct device *dev = rsnd_priv_to_dev(priv);
393*4882a593Smuzhiyun 	struct device_node *node;
394*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu;
395*4882a593Smuzhiyun 	struct rsnd_mod_ops *ops;
396*4882a593Smuzhiyun 	const int *list = NULL;
397*4882a593Smuzhiyun 	int i, nr, ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/*
400*4882a593Smuzhiyun 	 * Keep DT compatibility.
401*4882a593Smuzhiyun 	 * if it has "rcar_sound,ssiu", use it.
402*4882a593Smuzhiyun 	 * if not, use "rcar_sound,ssi"
403*4882a593Smuzhiyun 	 * see
404*4882a593Smuzhiyun 	 *	rsnd_ssiu_bufsif_to_id()
405*4882a593Smuzhiyun 	 */
406*4882a593Smuzhiyun 	node = rsnd_ssiu_of_node(priv);
407*4882a593Smuzhiyun 	if (node)
408*4882a593Smuzhiyun 		nr = of_get_child_count(node);
409*4882a593Smuzhiyun 	else
410*4882a593Smuzhiyun 		nr = priv->ssi_nr;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	ssiu	= devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
413*4882a593Smuzhiyun 	if (!ssiu)
414*4882a593Smuzhiyun 		return -ENOMEM;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	priv->ssiu	= ssiu;
417*4882a593Smuzhiyun 	priv->ssiu_nr	= nr;
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (rsnd_is_gen1(priv))
420*4882a593Smuzhiyun 		ops = &rsnd_ssiu_ops_gen1;
421*4882a593Smuzhiyun 	else
422*4882a593Smuzhiyun 		ops = &rsnd_ssiu_ops_gen2;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* Keep compatibility */
425*4882a593Smuzhiyun 	nr = 0;
426*4882a593Smuzhiyun 	if ((node) &&
427*4882a593Smuzhiyun 	    (ops == &rsnd_ssiu_ops_gen2)) {
428*4882a593Smuzhiyun 		ops->id		= rsnd_ssiu_id;
429*4882a593Smuzhiyun 		ops->id_sub	= rsnd_ssiu_id_sub;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 		if (rsnd_is_gen2(priv)) {
432*4882a593Smuzhiyun 			list	= gen2_id;
433*4882a593Smuzhiyun 			nr	= ARRAY_SIZE(gen2_id);
434*4882a593Smuzhiyun 		} else if (rsnd_is_gen3(priv)) {
435*4882a593Smuzhiyun 			list	= gen3_id;
436*4882a593Smuzhiyun 			nr	= ARRAY_SIZE(gen3_id);
437*4882a593Smuzhiyun 		} else {
438*4882a593Smuzhiyun 			dev_err(dev, "unknown SSIU\n");
439*4882a593Smuzhiyun 			return -ENODEV;
440*4882a593Smuzhiyun 		}
441*4882a593Smuzhiyun 	}
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun 	for_each_rsnd_ssiu(ssiu, priv, i) {
444*4882a593Smuzhiyun 		if (node) {
445*4882a593Smuzhiyun 			int j;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 			/*
448*4882a593Smuzhiyun 			 * see
449*4882a593Smuzhiyun 			 *	rsnd_ssiu_get_id()
450*4882a593Smuzhiyun 			 *	rsnd_ssiu_get_id_sub()
451*4882a593Smuzhiyun 			 */
452*4882a593Smuzhiyun 			for (j = 0; j < nr; j++) {
453*4882a593Smuzhiyun 				if (list[j] > i)
454*4882a593Smuzhiyun 					break;
455*4882a593Smuzhiyun 				ssiu->id	= j;
456*4882a593Smuzhiyun 				ssiu->id_sub	= i - list[ssiu->id];
457*4882a593Smuzhiyun 			}
458*4882a593Smuzhiyun 		} else {
459*4882a593Smuzhiyun 			ssiu->id = i;
460*4882a593Smuzhiyun 		}
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
463*4882a593Smuzhiyun 				    ops, NULL, RSND_MOD_SSIU, i);
464*4882a593Smuzhiyun 		if (ret)
465*4882a593Smuzhiyun 			return ret;
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
rsnd_ssiu_remove(struct rsnd_priv * priv)471*4882a593Smuzhiyun void rsnd_ssiu_remove(struct rsnd_priv *priv)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	struct rsnd_ssiu *ssiu;
474*4882a593Smuzhiyun 	int i;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	for_each_rsnd_ssiu(ssiu, priv, i) {
477*4882a593Smuzhiyun 		rsnd_mod_quit(rsnd_mod_get(ssiu));
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun }
480