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