xref: /kernel/linux/linux-5.10/sound/soc/sh/rcar/ssiu.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Renesas R-Car SSIU support
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "rsnd.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define SSIU_NAME "ssiu"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistruct rsnd_ssiu {
128c2ecf20Sopenharmony_ci	struct rsnd_mod mod;
138c2ecf20Sopenharmony_ci	u32 busif_status[8]; /* for BUSIF0 - BUSIF7 */
148c2ecf20Sopenharmony_ci	unsigned int usrcnt;
158c2ecf20Sopenharmony_ci	int id;
168c2ecf20Sopenharmony_ci	int id_sub;
178c2ecf20Sopenharmony_ci};
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* SSI_MODE */
208c2ecf20Sopenharmony_ci#define TDM_EXT		(1 << 0)
218c2ecf20Sopenharmony_ci#define TDM_SPLIT	(1 << 8)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr)
248c2ecf20Sopenharmony_ci#define rsnd_mod_to_ssiu(_mod) container_of((_mod), struct rsnd_ssiu, mod)
258c2ecf20Sopenharmony_ci#define for_each_rsnd_ssiu(pos, priv, i)				\
268c2ecf20Sopenharmony_ci	for (i = 0;							\
278c2ecf20Sopenharmony_ci	     (i < rsnd_ssiu_nr(priv)) &&				\
288c2ecf20Sopenharmony_ci		     ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i));	\
298c2ecf20Sopenharmony_ci	     i++)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/*
328c2ecf20Sopenharmony_ci *	SSI	Gen2		Gen3
338c2ecf20Sopenharmony_ci *	0	BUSIF0-3	BUSIF0-7
348c2ecf20Sopenharmony_ci *	1	BUSIF0-3	BUSIF0-7
358c2ecf20Sopenharmony_ci *	2	BUSIF0-3	BUSIF0-7
368c2ecf20Sopenharmony_ci *	3	BUSIF0		BUSIF0-7
378c2ecf20Sopenharmony_ci *	4	BUSIF0		BUSIF0-7
388c2ecf20Sopenharmony_ci *	5	BUSIF0		BUSIF0
398c2ecf20Sopenharmony_ci *	6	BUSIF0		BUSIF0
408c2ecf20Sopenharmony_ci *	7	BUSIF0		BUSIF0
418c2ecf20Sopenharmony_ci *	8	BUSIF0		BUSIF0
428c2ecf20Sopenharmony_ci *	9	BUSIF0-3	BUSIF0-7
438c2ecf20Sopenharmony_ci *	total	22		52
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistatic const int gen2_id[] = { 0, 4,  8, 12, 13, 14, 15, 16, 17, 18 };
468c2ecf20Sopenharmony_cistatic const int gen3_id[] = { 0, 8, 16, 24, 32, 40, 41, 42, 43, 44 };
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic u32 *rsnd_ssiu_get_status(struct rsnd_mod *mod,
498c2ecf20Sopenharmony_ci				 struct rsnd_dai_stream *io,
508c2ecf20Sopenharmony_ci				 enum rsnd_mod_type type)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
538c2ecf20Sopenharmony_ci	int busif = rsnd_mod_id_sub(mod);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return &ssiu->busif_status[busif];
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic int rsnd_ssiu_init(struct rsnd_mod *mod,
598c2ecf20Sopenharmony_ci			  struct rsnd_dai_stream *io,
608c2ecf20Sopenharmony_ci			  struct rsnd_priv *priv)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
638c2ecf20Sopenharmony_ci	u32 ssis = rsnd_ssi_multi_secondaries_runtime(io);
648c2ecf20Sopenharmony_ci	int use_busif = rsnd_ssi_use_busif(io);
658c2ecf20Sopenharmony_ci	int id = rsnd_mod_id(mod);
668c2ecf20Sopenharmony_ci	int is_clk_master = rsnd_rdai_is_clk_master(rdai);
678c2ecf20Sopenharmony_ci	u32 val1, val2;
688c2ecf20Sopenharmony_ci	int i;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	/* clear status */
718c2ecf20Sopenharmony_ci	switch (id) {
728c2ecf20Sopenharmony_ci	case 0:
738c2ecf20Sopenharmony_ci	case 1:
748c2ecf20Sopenharmony_ci	case 2:
758c2ecf20Sopenharmony_ci	case 3:
768c2ecf20Sopenharmony_ci	case 4:
778c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
788c2ecf20Sopenharmony_ci			rsnd_mod_write(mod, SSI_SYS_STATUS(i * 2), 0xf << (id * 4));
798c2ecf20Sopenharmony_ci		break;
808c2ecf20Sopenharmony_ci	case 9:
818c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
828c2ecf20Sopenharmony_ci			rsnd_mod_write(mod, SSI_SYS_STATUS((i * 2) + 1), 0xf << 4);
838c2ecf20Sopenharmony_ci		break;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/*
878c2ecf20Sopenharmony_ci	 * SSI_MODE0
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/*
928c2ecf20Sopenharmony_ci	 * SSI_MODE1 / SSI_MODE2
938c2ecf20Sopenharmony_ci	 *
948c2ecf20Sopenharmony_ci	 * FIXME
958c2ecf20Sopenharmony_ci	 * sharing/multi with SSI0 are mainly supported
968c2ecf20Sopenharmony_ci	 */
978c2ecf20Sopenharmony_ci	val1 = rsnd_mod_read(mod, SSI_MODE1);
988c2ecf20Sopenharmony_ci	val2 = rsnd_mod_read(mod, SSI_MODE2);
998c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_pin_sharing(io)) {
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		ssis |= (1 << id);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	} else if (ssis) {
1048c2ecf20Sopenharmony_ci		/*
1058c2ecf20Sopenharmony_ci		 * Multi SSI
1068c2ecf20Sopenharmony_ci		 *
1078c2ecf20Sopenharmony_ci		 * set synchronized bit here
1088c2ecf20Sopenharmony_ci		 */
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		/* SSI4 is synchronized with SSI3 */
1118c2ecf20Sopenharmony_ci		if (ssis & (1 << 4))
1128c2ecf20Sopenharmony_ci			val1 |= (1 << 20);
1138c2ecf20Sopenharmony_ci		/* SSI012 are synchronized */
1148c2ecf20Sopenharmony_ci		if (ssis == 0x0006)
1158c2ecf20Sopenharmony_ci			val1 |= (1 << 4);
1168c2ecf20Sopenharmony_ci		/* SSI0129 are synchronized */
1178c2ecf20Sopenharmony_ci		if (ssis == 0x0206)
1188c2ecf20Sopenharmony_ci			val2 |= (1 << 4);
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/* SSI1 is sharing pin with SSI0 */
1228c2ecf20Sopenharmony_ci	if (ssis & (1 << 1))
1238c2ecf20Sopenharmony_ci		val1 |= is_clk_master ? 0x2 : 0x1;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	/* SSI2 is sharing pin with SSI0 */
1268c2ecf20Sopenharmony_ci	if (ssis & (1 << 2))
1278c2ecf20Sopenharmony_ci		val1 |= is_clk_master ?	0x2 << 2 :
1288c2ecf20Sopenharmony_ci					0x1 << 2;
1298c2ecf20Sopenharmony_ci	/* SSI4 is sharing pin with SSI3 */
1308c2ecf20Sopenharmony_ci	if (ssis & (1 << 4))
1318c2ecf20Sopenharmony_ci		val1 |= is_clk_master ? 0x2 << 16 :
1328c2ecf20Sopenharmony_ci					0x1 << 16;
1338c2ecf20Sopenharmony_ci	/* SSI9 is sharing pin with SSI0 */
1348c2ecf20Sopenharmony_ci	if (ssis & (1 << 9))
1358c2ecf20Sopenharmony_ci		val2 |= is_clk_master ? 0x2 : 0x1;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	rsnd_mod_bset(mod, SSI_MODE1, 0x0013001f, val1);
1388c2ecf20Sopenharmony_ci	rsnd_mod_bset(mod, SSI_MODE2, 0x00000017, val2);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return 0;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = {
1448c2ecf20Sopenharmony_ci	.name		= SSIU_NAME,
1458c2ecf20Sopenharmony_ci	.init		= rsnd_ssiu_init,
1468c2ecf20Sopenharmony_ci	.get_status	= rsnd_ssiu_get_status,
1478c2ecf20Sopenharmony_ci};
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int rsnd_ssiu_init_gen2(struct rsnd_mod *mod,
1508c2ecf20Sopenharmony_ci			       struct rsnd_dai_stream *io,
1518c2ecf20Sopenharmony_ci			       struct rsnd_priv *priv)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
1548c2ecf20Sopenharmony_ci	u32 has_hdmi0 = rsnd_flags_has(io, RSND_STREAM_HDMI0);
1558c2ecf20Sopenharmony_ci	u32 has_hdmi1 = rsnd_flags_has(io, RSND_STREAM_HDMI1);
1568c2ecf20Sopenharmony_ci	int ret;
1578c2ecf20Sopenharmony_ci	u32 mode = 0;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	ret = rsnd_ssiu_init(mod, io, priv);
1608c2ecf20Sopenharmony_ci	if (ret < 0)
1618c2ecf20Sopenharmony_ci		return ret;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	ssiu->usrcnt++;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/*
1668c2ecf20Sopenharmony_ci	 * TDM Extend/Split Mode
1678c2ecf20Sopenharmony_ci	 * see
1688c2ecf20Sopenharmony_ci	 *	rsnd_ssi_config_init()
1698c2ecf20Sopenharmony_ci	 */
1708c2ecf20Sopenharmony_ci	if (rsnd_runtime_is_tdm(io))
1718c2ecf20Sopenharmony_ci		mode = TDM_EXT;
1728c2ecf20Sopenharmony_ci	else if (rsnd_runtime_is_tdm_split(io))
1738c2ecf20Sopenharmony_ci		mode = TDM_SPLIT;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSI_MODE, mode);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	if (rsnd_ssi_use_busif(io)) {
1788c2ecf20Sopenharmony_ci		int id = rsnd_mod_id(mod);
1798c2ecf20Sopenharmony_ci		int busif = rsnd_mod_id_sub(mod);
1808c2ecf20Sopenharmony_ci		enum rsnd_reg adinr_reg, mode_reg, dalign_reg;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		if ((id == 9) && (busif >= 4)) {
1838c2ecf20Sopenharmony_ci			adinr_reg = SSI9_BUSIF_ADINR(busif);
1848c2ecf20Sopenharmony_ci			mode_reg = SSI9_BUSIF_MODE(busif);
1858c2ecf20Sopenharmony_ci			dalign_reg = SSI9_BUSIF_DALIGN(busif);
1868c2ecf20Sopenharmony_ci		} else {
1878c2ecf20Sopenharmony_ci			adinr_reg = SSI_BUSIF_ADINR(busif);
1888c2ecf20Sopenharmony_ci			mode_reg = SSI_BUSIF_MODE(busif);
1898c2ecf20Sopenharmony_ci			dalign_reg = SSI_BUSIF_DALIGN(busif);
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, adinr_reg,
1938c2ecf20Sopenharmony_ci			       rsnd_get_adinr_bit(mod, io) |
1948c2ecf20Sopenharmony_ci			       (rsnd_io_is_play(io) ?
1958c2ecf20Sopenharmony_ci				rsnd_runtime_channel_after_ctu(io) :
1968c2ecf20Sopenharmony_ci				rsnd_runtime_channel_original(io)));
1978c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, mode_reg,
1988c2ecf20Sopenharmony_ci			       rsnd_get_busif_shift(io, mod) | 1);
1998c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, dalign_reg,
2008c2ecf20Sopenharmony_ci			       rsnd_get_dalign(mod, io));
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (has_hdmi0 || has_hdmi1) {
2048c2ecf20Sopenharmony_ci		enum rsnd_mod_type rsnd_ssi_array[] = {
2058c2ecf20Sopenharmony_ci			RSND_MOD_SSIM1,
2068c2ecf20Sopenharmony_ci			RSND_MOD_SSIM2,
2078c2ecf20Sopenharmony_ci			RSND_MOD_SSIM3,
2088c2ecf20Sopenharmony_ci		};
2098c2ecf20Sopenharmony_ci		struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
2108c2ecf20Sopenharmony_ci		struct rsnd_mod *pos;
2118c2ecf20Sopenharmony_ci		u32 val;
2128c2ecf20Sopenharmony_ci		int i, shift;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci		i = rsnd_mod_id(ssi_mod);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci		/* output all same SSI as default */
2178c2ecf20Sopenharmony_ci		val =	i << 16 |
2188c2ecf20Sopenharmony_ci			i << 20 |
2198c2ecf20Sopenharmony_ci			i << 24 |
2208c2ecf20Sopenharmony_ci			i << 28 |
2218c2ecf20Sopenharmony_ci			i;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci		for_each_rsnd_mod_array(i, pos, io, rsnd_ssi_array) {
2248c2ecf20Sopenharmony_ci			shift	= (i * 4) + 20;
2258c2ecf20Sopenharmony_ci			val	= (val & ~(0xF << shift)) |
2268c2ecf20Sopenharmony_ci				rsnd_mod_id(pos) << shift;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		if (has_hdmi0)
2308c2ecf20Sopenharmony_ci			rsnd_mod_write(mod, HDMI0_SEL, val);
2318c2ecf20Sopenharmony_ci		if (has_hdmi1)
2328c2ecf20Sopenharmony_ci			rsnd_mod_write(mod, HDMI1_SEL, val);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return 0;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int rsnd_ssiu_start_gen2(struct rsnd_mod *mod,
2398c2ecf20Sopenharmony_ci				struct rsnd_dai_stream *io,
2408c2ecf20Sopenharmony_ci				struct rsnd_priv *priv)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	int busif = rsnd_mod_id_sub(mod);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (!rsnd_ssi_use_busif(io))
2458c2ecf20Sopenharmony_ci		return 0;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 1 << (busif * 4));
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (rsnd_ssi_multi_secondaries_runtime(io))
2508c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, SSI_CONTROL, 0x1);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod,
2568c2ecf20Sopenharmony_ci			       struct rsnd_dai_stream *io,
2578c2ecf20Sopenharmony_ci			       struct rsnd_priv *priv)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
2608c2ecf20Sopenharmony_ci	int busif = rsnd_mod_id_sub(mod);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (!rsnd_ssi_use_busif(io))
2638c2ecf20Sopenharmony_ci		return 0;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	rsnd_mod_bset(mod, SSI_CTRL, 1 << (busif * 4), 0);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (--ssiu->usrcnt)
2688c2ecf20Sopenharmony_ci		return 0;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (rsnd_ssi_multi_secondaries_runtime(io))
2718c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, SSI_CONTROL, 0);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int rsnd_ssiu_id(struct rsnd_mod *mod)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	/* see rsnd_ssiu_probe() */
2818c2ecf20Sopenharmony_ci	return ssiu->id;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int rsnd_ssiu_id_sub(struct rsnd_mod *mod)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu = rsnd_mod_to_ssiu(mod);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	/* see rsnd_ssiu_probe() */
2898c2ecf20Sopenharmony_ci	return ssiu->id_sub;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic struct dma_chan *rsnd_ssiu_dma_req(struct rsnd_dai_stream *io,
2938c2ecf20Sopenharmony_ci					  struct rsnd_mod *mod)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
2968c2ecf20Sopenharmony_ci	int is_play = rsnd_io_is_play(io);
2978c2ecf20Sopenharmony_ci	char *name;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/*
3008c2ecf20Sopenharmony_ci	 * It should use "rcar_sound,ssiu" on DT.
3018c2ecf20Sopenharmony_ci	 * But, we need to keep compatibility for old version.
3028c2ecf20Sopenharmony_ci	 *
3038c2ecf20Sopenharmony_ci	 * If it has "rcar_sound.ssiu", it will be used.
3048c2ecf20Sopenharmony_ci	 * If not, "rcar_sound.ssi" will be used.
3058c2ecf20Sopenharmony_ci	 * see
3068c2ecf20Sopenharmony_ci	 *	rsnd_ssi_dma_req()
3078c2ecf20Sopenharmony_ci	 *	rsnd_dma_of_path()
3088c2ecf20Sopenharmony_ci	 */
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	name = is_play ? "rx" : "tx";
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return rsnd_dma_request_channel(rsnd_ssiu_of_node(priv),
3138c2ecf20Sopenharmony_ci					mod, name);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = {
3178c2ecf20Sopenharmony_ci	.name		= SSIU_NAME,
3188c2ecf20Sopenharmony_ci	.dma_req	= rsnd_ssiu_dma_req,
3198c2ecf20Sopenharmony_ci	.init		= rsnd_ssiu_init_gen2,
3208c2ecf20Sopenharmony_ci	.start		= rsnd_ssiu_start_gen2,
3218c2ecf20Sopenharmony_ci	.stop		= rsnd_ssiu_stop_gen2,
3228c2ecf20Sopenharmony_ci	.get_status	= rsnd_ssiu_get_status,
3238c2ecf20Sopenharmony_ci};
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv)))
3288c2ecf20Sopenharmony_ci		id = 0;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id);
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic void rsnd_parse_connect_ssiu_compatible(struct rsnd_priv *priv,
3348c2ecf20Sopenharmony_ci					       struct rsnd_dai_stream *io)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
3378c2ecf20Sopenharmony_ci	struct rsnd_mod *mod;
3388c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu;
3398c2ecf20Sopenharmony_ci	int i;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	if (!ssi_mod)
3428c2ecf20Sopenharmony_ci		return;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* select BUSIF0 */
3458c2ecf20Sopenharmony_ci	for_each_rsnd_ssiu(ssiu, priv, i) {
3468c2ecf20Sopenharmony_ci		mod = rsnd_mod_get(ssiu);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci		if ((rsnd_mod_id(ssi_mod) == rsnd_mod_id(mod)) &&
3498c2ecf20Sopenharmony_ci		    (rsnd_mod_id_sub(mod) == 0)) {
3508c2ecf20Sopenharmony_ci			rsnd_dai_connect(mod, io, mod->type);
3518c2ecf20Sopenharmony_ci			return;
3528c2ecf20Sopenharmony_ci		}
3538c2ecf20Sopenharmony_ci	}
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_civoid rsnd_parse_connect_ssiu(struct rsnd_dai *rdai,
3578c2ecf20Sopenharmony_ci			     struct device_node *playback,
3588c2ecf20Sopenharmony_ci			     struct device_node *capture)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
3618c2ecf20Sopenharmony_ci	struct device_node *node = rsnd_ssiu_of_node(priv);
3628c2ecf20Sopenharmony_ci	struct device_node *np;
3638c2ecf20Sopenharmony_ci	struct rsnd_mod *mod;
3648c2ecf20Sopenharmony_ci	struct rsnd_dai_stream *io_p = &rdai->playback;
3658c2ecf20Sopenharmony_ci	struct rsnd_dai_stream *io_c = &rdai->capture;
3668c2ecf20Sopenharmony_ci	int i;
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	/* use rcar_sound,ssiu if exist */
3698c2ecf20Sopenharmony_ci	if (node) {
3708c2ecf20Sopenharmony_ci		i = 0;
3718c2ecf20Sopenharmony_ci		for_each_child_of_node(node, np) {
3728c2ecf20Sopenharmony_ci			mod = rsnd_ssiu_mod_get(priv, i);
3738c2ecf20Sopenharmony_ci			if (np == playback)
3748c2ecf20Sopenharmony_ci				rsnd_dai_connect(mod, io_p, mod->type);
3758c2ecf20Sopenharmony_ci			if (np == capture)
3768c2ecf20Sopenharmony_ci				rsnd_dai_connect(mod, io_c, mod->type);
3778c2ecf20Sopenharmony_ci			i++;
3788c2ecf20Sopenharmony_ci		}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		of_node_put(node);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	/* Keep DT compatibility */
3848c2ecf20Sopenharmony_ci	if (!rsnd_io_to_mod_ssiu(io_p))
3858c2ecf20Sopenharmony_ci		rsnd_parse_connect_ssiu_compatible(priv, io_p);
3868c2ecf20Sopenharmony_ci	if (!rsnd_io_to_mod_ssiu(io_c))
3878c2ecf20Sopenharmony_ci		rsnd_parse_connect_ssiu_compatible(priv, io_c);
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ciint rsnd_ssiu_probe(struct rsnd_priv *priv)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
3938c2ecf20Sopenharmony_ci	struct device_node *node;
3948c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu;
3958c2ecf20Sopenharmony_ci	struct rsnd_mod_ops *ops;
3968c2ecf20Sopenharmony_ci	const int *list = NULL;
3978c2ecf20Sopenharmony_ci	int i, nr, ret;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	/*
4008c2ecf20Sopenharmony_ci	 * Keep DT compatibility.
4018c2ecf20Sopenharmony_ci	 * if it has "rcar_sound,ssiu", use it.
4028c2ecf20Sopenharmony_ci	 * if not, use "rcar_sound,ssi"
4038c2ecf20Sopenharmony_ci	 * see
4048c2ecf20Sopenharmony_ci	 *	rsnd_ssiu_bufsif_to_id()
4058c2ecf20Sopenharmony_ci	 */
4068c2ecf20Sopenharmony_ci	node = rsnd_ssiu_of_node(priv);
4078c2ecf20Sopenharmony_ci	if (node)
4088c2ecf20Sopenharmony_ci		nr = of_get_child_count(node);
4098c2ecf20Sopenharmony_ci	else
4108c2ecf20Sopenharmony_ci		nr = priv->ssi_nr;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ssiu	= devm_kcalloc(dev, nr, sizeof(*ssiu), GFP_KERNEL);
4138c2ecf20Sopenharmony_ci	if (!ssiu)
4148c2ecf20Sopenharmony_ci		return -ENOMEM;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	priv->ssiu	= ssiu;
4178c2ecf20Sopenharmony_ci	priv->ssiu_nr	= nr;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	if (rsnd_is_gen1(priv))
4208c2ecf20Sopenharmony_ci		ops = &rsnd_ssiu_ops_gen1;
4218c2ecf20Sopenharmony_ci	else
4228c2ecf20Sopenharmony_ci		ops = &rsnd_ssiu_ops_gen2;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Keep compatibility */
4258c2ecf20Sopenharmony_ci	nr = 0;
4268c2ecf20Sopenharmony_ci	if ((node) &&
4278c2ecf20Sopenharmony_ci	    (ops == &rsnd_ssiu_ops_gen2)) {
4288c2ecf20Sopenharmony_ci		ops->id		= rsnd_ssiu_id;
4298c2ecf20Sopenharmony_ci		ops->id_sub	= rsnd_ssiu_id_sub;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		if (rsnd_is_gen2(priv)) {
4328c2ecf20Sopenharmony_ci			list	= gen2_id;
4338c2ecf20Sopenharmony_ci			nr	= ARRAY_SIZE(gen2_id);
4348c2ecf20Sopenharmony_ci		} else if (rsnd_is_gen3(priv)) {
4358c2ecf20Sopenharmony_ci			list	= gen3_id;
4368c2ecf20Sopenharmony_ci			nr	= ARRAY_SIZE(gen3_id);
4378c2ecf20Sopenharmony_ci		} else {
4388c2ecf20Sopenharmony_ci			dev_err(dev, "unknown SSIU\n");
4398c2ecf20Sopenharmony_ci			return -ENODEV;
4408c2ecf20Sopenharmony_ci		}
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	for_each_rsnd_ssiu(ssiu, priv, i) {
4448c2ecf20Sopenharmony_ci		if (node) {
4458c2ecf20Sopenharmony_ci			int j;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci			/*
4488c2ecf20Sopenharmony_ci			 * see
4498c2ecf20Sopenharmony_ci			 *	rsnd_ssiu_get_id()
4508c2ecf20Sopenharmony_ci			 *	rsnd_ssiu_get_id_sub()
4518c2ecf20Sopenharmony_ci			 */
4528c2ecf20Sopenharmony_ci			for (j = 0; j < nr; j++) {
4538c2ecf20Sopenharmony_ci				if (list[j] > i)
4548c2ecf20Sopenharmony_ci					break;
4558c2ecf20Sopenharmony_ci				ssiu->id	= j;
4568c2ecf20Sopenharmony_ci				ssiu->id_sub	= i - list[ssiu->id];
4578c2ecf20Sopenharmony_ci			}
4588c2ecf20Sopenharmony_ci		} else {
4598c2ecf20Sopenharmony_ci			ssiu->id = i;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu),
4638c2ecf20Sopenharmony_ci				    ops, NULL, RSND_MOD_SSIU, i);
4648c2ecf20Sopenharmony_ci		if (ret)
4658c2ecf20Sopenharmony_ci			return ret;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return 0;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_civoid rsnd_ssiu_remove(struct rsnd_priv *priv)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct rsnd_ssiu *ssiu;
4748c2ecf20Sopenharmony_ci	int i;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	for_each_rsnd_ssiu(ssiu, priv, i) {
4778c2ecf20Sopenharmony_ci		rsnd_mod_quit(rsnd_mod_get(ssiu));
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci}
480