xref: /linux/sound/soc/renesas/rcar/ssiu.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
1*c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0
2*c087a94bSLad Prabhakar //
3*c087a94bSLad Prabhakar // Renesas R-Car SSIU support
4*c087a94bSLad Prabhakar //
5*c087a94bSLad Prabhakar // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6*c087a94bSLad Prabhakar 
7*c087a94bSLad Prabhakar #include "rsnd.h"
8*c087a94bSLad Prabhakar 
9*c087a94bSLad Prabhakar #define SSIU_NAME "ssiu"
10*c087a94bSLad Prabhakar 
11*c087a94bSLad Prabhakar struct rsnd_ssiu {
12*c087a94bSLad Prabhakar 	struct rsnd_mod mod;
13*c087a94bSLad Prabhakar 	u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
14*c087a94bSLad Prabhakar 	unsigned int usrcnt;
15*c087a94bSLad Prabhakar 	int id;
16*c087a94bSLad Prabhakar 	int id_sub;
17*c087a94bSLad Prabhakar };
18*c087a94bSLad Prabhakar 
19*c087a94bSLad Prabhakar /* SSI_MODE */
20*c087a94bSLad Prabhakar #define TDM_EXT		(1 << 0)
21*c087a94bSLad Prabhakar #define TDM_SPLIT	(1 << 8)
22*c087a94bSLad Prabhakar 
23*c087a94bSLad Prabhakar #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
24*c087a94bSLad Prabhakar #define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
25*c087a94bSLad Prabhakar #define for_each_rsnd_ssiu(pos, priv, i)				\
26*c087a94bSLad Prabhakar 	for (i = 0;							\
27*c087a94bSLad Prabhakar 	     (i < rsnd_ssiu_nr(priv)) &&				\
28*c087a94bSLad Prabhakar 		     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));	\
29*c087a94bSLad Prabhakar 	     i++)
30*c087a94bSLad Prabhakar 
31*c087a94bSLad Prabhakar /*
32*c087a94bSLad Prabhakar  *	SSI	Gen2		Gen3		Gen4
33*c087a94bSLad Prabhakar  *	0	BUSIF0-3	BUSIF0-7	BUSIF0-7
34*c087a94bSLad Prabhakar  *	1	BUSIF0-3	BUSIF0-7
35*c087a94bSLad Prabhakar  *	2	BUSIF0-3	BUSIF0-7
36*c087a94bSLad Prabhakar  *	3	BUSIF0		BUSIF0-7
37*c087a94bSLad Prabhakar  *	4	BUSIF0		BUSIF0-7
38*c087a94bSLad Prabhakar  *	5	BUSIF0		BUSIF0
39*c087a94bSLad Prabhakar  *	6	BUSIF0		BUSIF0
40*c087a94bSLad Prabhakar  *	7	BUSIF0		BUSIF0
41*c087a94bSLad Prabhakar  *	8	BUSIF0		BUSIF0
42*c087a94bSLad Prabhakar  *	9	BUSIF0-3	BUSIF0-7
43*c087a94bSLad Prabhakar  *	total	22		52		8
44*c087a94bSLad Prabhakar  */
45*c087a94bSLad Prabhakar static const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
46*c087a94bSLad Prabhakar static const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
47*c087a94bSLad Prabhakar static const int gen4_id[] = { 0 };
48*c087a94bSLad Prabhakar 
49*c087a94bSLad Prabhakar /* enable busif buffer over/under run interrupt. */
50*c087a94bSLad Prabhakar #define rsnd_ssiu_busif_err_irq_enable(mod)  rsnd_ssiu_busif_err_irq_ctrl(mod, 1)
51*c087a94bSLad Prabhakar #define rsnd_ssiu_busif_err_irq_disable(mod) rsnd_ssiu_busif_err_irq_ctrl(mod, 0)
52*c087a94bSLad Prabhakar static void rsnd_ssiu_busif_err_irq_ctrl(struct rsnd_mod *mod, int enable)
53*c087a94bSLad Prabhakar {
54*c087a94bSLad Prabhakar 	int id = rsnd_mod_id(mod);
55*c087a94bSLad Prabhakar 	int shift, offset;
56*c087a94bSLad Prabhakar 	int i;
57*c087a94bSLad Prabhakar 
58*c087a94bSLad Prabhakar 	switch (id) {
59*c087a94bSLad Prabhakar 	case 0:
60*c087a94bSLad Prabhakar 	case 1:
61*c087a94bSLad Prabhakar 	case 2:
62*c087a94bSLad Prabhakar 	case 3:
63*c087a94bSLad Prabhakar 	case 4:
64*c087a94bSLad Prabhakar 		shift  = id;
65*c087a94bSLad Prabhakar 		offset = 0;
66*c087a94bSLad Prabhakar 		break;
67*c087a94bSLad Prabhakar 	case 9:
68*c087a94bSLad Prabhakar 		shift  = 1;
69*c087a94bSLad Prabhakar 		offset = 1;
70*c087a94bSLad Prabhakar 		break;
71*c087a94bSLad Prabhakar 	default:
72*c087a94bSLad Prabhakar 		return;
73*c087a94bSLad Prabhakar 	}
74*c087a94bSLad Prabhakar 
75*c087a94bSLad Prabhakar 	for (i = 0; i < 4; i++) {
76*c087a94bSLad Prabhakar 		enum rsnd_reg reg = SSI_SYS_INT_ENABLE((i * 2) + offset);
77*c087a94bSLad Prabhakar 		u32 val = 0xf << (shift * 4);
78*c087a94bSLad Prabhakar 		u32 sys_int_enable = rsnd_mod_read(mod, reg);
79*c087a94bSLad Prabhakar 
80*c087a94bSLad Prabhakar 		if (enable)
81*c087a94bSLad Prabhakar 			sys_int_enable |= val;
82*c087a94bSLad Prabhakar 		else
83*c087a94bSLad Prabhakar 			sys_int_enable &= ~val;
84*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, reg, sys_int_enable);
85*c087a94bSLad Prabhakar 	}
86*c087a94bSLad Prabhakar }
87*c087a94bSLad Prabhakar 
88*c087a94bSLad Prabhakar bool rsnd_ssiu_busif_err_status_clear(struct rsnd_mod *mod)
89*c087a94bSLad Prabhakar {
90*c087a94bSLad Prabhakar 	bool error = false;
91*c087a94bSLad Prabhakar 	int id = rsnd_mod_id(mod);
92*c087a94bSLad Prabhakar 	int shift, offset;
93*c087a94bSLad Prabhakar 	int i;
94*c087a94bSLad Prabhakar 
95*c087a94bSLad Prabhakar 	switch (id) {
96*c087a94bSLad Prabhakar 	case 0:
97*c087a94bSLad Prabhakar 	case 1:
98*c087a94bSLad Prabhakar 	case 2:
99*c087a94bSLad Prabhakar 	case 3:
100*c087a94bSLad Prabhakar 	case 4:
101*c087a94bSLad Prabhakar 		shift  = id;
102*c087a94bSLad Prabhakar 		offset = 0;
103*c087a94bSLad Prabhakar 		break;
104*c087a94bSLad Prabhakar 	case 9:
105*c087a94bSLad Prabhakar 		shift  = 1;
106*c087a94bSLad Prabhakar 		offset = 1;
107*c087a94bSLad Prabhakar 		break;
108*c087a94bSLad Prabhakar 	default:
109*c087a94bSLad Prabhakar 		goto out;
110*c087a94bSLad Prabhakar 	}
111*c087a94bSLad Prabhakar 
112*c087a94bSLad Prabhakar 	for (i = 0; i < 4; i++) {
113*c087a94bSLad Prabhakar 		u32 reg = SSI_SYS_STATUS(i * 2) + offset;
114*c087a94bSLad Prabhakar 		u32 status = rsnd_mod_read(mod, reg);
115*c087a94bSLad Prabhakar 		u32 val = 0xf << (shift * 4);
116*c087a94bSLad Prabhakar 
117*c087a94bSLad Prabhakar 		status &= val;
118*c087a94bSLad Prabhakar 		if (status) {
119*c087a94bSLad Prabhakar 			struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
120*c087a94bSLad Prabhakar 			struct device *dev = rsnd_priv_to_dev(priv);
121*c087a94bSLad Prabhakar 
122*c087a94bSLad Prabhakar 			rsnd_print_irq_status(dev, "%s err status : 0x%08x\n",
123*c087a94bSLad Prabhakar 					      rsnd_mod_name(mod), status);
124*c087a94bSLad Prabhakar 			error = true;
125*c087a94bSLad Prabhakar 		}
126*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, reg, val);
127*c087a94bSLad Prabhakar 	}
128*c087a94bSLad Prabhakar out:
129*c087a94bSLad Prabhakar 	return error;
130*c087a94bSLad Prabhakar }
131*c087a94bSLad Prabhakar 
132*c087a94bSLad Prabhakar static u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
133*c087a94bSLad Prabhakar 				 struct rsnd_dai_stream *io,
134*c087a94bSLad Prabhakar 				 enum rsnd_mod_type type)
135*c087a94bSLad Prabhakar {
136*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
137*c087a94bSLad Prabhakar 	int busif = rsnd_mod_id_sub(mod);
138*c087a94bSLad Prabhakar 
139*c087a94bSLad Prabhakar 	return &ssiu->busif_status[busif];
140*c087a94bSLad Prabhakar }
141*c087a94bSLad Prabhakar 
142*c087a94bSLad Prabhakar static int rsnd_ssiu_init(struct rsnd_mod *mod,
143*c087a94bSLad Prabhakar 			  struct rsnd_dai_stream *io,
144*c087a94bSLad Prabhakar 			  struct rsnd_priv *priv)
145*c087a94bSLad Prabhakar {
146*c087a94bSLad Prabhakar 	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
147*c087a94bSLad Prabhakar 	u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
148*c087a94bSLad Prabhakar 	int use_busif = rsnd_ssi_use_busif(io);
149*c087a94bSLad Prabhakar 	int id = rsnd_mod_id(mod);
150*c087a94bSLad Prabhakar 	int is_clk_master = rsnd_rdai_is_clk_master(rdai);
151*c087a94bSLad Prabhakar 	u32 val1, val2;
152*c087a94bSLad Prabhakar 
153*c087a94bSLad Prabhakar 	/* clear status */
154*c087a94bSLad Prabhakar 	rsnd_ssiu_busif_err_status_clear(mod);
155*c087a94bSLad Prabhakar 
156*c087a94bSLad Prabhakar 	/* Gen4 doesn't have SSI_MODE */
157*c087a94bSLad Prabhakar 	if (rsnd_is_gen4(priv))
158*c087a94bSLad Prabhakar 		goto ssi_mode_setting_end;
159*c087a94bSLad Prabhakar 
160*c087a94bSLad Prabhakar 	/*
161*c087a94bSLad Prabhakar 	 * SSI_MODE0
162*c087a94bSLad Prabhakar 	 */
163*c087a94bSLad Prabhakar 	rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
164*c087a94bSLad Prabhakar 
165*c087a94bSLad Prabhakar 	/*
166*c087a94bSLad Prabhakar 	 * SSI_MODE1 / SSI_MODE2
167*c087a94bSLad Prabhakar 	 *
168*c087a94bSLad Prabhakar 	 * FIXME
169*c087a94bSLad Prabhakar 	 * sharing/multi with SSI0 are mainly supported
170*c087a94bSLad Prabhakar 	 */
171*c087a94bSLad Prabhakar 	val1 = rsnd_mod_read(mod, SSI_MODE1);
172*c087a94bSLad Prabhakar 	val2 = rsnd_mod_read(mod, SSI_MODE2);
173*c087a94bSLad Prabhakar 	if (rsnd_ssi_is_pin_sharing(io)) {
174*c087a94bSLad Prabhakar 
175*c087a94bSLad Prabhakar 		ssis |= (1 << id);
176*c087a94bSLad Prabhakar 
177*c087a94bSLad Prabhakar 	} else if (ssis) {
178*c087a94bSLad Prabhakar 		/*
179*c087a94bSLad Prabhakar 		 * Multi SSI
180*c087a94bSLad Prabhakar 		 *
181*c087a94bSLad Prabhakar 		 * set synchronized bit here
182*c087a94bSLad Prabhakar 		 */
183*c087a94bSLad Prabhakar 
184*c087a94bSLad Prabhakar 		/* SSI4 is synchronized with SSI3 */
185*c087a94bSLad Prabhakar 		if (ssis & (1 << 4))
186*c087a94bSLad Prabhakar 			val1 |= (1 << 20);
187*c087a94bSLad Prabhakar 		/* SSI012 are synchronized */
188*c087a94bSLad Prabhakar 		if (ssis == 0x0006)
189*c087a94bSLad Prabhakar 			val1 |= (1 << 4);
190*c087a94bSLad Prabhakar 		/* SSI0129 are synchronized */
191*c087a94bSLad Prabhakar 		if (ssis == 0x0206)
192*c087a94bSLad Prabhakar 			val2 |= (1 << 4);
193*c087a94bSLad Prabhakar 	}
194*c087a94bSLad Prabhakar 
195*c087a94bSLad Prabhakar 	/* SSI1 is sharing pin with SSI0 */
196*c087a94bSLad Prabhakar 	if (ssis & (1 << 1))
197*c087a94bSLad Prabhakar 		val1 |= is_clk_master ? 0x2 : 0x1;
198*c087a94bSLad Prabhakar 
199*c087a94bSLad Prabhakar 	/* SSI2 is sharing pin with SSI0 */
200*c087a94bSLad Prabhakar 	if (ssis & (1 << 2))
201*c087a94bSLad Prabhakar 		val1 |= is_clk_master ?	0x2 << 2 :
202*c087a94bSLad Prabhakar 					0x1 << 2;
203*c087a94bSLad Prabhakar 	/* SSI4 is sharing pin with SSI3 */
204*c087a94bSLad Prabhakar 	if (ssis & (1 << 4))
205*c087a94bSLad Prabhakar 		val1 |= is_clk_master ? 0x2 << 16 :
206*c087a94bSLad Prabhakar 					0x1 << 16;
207*c087a94bSLad Prabhakar 	/* SSI9 is sharing pin with SSI0 */
208*c087a94bSLad Prabhakar 	if (ssis & (1 << 9))
209*c087a94bSLad Prabhakar 		val2 |= is_clk_master ? 0x2 : 0x1;
210*c087a94bSLad Prabhakar 
211*c087a94bSLad Prabhakar 	rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
212*c087a94bSLad Prabhakar 	rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
213*c087a94bSLad Prabhakar 
214*c087a94bSLad Prabhakar ssi_mode_setting_end:
215*c087a94bSLad Prabhakar 	/*
216*c087a94bSLad Prabhakar 	 * Enable busif buffer over/under run interrupt.
217*c087a94bSLad Prabhakar 	 * It will be handled from ssi.c
218*c087a94bSLad Prabhakar 	 * see
219*c087a94bSLad Prabhakar 	 *	__rsnd_ssi_interrupt()
220*c087a94bSLad Prabhakar 	 */
221*c087a94bSLad Prabhakar 	rsnd_ssiu_busif_err_irq_enable(mod);
222*c087a94bSLad Prabhakar 
223*c087a94bSLad Prabhakar 	return 0;
224*c087a94bSLad Prabhakar }
225*c087a94bSLad Prabhakar 
226*c087a94bSLad Prabhakar static int rsnd_ssiu_quit(struct rsnd_mod *mod,
227*c087a94bSLad Prabhakar 			  struct rsnd_dai_stream *io,
228*c087a94bSLad Prabhakar 			  struct rsnd_priv *priv)
229*c087a94bSLad Prabhakar {
230*c087a94bSLad Prabhakar 	/* disable busif buffer over/under run interrupt. */
231*c087a94bSLad Prabhakar 	rsnd_ssiu_busif_err_irq_disable(mod);
232*c087a94bSLad Prabhakar 
233*c087a94bSLad Prabhakar 	return 0;
234*c087a94bSLad Prabhakar }
235*c087a94bSLad Prabhakar 
236*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
237*c087a94bSLad Prabhakar 	.name		= SSIU_NAME,
238*c087a94bSLad Prabhakar 	.init		= rsnd_ssiu_init,
239*c087a94bSLad Prabhakar 	.quit		= rsnd_ssiu_quit,
240*c087a94bSLad Prabhakar 	.get_status	= rsnd_ssiu_get_status,
241*c087a94bSLad Prabhakar };
242*c087a94bSLad Prabhakar 
243*c087a94bSLad Prabhakar static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
244*c087a94bSLad Prabhakar 			       struct rsnd_dai_stream *io,
245*c087a94bSLad Prabhakar 			       struct rsnd_priv *priv)
246*c087a94bSLad Prabhakar {
247*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
248*c087a94bSLad Prabhakar 	u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
249*c087a94bSLad Prabhakar 	u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
250*c087a94bSLad Prabhakar 	int ret;
251*c087a94bSLad Prabhakar 	u32 mode = 0;
252*c087a94bSLad Prabhakar 
253*c087a94bSLad Prabhakar 	ret = rsnd_ssiu_init(mod, io, priv);
254*c087a94bSLad Prabhakar 	if (ret < 0)
255*c087a94bSLad Prabhakar 		return ret;
256*c087a94bSLad Prabhakar 
257*c087a94bSLad Prabhakar 	ssiu->usrcnt++;
258*c087a94bSLad Prabhakar 
259*c087a94bSLad Prabhakar 	/*
260*c087a94bSLad Prabhakar 	 * TDM Extend/Split Mode
261*c087a94bSLad Prabhakar 	 * see
262*c087a94bSLad Prabhakar 	 *	rsnd_ssi_config_init()
263*c087a94bSLad Prabhakar 	 */
264*c087a94bSLad Prabhakar 	if (rsnd_runtime_is_tdm(io))
265*c087a94bSLad Prabhakar 		mode = TDM_EXT;
266*c087a94bSLad Prabhakar 	else if (rsnd_runtime_is_tdm_split(io))
267*c087a94bSLad Prabhakar 		mode = TDM_SPLIT;
268*c087a94bSLad Prabhakar 
269*c087a94bSLad Prabhakar 	rsnd_mod_write(mod, SSI_MODE, mode);
270*c087a94bSLad Prabhakar 
271*c087a94bSLad Prabhakar 	if (rsnd_ssi_use_busif(io)) {
272*c087a94bSLad Prabhakar 		int id = rsnd_mod_id(mod);
273*c087a94bSLad Prabhakar 		int busif = rsnd_mod_id_sub(mod);
274*c087a94bSLad Prabhakar 		enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
275*c087a94bSLad Prabhakar 
276*c087a94bSLad Prabhakar 		if ((id == 9) && (busif >= 4)) {
277*c087a94bSLad Prabhakar 			adinr_reg = SSI9_BUSIF_ADINR(busif);
278*c087a94bSLad Prabhakar 			mode_reg = SSI9_BUSIF_MODE(busif);
279*c087a94bSLad Prabhakar 			dalign_reg = SSI9_BUSIF_DALIGN(busif);
280*c087a94bSLad Prabhakar 		} else {
281*c087a94bSLad Prabhakar 			adinr_reg = SSI_BUSIF_ADINR(busif);
282*c087a94bSLad Prabhakar 			mode_reg = SSI_BUSIF_MODE(busif);
283*c087a94bSLad Prabhakar 			dalign_reg = SSI_BUSIF_DALIGN(busif);
284*c087a94bSLad Prabhakar 		}
285*c087a94bSLad Prabhakar 
286*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, adinr_reg,
287*c087a94bSLad Prabhakar 			       rsnd_get_adinr_bit(mod, io) |
288*c087a94bSLad Prabhakar 			       (rsnd_io_is_play(io) ?
289*c087a94bSLad Prabhakar 				rsnd_runtime_channel_after_ctu(io) :
290*c087a94bSLad Prabhakar 				rsnd_runtime_channel_original(io)));
291*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, mode_reg,
292*c087a94bSLad Prabhakar 			       rsnd_get_busif_shift(io, mod) | 1);
293*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, dalign_reg,
294*c087a94bSLad Prabhakar 			       rsnd_get_dalign(mod, io));
295*c087a94bSLad Prabhakar 	}
296*c087a94bSLad Prabhakar 
297*c087a94bSLad Prabhakar 	if (has_hdmi0 || has_hdmi1) {
298*c087a94bSLad Prabhakar 		enum rsnd_mod_type rsnd_ssi_array[] = {
299*c087a94bSLad Prabhakar 			RSND_MOD_SSIM1,
300*c087a94bSLad Prabhakar 			RSND_MOD_SSIM2,
301*c087a94bSLad Prabhakar 			RSND_MOD_SSIM3,
302*c087a94bSLad Prabhakar 		};
303*c087a94bSLad Prabhakar 		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
304*c087a94bSLad Prabhakar 		struct rsnd_mod *pos;
305*c087a94bSLad Prabhakar 		u32 val;
306*c087a94bSLad Prabhakar 		int i;
307*c087a94bSLad Prabhakar 
308*c087a94bSLad Prabhakar 		i = rsnd_mod_id(ssi_mod);
309*c087a94bSLad Prabhakar 
310*c087a94bSLad Prabhakar 		/* output all same SSI as default */
311*c087a94bSLad Prabhakar 		val =	i << 16 |
312*c087a94bSLad Prabhakar 			i << 20 |
313*c087a94bSLad Prabhakar 			i << 24 |
314*c087a94bSLad Prabhakar 			i << 28 |
315*c087a94bSLad Prabhakar 			i;
316*c087a94bSLad Prabhakar 
317*c087a94bSLad Prabhakar 		for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
318*c087a94bSLad Prabhakar 			int shift = (i * 4) + 20;
319*c087a94bSLad Prabhakar 
320*c087a94bSLad Prabhakar 			val	= (val & ~(0xF << shift)) |
321*c087a94bSLad Prabhakar 				rsnd_mod_id(pos) << shift;
322*c087a94bSLad Prabhakar 		}
323*c087a94bSLad Prabhakar 
324*c087a94bSLad Prabhakar 		if (has_hdmi0)
325*c087a94bSLad Prabhakar 			rsnd_mod_write(mod, HDMI0_SEL, val);
326*c087a94bSLad Prabhakar 		if (has_hdmi1)
327*c087a94bSLad Prabhakar 			rsnd_mod_write(mod, HDMI1_SEL, val);
328*c087a94bSLad Prabhakar 	}
329*c087a94bSLad Prabhakar 
330*c087a94bSLad Prabhakar 	return 0;
331*c087a94bSLad Prabhakar }
332*c087a94bSLad Prabhakar 
333*c087a94bSLad Prabhakar static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
334*c087a94bSLad Prabhakar 				struct rsnd_dai_stream *io,
335*c087a94bSLad Prabhakar 				struct rsnd_priv *priv)
336*c087a94bSLad Prabhakar {
337*c087a94bSLad Prabhakar 	int busif = rsnd_mod_id_sub(mod);
338*c087a94bSLad Prabhakar 
339*c087a94bSLad Prabhakar 	if (!rsnd_ssi_use_busif(io))
340*c087a94bSLad Prabhakar 		return 0;
341*c087a94bSLad Prabhakar 
342*c087a94bSLad Prabhakar 	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
343*c087a94bSLad Prabhakar 
344*c087a94bSLad Prabhakar 	if (rsnd_ssi_multi_secondaries_runtime(io))
345*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
346*c087a94bSLad Prabhakar 
347*c087a94bSLad Prabhakar 	return 0;
348*c087a94bSLad Prabhakar }
349*c087a94bSLad Prabhakar 
350*c087a94bSLad Prabhakar static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
351*c087a94bSLad Prabhakar 			       struct rsnd_dai_stream *io,
352*c087a94bSLad Prabhakar 			       struct rsnd_priv *priv)
353*c087a94bSLad Prabhakar {
354*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
355*c087a94bSLad Prabhakar 	int busif = rsnd_mod_id_sub(mod);
356*c087a94bSLad Prabhakar 
357*c087a94bSLad Prabhakar 	if (!rsnd_ssi_use_busif(io))
358*c087a94bSLad Prabhakar 		return 0;
359*c087a94bSLad Prabhakar 
360*c087a94bSLad Prabhakar 	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
361*c087a94bSLad Prabhakar 
362*c087a94bSLad Prabhakar 	if (--ssiu->usrcnt)
363*c087a94bSLad Prabhakar 		return 0;
364*c087a94bSLad Prabhakar 
365*c087a94bSLad Prabhakar 	if (rsnd_ssi_multi_secondaries_runtime(io))
366*c087a94bSLad Prabhakar 		rsnd_mod_write(mod, SSI_CONTROL, 0);
367*c087a94bSLad Prabhakar 
368*c087a94bSLad Prabhakar 	return 0;
369*c087a94bSLad Prabhakar }
370*c087a94bSLad Prabhakar 
371*c087a94bSLad Prabhakar static int rsnd_ssiu_id(struct rsnd_mod *mod)
372*c087a94bSLad Prabhakar {
373*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
374*c087a94bSLad Prabhakar 
375*c087a94bSLad Prabhakar 	/* see rsnd_ssiu_probe() */
376*c087a94bSLad Prabhakar 	return ssiu->id;
377*c087a94bSLad Prabhakar }
378*c087a94bSLad Prabhakar 
379*c087a94bSLad Prabhakar static int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
380*c087a94bSLad Prabhakar {
381*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
382*c087a94bSLad Prabhakar 
383*c087a94bSLad Prabhakar 	/* see rsnd_ssiu_probe() */
384*c087a94bSLad Prabhakar 	return ssiu->id_sub;
385*c087a94bSLad Prabhakar }
386*c087a94bSLad Prabhakar 
387*c087a94bSLad Prabhakar static struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
388*c087a94bSLad Prabhakar 					  struct rsnd_mod *mod)
389*c087a94bSLad Prabhakar {
390*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
391*c087a94bSLad Prabhakar 	int is_play = rsnd_io_is_play(io);
392*c087a94bSLad Prabhakar 	char *name;
393*c087a94bSLad Prabhakar 
394*c087a94bSLad Prabhakar 	/*
395*c087a94bSLad Prabhakar 	 * It should use "rcar_sound,ssiu" on DT.
396*c087a94bSLad Prabhakar 	 * But, we need to keep compatibility for old version.
397*c087a94bSLad Prabhakar 	 *
398*c087a94bSLad Prabhakar 	 * If it has "rcar_sound.ssiu", it will be used.
399*c087a94bSLad Prabhakar 	 * If not, "rcar_sound.ssi" will be used.
400*c087a94bSLad Prabhakar 	 * see
401*c087a94bSLad Prabhakar 	 *	rsnd_ssi_dma_req()
402*c087a94bSLad Prabhakar 	 *	rsnd_dma_of_path()
403*c087a94bSLad Prabhakar 	 */
404*c087a94bSLad Prabhakar 
405*c087a94bSLad Prabhakar 	name = is_play ? "rx" : "tx";
406*c087a94bSLad Prabhakar 
407*c087a94bSLad Prabhakar 	return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
408*c087a94bSLad Prabhakar 					SSIU_NAME, mod, name);
409*c087a94bSLad Prabhakar }
410*c087a94bSLad Prabhakar 
411*c087a94bSLad Prabhakar #ifdef CONFIG_DEBUG_FS
412*c087a94bSLad Prabhakar static void rsnd_ssiu_debug_info(struct seq_file *m,
413*c087a94bSLad Prabhakar 				 struct rsnd_dai_stream *io,
414*c087a94bSLad Prabhakar 				struct rsnd_mod *mod)
415*c087a94bSLad Prabhakar {
416*c087a94bSLad Prabhakar 	rsnd_debugfs_mod_reg_show(m, mod, RSND_BASE_SSIU,
417*c087a94bSLad Prabhakar 				  rsnd_mod_id(mod) * 0x80, 0x80);
418*c087a94bSLad Prabhakar }
419*c087a94bSLad Prabhakar #define DEBUG_INFO .debug_info = rsnd_ssiu_debug_info
420*c087a94bSLad Prabhakar #else
421*c087a94bSLad Prabhakar #define DEBUG_INFO
422*c087a94bSLad Prabhakar #endif
423*c087a94bSLad Prabhakar 
424*c087a94bSLad Prabhakar static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
425*c087a94bSLad Prabhakar 	.name		= SSIU_NAME,
426*c087a94bSLad Prabhakar 	.dma_req	= rsnd_ssiu_dma_req,
427*c087a94bSLad Prabhakar 	.init		= rsnd_ssiu_init_gen2,
428*c087a94bSLad Prabhakar 	.quit		= rsnd_ssiu_quit,
429*c087a94bSLad Prabhakar 	.start		= rsnd_ssiu_start_gen2,
430*c087a94bSLad Prabhakar 	.stop		= rsnd_ssiu_stop_gen2,
431*c087a94bSLad Prabhakar 	.get_status	= rsnd_ssiu_get_status,
432*c087a94bSLad Prabhakar 	DEBUG_INFO
433*c087a94bSLad Prabhakar };
434*c087a94bSLad Prabhakar 
435*c087a94bSLad Prabhakar static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
436*c087a94bSLad Prabhakar {
437*c087a94bSLad Prabhakar 	if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
438*c087a94bSLad Prabhakar 		id = 0;
439*c087a94bSLad Prabhakar 
440*c087a94bSLad Prabhakar 	return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
441*c087a94bSLad Prabhakar }
442*c087a94bSLad Prabhakar 
443*c087a94bSLad Prabhakar static void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
444*c087a94bSLad Prabhakar 					       struct rsnd_dai_stream *io)
445*c087a94bSLad Prabhakar {
446*c087a94bSLad Prabhakar 	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
447*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu;
448*c087a94bSLad Prabhakar 	int is_dma_mode;
449*c087a94bSLad Prabhakar 	int i;
450*c087a94bSLad Prabhakar 
451*c087a94bSLad Prabhakar 	if (!ssi_mod)
452*c087a94bSLad Prabhakar 		return;
453*c087a94bSLad Prabhakar 
454*c087a94bSLad Prabhakar 	is_dma_mode = rsnd_ssi_is_dma_mode(ssi_mod);
455*c087a94bSLad Prabhakar 
456*c087a94bSLad Prabhakar 	/* select BUSIF0 */
457*c087a94bSLad Prabhakar 	for_each_rsnd_ssiu(ssiu, priv, i) {
458*c087a94bSLad Prabhakar 		struct rsnd_mod *mod = rsnd_mod_get(ssiu);
459*c087a94bSLad Prabhakar 
460*c087a94bSLad Prabhakar 		if (is_dma_mode &&
461*c087a94bSLad Prabhakar 		    (rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
462*c087a94bSLad Prabhakar 		    (rsnd_mod_id_sub(mod) == 0)) {
463*c087a94bSLad Prabhakar 			rsnd_dai_connect(mod, io, mod->type);
464*c087a94bSLad Prabhakar 			return;
465*c087a94bSLad Prabhakar 		}
466*c087a94bSLad Prabhakar 	}
467*c087a94bSLad Prabhakar }
468*c087a94bSLad Prabhakar 
469*c087a94bSLad Prabhakar void rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
470*c087a94bSLad Prabhakar 			     struct device_node *playback,
471*c087a94bSLad Prabhakar 			     struct device_node *capture)
472*c087a94bSLad Prabhakar {
473*c087a94bSLad Prabhakar 	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
474*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
475*c087a94bSLad Prabhakar 	struct device_node *node = rsnd_ssiu_of_node(priv);
476*c087a94bSLad Prabhakar 	struct rsnd_dai_stream *io_p = &rdai->playback;
477*c087a94bSLad Prabhakar 	struct rsnd_dai_stream *io_c = &rdai->capture;
478*c087a94bSLad Prabhakar 
479*c087a94bSLad Prabhakar 	/* use rcar_sound,ssiu if exist */
480*c087a94bSLad Prabhakar 	if (node) {
481*c087a94bSLad Prabhakar 		struct device_node *np;
482*c087a94bSLad Prabhakar 		int i = 0;
483*c087a94bSLad Prabhakar 
484*c087a94bSLad Prabhakar 		for_each_child_of_node(node, np) {
485*c087a94bSLad Prabhakar 			struct rsnd_mod *mod;
486*c087a94bSLad Prabhakar 
487*c087a94bSLad Prabhakar 			i = rsnd_node_fixed_index(dev, np, SSIU_NAME, i);
488*c087a94bSLad Prabhakar 			if (i < 0) {
489*c087a94bSLad Prabhakar 				of_node_put(np);
490*c087a94bSLad Prabhakar 				break;
491*c087a94bSLad Prabhakar 			}
492*c087a94bSLad Prabhakar 
493*c087a94bSLad Prabhakar 			mod = rsnd_ssiu_mod_get(priv, i);
494*c087a94bSLad Prabhakar 
495*c087a94bSLad Prabhakar 			if (np == playback)
496*c087a94bSLad Prabhakar 				rsnd_dai_connect(mod, io_p, mod->type);
497*c087a94bSLad Prabhakar 			if (np == capture)
498*c087a94bSLad Prabhakar 				rsnd_dai_connect(mod, io_c, mod->type);
499*c087a94bSLad Prabhakar 			i++;
500*c087a94bSLad Prabhakar 		}
501*c087a94bSLad Prabhakar 
502*c087a94bSLad Prabhakar 		of_node_put(node);
503*c087a94bSLad Prabhakar 	}
504*c087a94bSLad Prabhakar 
505*c087a94bSLad Prabhakar 	/* Keep DT compatibility */
506*c087a94bSLad Prabhakar 	if (!rsnd_io_to_mod_ssiu(io_p))
507*c087a94bSLad Prabhakar 		rsnd_parse_connect_ssiu_compatible(priv, io_p);
508*c087a94bSLad Prabhakar 	if (!rsnd_io_to_mod_ssiu(io_c))
509*c087a94bSLad Prabhakar 		rsnd_parse_connect_ssiu_compatible(priv, io_c);
510*c087a94bSLad Prabhakar }
511*c087a94bSLad Prabhakar 
512*c087a94bSLad Prabhakar int rsnd_ssiu_probe(struct rsnd_priv *priv)
513*c087a94bSLad Prabhakar {
514*c087a94bSLad Prabhakar 	struct device *dev = rsnd_priv_to_dev(priv);
515*c087a94bSLad Prabhakar 	struct device_node *node;
516*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu;
517*c087a94bSLad Prabhakar 	struct rsnd_mod_ops *ops;
518*c087a94bSLad Prabhakar 	const int *list = NULL;
519*c087a94bSLad Prabhakar 	int i, nr;
520*c087a94bSLad Prabhakar 
521*c087a94bSLad Prabhakar 	/*
522*c087a94bSLad Prabhakar 	 * Keep DT compatibility.
523*c087a94bSLad Prabhakar 	 * if it has "rcar_sound,ssiu", use it.
524*c087a94bSLad Prabhakar 	 * if not, use "rcar_sound,ssi"
525*c087a94bSLad Prabhakar 	 * see
526*c087a94bSLad Prabhakar 	 *	rsnd_ssiu_bufsif_to_id()
527*c087a94bSLad Prabhakar 	 */
528*c087a94bSLad Prabhakar 	node = rsnd_ssiu_of_node(priv);
529*c087a94bSLad Prabhakar 	if (node)
530*c087a94bSLad Prabhakar 		nr = rsnd_node_count(priv, node, SSIU_NAME);
531*c087a94bSLad Prabhakar 	else
532*c087a94bSLad Prabhakar 		nr = priv->ssi_nr;
533*c087a94bSLad Prabhakar 
534*c087a94bSLad Prabhakar 	if (!nr)
535*c087a94bSLad Prabhakar 		return -EINVAL;
536*c087a94bSLad Prabhakar 
537*c087a94bSLad Prabhakar 	ssiu	= devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
538*c087a94bSLad Prabhakar 	if (!ssiu)
539*c087a94bSLad Prabhakar 		return -ENOMEM;
540*c087a94bSLad Prabhakar 
541*c087a94bSLad Prabhakar 	priv->ssiu	= ssiu;
542*c087a94bSLad Prabhakar 	priv->ssiu_nr	= nr;
543*c087a94bSLad Prabhakar 
544*c087a94bSLad Prabhakar 	if (rsnd_is_gen1(priv))
545*c087a94bSLad Prabhakar 		ops = &rsnd_ssiu_ops_gen1;
546*c087a94bSLad Prabhakar 	else
547*c087a94bSLad Prabhakar 		ops = &rsnd_ssiu_ops_gen2;
548*c087a94bSLad Prabhakar 
549*c087a94bSLad Prabhakar 	/* Keep compatibility */
550*c087a94bSLad Prabhakar 	nr = 0;
551*c087a94bSLad Prabhakar 	if ((node) &&
552*c087a94bSLad Prabhakar 	    (ops == &rsnd_ssiu_ops_gen2)) {
553*c087a94bSLad Prabhakar 		ops->id		= rsnd_ssiu_id;
554*c087a94bSLad Prabhakar 		ops->id_sub	= rsnd_ssiu_id_sub;
555*c087a94bSLad Prabhakar 
556*c087a94bSLad Prabhakar 		if (rsnd_is_gen2(priv)) {
557*c087a94bSLad Prabhakar 			list	= gen2_id;
558*c087a94bSLad Prabhakar 			nr	= ARRAY_SIZE(gen2_id);
559*c087a94bSLad Prabhakar 		} else if (rsnd_is_gen3(priv)) {
560*c087a94bSLad Prabhakar 			list	= gen3_id;
561*c087a94bSLad Prabhakar 			nr	= ARRAY_SIZE(gen3_id);
562*c087a94bSLad Prabhakar 		} else if (rsnd_is_gen4(priv)) {
563*c087a94bSLad Prabhakar 			list	= gen4_id;
564*c087a94bSLad Prabhakar 			nr	= ARRAY_SIZE(gen4_id);
565*c087a94bSLad Prabhakar 		} else {
566*c087a94bSLad Prabhakar 			dev_err(dev, "unknown SSIU\n");
567*c087a94bSLad Prabhakar 			return -ENODEV;
568*c087a94bSLad Prabhakar 		}
569*c087a94bSLad Prabhakar 	}
570*c087a94bSLad Prabhakar 
571*c087a94bSLad Prabhakar 	for_each_rsnd_ssiu(ssiu, priv, i) {
572*c087a94bSLad Prabhakar 		int ret;
573*c087a94bSLad Prabhakar 
574*c087a94bSLad Prabhakar 		if (node) {
575*c087a94bSLad Prabhakar 			int j;
576*c087a94bSLad Prabhakar 
577*c087a94bSLad Prabhakar 			/*
578*c087a94bSLad Prabhakar 			 * see
579*c087a94bSLad Prabhakar 			 *	rsnd_ssiu_get_id()
580*c087a94bSLad Prabhakar 			 *	rsnd_ssiu_get_id_sub()
581*c087a94bSLad Prabhakar 			 */
582*c087a94bSLad Prabhakar 			for (j = 0; j < nr; j++) {
583*c087a94bSLad Prabhakar 				if (list[j] > i)
584*c087a94bSLad Prabhakar 					break;
585*c087a94bSLad Prabhakar 				ssiu->id	= j;
586*c087a94bSLad Prabhakar 				ssiu->id_sub	= i - list[ssiu->id];
587*c087a94bSLad Prabhakar 			}
588*c087a94bSLad Prabhakar 		} else {
589*c087a94bSLad Prabhakar 			ssiu->id = i;
590*c087a94bSLad Prabhakar 		}
591*c087a94bSLad Prabhakar 
592*c087a94bSLad Prabhakar 		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
593*c087a94bSLad Prabhakar 				    ops, NULL, RSND_MOD_SSIU, i);
594*c087a94bSLad Prabhakar 		if (ret)
595*c087a94bSLad Prabhakar 			return ret;
596*c087a94bSLad Prabhakar 	}
597*c087a94bSLad Prabhakar 
598*c087a94bSLad Prabhakar 	return 0;
599*c087a94bSLad Prabhakar }
600*c087a94bSLad Prabhakar 
601*c087a94bSLad Prabhakar void rsnd_ssiu_remove(struct rsnd_priv *priv)
602*c087a94bSLad Prabhakar {
603*c087a94bSLad Prabhakar 	struct rsnd_ssiu *ssiu;
604*c087a94bSLad Prabhakar 	int i;
605*c087a94bSLad Prabhakar 
606*c087a94bSLad Prabhakar 	for_each_rsnd_ssiu(ssiu, priv, i) {
607*c087a94bSLad Prabhakar 		rsnd_mod_quit(rsnd_mod_get(ssiu));
608*c087a94bSLad Prabhakar 	}
609*c087a94bSLad Prabhakar }
610