xref: /kernel/linux/linux-5.10/sound/soc/sh/rcar/ssi.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Renesas R-Car SSIU/SSI support
48c2ecf20Sopenharmony_ci//
58c2ecf20Sopenharmony_ci// Copyright (C) 2013 Renesas Solutions Corp.
68c2ecf20Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci// Based on fsi.c
98c2ecf20Sopenharmony_ci// Kuninori Morimoto <morimoto.kuninori@renesas.com>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * you can enable below define if you don't need
138c2ecf20Sopenharmony_ci * SSI interrupt status debug message when debugging
148c2ecf20Sopenharmony_ci * see rsnd_dbg_irq_status()
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * #define RSND_DEBUG_NO_IRQ_STATUS 1
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <sound/simple_card_utils.h>
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include "rsnd.h"
228c2ecf20Sopenharmony_ci#define RSND_SSI_NAME_SIZE 16
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * SSICR
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_ci#define	FORCE		(1 << 31)	/* Fixed */
288c2ecf20Sopenharmony_ci#define	DMEN		(1 << 28)	/* DMA Enable */
298c2ecf20Sopenharmony_ci#define	UIEN		(1 << 27)	/* Underflow Interrupt Enable */
308c2ecf20Sopenharmony_ci#define	OIEN		(1 << 26)	/* Overflow Interrupt Enable */
318c2ecf20Sopenharmony_ci#define	IIEN		(1 << 25)	/* Idle Mode Interrupt Enable */
328c2ecf20Sopenharmony_ci#define	DIEN		(1 << 24)	/* Data Interrupt Enable */
338c2ecf20Sopenharmony_ci#define	CHNL_4		(1 << 22)	/* Channels */
348c2ecf20Sopenharmony_ci#define	CHNL_6		(2 << 22)	/* Channels */
358c2ecf20Sopenharmony_ci#define	CHNL_8		(3 << 22)	/* Channels */
368c2ecf20Sopenharmony_ci#define DWL_MASK	(7 << 19)	/* Data Word Length mask */
378c2ecf20Sopenharmony_ci#define	DWL_8		(0 << 19)	/* Data Word Length */
388c2ecf20Sopenharmony_ci#define	DWL_16		(1 << 19)	/* Data Word Length */
398c2ecf20Sopenharmony_ci#define	DWL_18		(2 << 19)	/* Data Word Length */
408c2ecf20Sopenharmony_ci#define	DWL_20		(3 << 19)	/* Data Word Length */
418c2ecf20Sopenharmony_ci#define	DWL_22		(4 << 19)	/* Data Word Length */
428c2ecf20Sopenharmony_ci#define	DWL_24		(5 << 19)	/* Data Word Length */
438c2ecf20Sopenharmony_ci#define	DWL_32		(6 << 19)	/* Data Word Length */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * System word length
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci#define	SWL_16		(1 << 16)	/* R/W System Word Length */
498c2ecf20Sopenharmony_ci#define	SWL_24		(2 << 16)	/* R/W System Word Length */
508c2ecf20Sopenharmony_ci#define	SWL_32		(3 << 16)	/* R/W System Word Length */
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define	SCKD		(1 << 15)	/* Serial Bit Clock Direction */
538c2ecf20Sopenharmony_ci#define	SWSD		(1 << 14)	/* Serial WS Direction */
548c2ecf20Sopenharmony_ci#define	SCKP		(1 << 13)	/* Serial Bit Clock Polarity */
558c2ecf20Sopenharmony_ci#define	SWSP		(1 << 12)	/* Serial WS Polarity */
568c2ecf20Sopenharmony_ci#define	SDTA		(1 << 10)	/* Serial Data Alignment */
578c2ecf20Sopenharmony_ci#define	PDTA		(1 <<  9)	/* Parallel Data Alignment */
588c2ecf20Sopenharmony_ci#define	DEL		(1 <<  8)	/* Serial Data Delay */
598c2ecf20Sopenharmony_ci#define	CKDV(v)		(v <<  4)	/* Serial Clock Division Ratio */
608c2ecf20Sopenharmony_ci#define	TRMD		(1 <<  1)	/* Transmit/Receive Mode Select */
618c2ecf20Sopenharmony_ci#define	EN		(1 <<  0)	/* SSI Module Enable */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci * SSISR
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_ci#define	UIRQ		(1 << 27)	/* Underflow Error Interrupt Status */
678c2ecf20Sopenharmony_ci#define	OIRQ		(1 << 26)	/* Overflow Error Interrupt Status */
688c2ecf20Sopenharmony_ci#define	IIRQ		(1 << 25)	/* Idle Mode Interrupt Status */
698c2ecf20Sopenharmony_ci#define	DIRQ		(1 << 24)	/* Data Interrupt Status Flag */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * SSIWSR
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_ci#define CONT		(1 << 8)	/* WS Continue Function */
758c2ecf20Sopenharmony_ci#define WS_MODE		(1 << 0)	/* WS Mode */
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define SSI_NAME "ssi"
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistruct rsnd_ssi {
808c2ecf20Sopenharmony_ci	struct rsnd_mod mod;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	u32 flags;
838c2ecf20Sopenharmony_ci	u32 cr_own;
848c2ecf20Sopenharmony_ci	u32 cr_clk;
858c2ecf20Sopenharmony_ci	u32 cr_mode;
868c2ecf20Sopenharmony_ci	u32 cr_en;
878c2ecf20Sopenharmony_ci	u32 wsr;
888c2ecf20Sopenharmony_ci	int chan;
898c2ecf20Sopenharmony_ci	int rate;
908c2ecf20Sopenharmony_ci	int irq;
918c2ecf20Sopenharmony_ci	unsigned int usrcnt;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* for PIO */
948c2ecf20Sopenharmony_ci	int byte_pos;
958c2ecf20Sopenharmony_ci	int byte_per_period;
968c2ecf20Sopenharmony_ci	int next_period_byte;
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci/* flags */
1008c2ecf20Sopenharmony_ci#define RSND_SSI_CLK_PIN_SHARE		(1 << 0)
1018c2ecf20Sopenharmony_ci#define RSND_SSI_NO_BUSIF		(1 << 1) /* SSI+DMA without BUSIF */
1028c2ecf20Sopenharmony_ci#define RSND_SSI_PROBED			(1 << 2)
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci#define for_each_rsnd_ssi(pos, priv, i)					\
1058c2ecf20Sopenharmony_ci	for (i = 0;							\
1068c2ecf20Sopenharmony_ci	     (i < rsnd_ssi_nr(priv)) &&					\
1078c2ecf20Sopenharmony_ci		((pos) = ((struct rsnd_ssi *)(priv)->ssi + i));		\
1088c2ecf20Sopenharmony_ci	     i++)
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id)
1118c2ecf20Sopenharmony_ci#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
1128c2ecf20Sopenharmony_ci#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
1138c2ecf20Sopenharmony_ci#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io))
1148c2ecf20Sopenharmony_ci#define rsnd_ssi_is_multi_secondary(mod, io)				\
1158c2ecf20Sopenharmony_ci	(rsnd_ssi_multi_secondaries(io) & (1 << rsnd_mod_id(mod)))
1168c2ecf20Sopenharmony_ci#define rsnd_ssi_is_run_mods(mod, io) \
1178c2ecf20Sopenharmony_ci	(rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod)))
1188c2ecf20Sopenharmony_ci#define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod))
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciint rsnd_ssi_use_busif(struct rsnd_dai_stream *io)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io);
1258c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
1268c2ecf20Sopenharmony_ci	int use_busif = 0;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_dma_mode(mod))
1298c2ecf20Sopenharmony_ci		return 0;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	if (!(rsnd_flags_has(ssi, RSND_SSI_NO_BUSIF)))
1328c2ecf20Sopenharmony_ci		use_busif = 1;
1338c2ecf20Sopenharmony_ci	if (rsnd_io_to_mod_src(io))
1348c2ecf20Sopenharmony_ci		use_busif = 1;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return use_busif;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic void rsnd_ssi_status_clear(struct rsnd_mod *mod)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSISR, 0);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic u32 rsnd_ssi_status_get(struct rsnd_mod *mod)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	return rsnd_mod_read(mod, SSISR);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic void rsnd_ssi_status_check(struct rsnd_mod *mod,
1508c2ecf20Sopenharmony_ci				  u32 bit)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
1538c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
1548c2ecf20Sopenharmony_ci	u32 status;
1558c2ecf20Sopenharmony_ci	int i;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	for (i = 0; i < 1024; i++) {
1588c2ecf20Sopenharmony_ci		status = rsnd_ssi_status_get(mod);
1598c2ecf20Sopenharmony_ci		if (status & bit)
1608c2ecf20Sopenharmony_ci			return;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		udelay(5);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	dev_warn(dev, "%s status check failed\n", rsnd_mod_name(mod));
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	struct rsnd_mod *mod;
1718c2ecf20Sopenharmony_ci	enum rsnd_mod_type types[] = {
1728c2ecf20Sopenharmony_ci		RSND_MOD_SSIM1,
1738c2ecf20Sopenharmony_ci		RSND_MOD_SSIM2,
1748c2ecf20Sopenharmony_ci		RSND_MOD_SSIM3,
1758c2ecf20Sopenharmony_ci	};
1768c2ecf20Sopenharmony_ci	int i, mask;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	mask = 0;
1798c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(types); i++) {
1808c2ecf20Sopenharmony_ci		mod = rsnd_io_to_mod(io, types[i]);
1818c2ecf20Sopenharmony_ci		if (!mod)
1828c2ecf20Sopenharmony_ci			continue;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		mask |= 1 << rsnd_mod_id(mod);
1858c2ecf20Sopenharmony_ci	}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	return mask;
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistatic u32 rsnd_ssi_run_mods(struct rsnd_dai_stream *io)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
1938c2ecf20Sopenharmony_ci	struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io);
1948c2ecf20Sopenharmony_ci	u32 mods;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	mods = rsnd_ssi_multi_secondaries_runtime(io) |
1978c2ecf20Sopenharmony_ci		1 << rsnd_mod_id(ssi_mod);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	if (ssi_parent_mod)
2008c2ecf20Sopenharmony_ci		mods |= 1 << rsnd_mod_id(ssi_parent_mod);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	return mods;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciu32 rsnd_ssi_multi_secondaries_runtime(struct rsnd_dai_stream *io)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	if (rsnd_runtime_is_multi_ssi(io))
2088c2ecf20Sopenharmony_ci		return rsnd_ssi_multi_secondaries(io);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
2168c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
2178c2ecf20Sopenharmony_ci	int width = rsnd_rdai_width_get(rdai);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	switch (width) {
2208c2ecf20Sopenharmony_ci	case 32: return SWL_32;
2218c2ecf20Sopenharmony_ci	case 24: return SWL_24;
2228c2ecf20Sopenharmony_ci	case 16: return SWL_16;
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	dev_err(dev, "unsupported slot width value: %d\n", width);
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ciunsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
2308c2ecf20Sopenharmony_ci		       int param1, int param2, int *idx)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
2338c2ecf20Sopenharmony_ci	int ssi_clk_mul_table[] = {
2348c2ecf20Sopenharmony_ci		1, 2, 4, 8, 16, 6, 12,
2358c2ecf20Sopenharmony_ci	};
2368c2ecf20Sopenharmony_ci	int j, ret;
2378c2ecf20Sopenharmony_ci	unsigned int main_rate;
2388c2ecf20Sopenharmony_ci	int width = rsnd_rdai_width_get(rdai);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		/*
2438c2ecf20Sopenharmony_ci		 * It will set SSIWSR.CONT here, but SSICR.CKDV = 000
2448c2ecf20Sopenharmony_ci		 * with it is not allowed. (SSIWSR.WS_MODE with
2458c2ecf20Sopenharmony_ci		 * SSICR.CKDV = 000 is not allowed either).
2468c2ecf20Sopenharmony_ci		 * Skip it. See SSICR.CKDV
2478c2ecf20Sopenharmony_ci		 */
2488c2ecf20Sopenharmony_ci		if (j == 0)
2498c2ecf20Sopenharmony_ci			continue;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci		main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		ret = rsnd_adg_clk_query(priv, main_rate);
2548c2ecf20Sopenharmony_ci		if (ret < 0)
2558c2ecf20Sopenharmony_ci			continue;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci		if (idx)
2588c2ecf20Sopenharmony_ci			*idx = j;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		return main_rate;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return 0;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
2678c2ecf20Sopenharmony_ci				     struct rsnd_dai_stream *io)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_io_to_priv(io);
2708c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
2718c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
2728c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
2738c2ecf20Sopenharmony_ci	int chan = rsnd_runtime_channel_for_ssi(io);
2748c2ecf20Sopenharmony_ci	int idx, ret;
2758c2ecf20Sopenharmony_ci	unsigned int main_rate;
2768c2ecf20Sopenharmony_ci	unsigned int rate = rsnd_io_is_play(io) ?
2778c2ecf20Sopenharmony_ci		rsnd_src_get_out_rate(priv, io) :
2788c2ecf20Sopenharmony_ci		rsnd_src_get_in_rate(priv, io);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	if (!rsnd_rdai_is_clk_master(rdai))
2818c2ecf20Sopenharmony_ci		return 0;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (!rsnd_ssi_can_output_clk(mod))
2848c2ecf20Sopenharmony_ci		return 0;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_multi_secondary(mod, io))
2878c2ecf20Sopenharmony_ci		return 0;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (rsnd_runtime_is_tdm_split(io))
2908c2ecf20Sopenharmony_ci		chan = rsnd_io_converted_chan(io);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	chan = rsnd_channel_normalization(chan);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (ssi->usrcnt > 0) {
2958c2ecf20Sopenharmony_ci		if (ssi->rate != rate) {
2968c2ecf20Sopenharmony_ci			dev_err(dev, "SSI parent/child should use same rate\n");
2978c2ecf20Sopenharmony_ci			return -EINVAL;
2988c2ecf20Sopenharmony_ci		}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		if (ssi->chan != chan) {
3018c2ecf20Sopenharmony_ci			dev_err(dev, "SSI parent/child should use same chan\n");
3028c2ecf20Sopenharmony_ci			return -EINVAL;
3038c2ecf20Sopenharmony_ci		}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		return 0;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
3098c2ecf20Sopenharmony_ci	if (!main_rate) {
3108c2ecf20Sopenharmony_ci		dev_err(dev, "unsupported clock rate\n");
3118c2ecf20Sopenharmony_ci		return -EIO;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ret = rsnd_adg_ssi_clk_try_start(mod, main_rate);
3158c2ecf20Sopenharmony_ci	if (ret < 0)
3168c2ecf20Sopenharmony_ci		return ret;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/*
3198c2ecf20Sopenharmony_ci	 * SSI clock will be output contiguously
3208c2ecf20Sopenharmony_ci	 * by below settings.
3218c2ecf20Sopenharmony_ci	 * This means, rsnd_ssi_master_clk_start()
3228c2ecf20Sopenharmony_ci	 * and rsnd_ssi_register_setup() are necessary
3238c2ecf20Sopenharmony_ci	 * for SSI parent
3248c2ecf20Sopenharmony_ci	 *
3258c2ecf20Sopenharmony_ci	 * SSICR  : FORCE, SCKD, SWSD
3268c2ecf20Sopenharmony_ci	 * SSIWSR : CONT
3278c2ecf20Sopenharmony_ci	 */
3288c2ecf20Sopenharmony_ci	ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
3298c2ecf20Sopenharmony_ci			SCKD | SWSD | CKDV(idx);
3308c2ecf20Sopenharmony_ci	ssi->wsr = CONT;
3318c2ecf20Sopenharmony_ci	ssi->rate = rate;
3328c2ecf20Sopenharmony_ci	ssi->chan = chan;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s outputs %d chan %u Hz\n",
3358c2ecf20Sopenharmony_ci		rsnd_mod_name(mod), chan, rate);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	return 0;
3388c2ecf20Sopenharmony_ci}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_cistatic void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod,
3418c2ecf20Sopenharmony_ci				     struct rsnd_dai_stream *io)
3428c2ecf20Sopenharmony_ci{
3438c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
3448c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	if (!rsnd_rdai_is_clk_master(rdai))
3478c2ecf20Sopenharmony_ci		return;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (!rsnd_ssi_can_output_clk(mod))
3508c2ecf20Sopenharmony_ci		return;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (ssi->usrcnt > 1)
3538c2ecf20Sopenharmony_ci		return;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	ssi->cr_clk	= 0;
3568c2ecf20Sopenharmony_ci	ssi->rate	= 0;
3578c2ecf20Sopenharmony_ci	ssi->chan	= 0;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	rsnd_adg_ssi_clk_stop(mod);
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic void rsnd_ssi_config_init(struct rsnd_mod *mod,
3638c2ecf20Sopenharmony_ci				struct rsnd_dai_stream *io)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
3668c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
3678c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
3688c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
3698c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
3708c2ecf20Sopenharmony_ci	u32 cr_own	= ssi->cr_own;
3718c2ecf20Sopenharmony_ci	u32 cr_mode	= ssi->cr_mode;
3728c2ecf20Sopenharmony_ci	u32 wsr		= ssi->wsr;
3738c2ecf20Sopenharmony_ci	int width;
3748c2ecf20Sopenharmony_ci	int is_tdm, is_tdm_split;
3758c2ecf20Sopenharmony_ci	int id = rsnd_mod_id(mod);
3768c2ecf20Sopenharmony_ci	int i;
3778c2ecf20Sopenharmony_ci	u32 sys_int_enable = 0;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	is_tdm		= rsnd_runtime_is_tdm(io);
3808c2ecf20Sopenharmony_ci	is_tdm_split	= rsnd_runtime_is_tdm_split(io);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (is_tdm)
3838c2ecf20Sopenharmony_ci		dev_dbg(dev, "TDM mode\n");
3848c2ecf20Sopenharmony_ci	if (is_tdm_split)
3858c2ecf20Sopenharmony_ci		dev_dbg(dev, "TDM Split mode\n");
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	if (rdai->bit_clk_inv)
3908c2ecf20Sopenharmony_ci		cr_own |= SCKP;
3918c2ecf20Sopenharmony_ci	if (rdai->frm_clk_inv && !is_tdm)
3928c2ecf20Sopenharmony_ci		cr_own |= SWSP;
3938c2ecf20Sopenharmony_ci	if (rdai->data_alignment)
3948c2ecf20Sopenharmony_ci		cr_own |= SDTA;
3958c2ecf20Sopenharmony_ci	if (rdai->sys_delay)
3968c2ecf20Sopenharmony_ci		cr_own |= DEL;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/*
3998c2ecf20Sopenharmony_ci	 * TDM Mode
4008c2ecf20Sopenharmony_ci	 * see
4018c2ecf20Sopenharmony_ci	 *	rsnd_ssiu_init_gen2()
4028c2ecf20Sopenharmony_ci	 */
4038c2ecf20Sopenharmony_ci	wsr = ssi->wsr;
4048c2ecf20Sopenharmony_ci	if (is_tdm || is_tdm_split) {
4058c2ecf20Sopenharmony_ci		wsr	|= WS_MODE;
4068c2ecf20Sopenharmony_ci		cr_own	|= CHNL_8;
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/*
4108c2ecf20Sopenharmony_ci	 * We shouldn't exchange SWSP after running.
4118c2ecf20Sopenharmony_ci	 * This means, parent needs to care it.
4128c2ecf20Sopenharmony_ci	 */
4138c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_parent(mod, io))
4148c2ecf20Sopenharmony_ci		goto init_end;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (rsnd_io_is_play(io))
4178c2ecf20Sopenharmony_ci		cr_own |= TRMD;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	cr_own &= ~DWL_MASK;
4208c2ecf20Sopenharmony_ci	width = snd_pcm_format_width(runtime->format);
4218c2ecf20Sopenharmony_ci	if (is_tdm_split) {
4228c2ecf20Sopenharmony_ci		/*
4238c2ecf20Sopenharmony_ci		 * The SWL and DWL bits in SSICR should be fixed at 32-bit
4248c2ecf20Sopenharmony_ci		 * setting when TDM split mode.
4258c2ecf20Sopenharmony_ci		 * see datasheet
4268c2ecf20Sopenharmony_ci		 *	Operation :: TDM Format Split Function (TDM Split Mode)
4278c2ecf20Sopenharmony_ci		 */
4288c2ecf20Sopenharmony_ci		width = 32;
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	switch (width) {
4328c2ecf20Sopenharmony_ci	case 8:
4338c2ecf20Sopenharmony_ci		cr_own |= DWL_8;
4348c2ecf20Sopenharmony_ci		break;
4358c2ecf20Sopenharmony_ci	case 16:
4368c2ecf20Sopenharmony_ci		cr_own |= DWL_16;
4378c2ecf20Sopenharmony_ci		break;
4388c2ecf20Sopenharmony_ci	case 24:
4398c2ecf20Sopenharmony_ci		cr_own |= DWL_24;
4408c2ecf20Sopenharmony_ci		break;
4418c2ecf20Sopenharmony_ci	case 32:
4428c2ecf20Sopenharmony_ci		cr_own |= DWL_32;
4438c2ecf20Sopenharmony_ci		break;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_dma_mode(mod)) {
4478c2ecf20Sopenharmony_ci		cr_mode = UIEN | OIEN |	/* over/under run */
4488c2ecf20Sopenharmony_ci			  DMEN;		/* DMA : enable DMA */
4498c2ecf20Sopenharmony_ci	} else {
4508c2ecf20Sopenharmony_ci		cr_mode = DIEN;		/* PIO : enable Data interrupt */
4518c2ecf20Sopenharmony_ci	}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	/* enable busif buffer over/under run interrupt. */
4548c2ecf20Sopenharmony_ci	if (is_tdm || is_tdm_split) {
4558c2ecf20Sopenharmony_ci		switch (id) {
4568c2ecf20Sopenharmony_ci		case 0:
4578c2ecf20Sopenharmony_ci		case 1:
4588c2ecf20Sopenharmony_ci		case 2:
4598c2ecf20Sopenharmony_ci		case 3:
4608c2ecf20Sopenharmony_ci		case 4:
4618c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
4628c2ecf20Sopenharmony_ci				sys_int_enable = rsnd_mod_read(mod,
4638c2ecf20Sopenharmony_ci					SSI_SYS_INT_ENABLE(i * 2));
4648c2ecf20Sopenharmony_ci				sys_int_enable |= 0xf << (id * 4);
4658c2ecf20Sopenharmony_ci				rsnd_mod_write(mod,
4668c2ecf20Sopenharmony_ci					       SSI_SYS_INT_ENABLE(i * 2),
4678c2ecf20Sopenharmony_ci					       sys_int_enable);
4688c2ecf20Sopenharmony_ci			}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci			break;
4718c2ecf20Sopenharmony_ci		case 9:
4728c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
4738c2ecf20Sopenharmony_ci				sys_int_enable = rsnd_mod_read(mod,
4748c2ecf20Sopenharmony_ci					SSI_SYS_INT_ENABLE((i * 2) + 1));
4758c2ecf20Sopenharmony_ci				sys_int_enable |= 0xf << 4;
4768c2ecf20Sopenharmony_ci				rsnd_mod_write(mod,
4778c2ecf20Sopenharmony_ci					       SSI_SYS_INT_ENABLE((i * 2) + 1),
4788c2ecf20Sopenharmony_ci					       sys_int_enable);
4798c2ecf20Sopenharmony_ci			}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci		}
4838c2ecf20Sopenharmony_ci	}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ciinit_end:
4868c2ecf20Sopenharmony_ci	ssi->cr_own	= cr_own;
4878c2ecf20Sopenharmony_ci	ssi->cr_mode	= cr_mode;
4888c2ecf20Sopenharmony_ci	ssi->wsr	= wsr;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistatic void rsnd_ssi_register_setup(struct rsnd_mod *mod)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSIWSR,	ssi->wsr);
4968c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSICR,	ssi->cr_own	|
4978c2ecf20Sopenharmony_ci					ssi->cr_clk	|
4988c2ecf20Sopenharmony_ci					ssi->cr_mode	|
4998c2ecf20Sopenharmony_ci					ssi->cr_en);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci/*
5038c2ecf20Sopenharmony_ci *	SSI mod common functions
5048c2ecf20Sopenharmony_ci */
5058c2ecf20Sopenharmony_cistatic int rsnd_ssi_init(struct rsnd_mod *mod,
5068c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
5078c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
5108c2ecf20Sopenharmony_ci	int ret;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_run_mods(mod, io))
5138c2ecf20Sopenharmony_ci		return 0;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	ret = rsnd_ssi_master_clk_start(mod, io);
5168c2ecf20Sopenharmony_ci	if (ret < 0)
5178c2ecf20Sopenharmony_ci		return ret;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	ssi->usrcnt++;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	ret = rsnd_mod_power_on(mod);
5228c2ecf20Sopenharmony_ci	if (ret < 0)
5238c2ecf20Sopenharmony_ci		return ret;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	rsnd_ssi_config_init(mod, io);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	rsnd_ssi_register_setup(mod);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* clear error status */
5308c2ecf20Sopenharmony_ci	rsnd_ssi_status_clear(mod);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	return 0;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic int rsnd_ssi_quit(struct rsnd_mod *mod,
5368c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
5378c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
5408c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
5418c2ecf20Sopenharmony_ci	int is_tdm, is_tdm_split;
5428c2ecf20Sopenharmony_ci	int id = rsnd_mod_id(mod);
5438c2ecf20Sopenharmony_ci	int i;
5448c2ecf20Sopenharmony_ci	u32 sys_int_enable = 0;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	is_tdm		= rsnd_runtime_is_tdm(io);
5478c2ecf20Sopenharmony_ci	is_tdm_split	= rsnd_runtime_is_tdm_split(io);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_run_mods(mod, io))
5508c2ecf20Sopenharmony_ci		return 0;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	if (!ssi->usrcnt) {
5538c2ecf20Sopenharmony_ci		dev_err(dev, "%s usrcnt error\n", rsnd_mod_name(mod));
5548c2ecf20Sopenharmony_ci		return -EIO;
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	rsnd_ssi_master_clk_stop(mod, io);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	rsnd_mod_power_off(mod);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	ssi->usrcnt--;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	if (!ssi->usrcnt) {
5648c2ecf20Sopenharmony_ci		ssi->cr_own	= 0;
5658c2ecf20Sopenharmony_ci		ssi->cr_mode	= 0;
5668c2ecf20Sopenharmony_ci		ssi->wsr	= 0;
5678c2ecf20Sopenharmony_ci	}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* disable busif buffer over/under run interrupt. */
5708c2ecf20Sopenharmony_ci	if (is_tdm || is_tdm_split) {
5718c2ecf20Sopenharmony_ci		switch (id) {
5728c2ecf20Sopenharmony_ci		case 0:
5738c2ecf20Sopenharmony_ci		case 1:
5748c2ecf20Sopenharmony_ci		case 2:
5758c2ecf20Sopenharmony_ci		case 3:
5768c2ecf20Sopenharmony_ci		case 4:
5778c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
5788c2ecf20Sopenharmony_ci				sys_int_enable = rsnd_mod_read(mod,
5798c2ecf20Sopenharmony_ci						SSI_SYS_INT_ENABLE(i * 2));
5808c2ecf20Sopenharmony_ci				sys_int_enable &= ~(0xf << (id * 4));
5818c2ecf20Sopenharmony_ci				rsnd_mod_write(mod,
5828c2ecf20Sopenharmony_ci					       SSI_SYS_INT_ENABLE(i * 2),
5838c2ecf20Sopenharmony_ci					       sys_int_enable);
5848c2ecf20Sopenharmony_ci			}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci			break;
5878c2ecf20Sopenharmony_ci		case 9:
5888c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
5898c2ecf20Sopenharmony_ci				sys_int_enable = rsnd_mod_read(mod,
5908c2ecf20Sopenharmony_ci					SSI_SYS_INT_ENABLE((i * 2) + 1));
5918c2ecf20Sopenharmony_ci				sys_int_enable &= ~(0xf << 4);
5928c2ecf20Sopenharmony_ci				rsnd_mod_write(mod,
5938c2ecf20Sopenharmony_ci					       SSI_SYS_INT_ENABLE((i * 2) + 1),
5948c2ecf20Sopenharmony_ci					       sys_int_enable);
5958c2ecf20Sopenharmony_ci			}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci			break;
5988c2ecf20Sopenharmony_ci		}
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int rsnd_ssi_hw_params(struct rsnd_mod *mod,
6058c2ecf20Sopenharmony_ci			      struct rsnd_dai_stream *io,
6068c2ecf20Sopenharmony_ci			      struct snd_pcm_substream *substream,
6078c2ecf20Sopenharmony_ci			      struct snd_pcm_hw_params *params)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
6108c2ecf20Sopenharmony_ci	unsigned int fmt_width = snd_pcm_format_width(params_format(params));
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	if (fmt_width > rdai->chan_width) {
6138c2ecf20Sopenharmony_ci		struct rsnd_priv *priv = rsnd_io_to_priv(io);
6148c2ecf20Sopenharmony_ci		struct device *dev = rsnd_priv_to_dev(priv);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci		dev_err(dev, "invalid combination of slot-width and format-data-width\n");
6178c2ecf20Sopenharmony_ci		return -EINVAL;
6188c2ecf20Sopenharmony_ci	}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	return 0;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_cistatic int rsnd_ssi_start(struct rsnd_mod *mod,
6248c2ecf20Sopenharmony_ci			  struct rsnd_dai_stream *io,
6258c2ecf20Sopenharmony_ci			  struct rsnd_priv *priv)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_run_mods(mod, io))
6308c2ecf20Sopenharmony_ci		return 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/*
6338c2ecf20Sopenharmony_ci	 * EN will be set via SSIU :: SSI_CONTROL
6348c2ecf20Sopenharmony_ci	 * if Multi channel mode
6358c2ecf20Sopenharmony_ci	 */
6368c2ecf20Sopenharmony_ci	if (rsnd_ssi_multi_secondaries_runtime(io))
6378c2ecf20Sopenharmony_ci		return 0;
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/*
6408c2ecf20Sopenharmony_ci	 * EN is for data output.
6418c2ecf20Sopenharmony_ci	 * SSI parent EN is not needed.
6428c2ecf20Sopenharmony_ci	 */
6438c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_parent(mod, io))
6448c2ecf20Sopenharmony_ci		return 0;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	ssi->cr_en = EN;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSICR,	ssi->cr_own	|
6498c2ecf20Sopenharmony_ci					ssi->cr_clk	|
6508c2ecf20Sopenharmony_ci					ssi->cr_mode	|
6518c2ecf20Sopenharmony_ci					ssi->cr_en);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	return 0;
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic int rsnd_ssi_stop(struct rsnd_mod *mod,
6578c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
6588c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
6618c2ecf20Sopenharmony_ci	u32 cr;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_run_mods(mod, io))
6648c2ecf20Sopenharmony_ci		return 0;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_parent(mod, io))
6678c2ecf20Sopenharmony_ci		return 0;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	cr  =	ssi->cr_own	|
6708c2ecf20Sopenharmony_ci		ssi->cr_clk;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	/*
6738c2ecf20Sopenharmony_ci	 * disable all IRQ,
6748c2ecf20Sopenharmony_ci	 * Playback: Wait all data was sent
6758c2ecf20Sopenharmony_ci	 * Capture:  It might not receave data. Do nothing
6768c2ecf20Sopenharmony_ci	 */
6778c2ecf20Sopenharmony_ci	if (rsnd_io_is_play(io)) {
6788c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, SSICR, cr | ssi->cr_en);
6798c2ecf20Sopenharmony_ci		rsnd_ssi_status_check(mod, DIRQ);
6808c2ecf20Sopenharmony_ci	}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	/* In multi-SSI mode, stop is performed by setting ssi0129 in
6838c2ecf20Sopenharmony_ci	 * SSI_CONTROL to 0 (in rsnd_ssio_stop_gen2). Do nothing here.
6848c2ecf20Sopenharmony_ci	 */
6858c2ecf20Sopenharmony_ci	if (rsnd_ssi_multi_secondaries_runtime(io))
6868c2ecf20Sopenharmony_ci		return 0;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	/*
6898c2ecf20Sopenharmony_ci	 * disable SSI,
6908c2ecf20Sopenharmony_ci	 * and, wait idle state
6918c2ecf20Sopenharmony_ci	 */
6928c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSICR, cr);	/* disabled all */
6938c2ecf20Sopenharmony_ci	rsnd_ssi_status_check(mod, IIRQ);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	ssi->cr_en = 0;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	return 0;
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic int rsnd_ssi_irq(struct rsnd_mod *mod,
7018c2ecf20Sopenharmony_ci			struct rsnd_dai_stream *io,
7028c2ecf20Sopenharmony_ci			struct rsnd_priv *priv,
7038c2ecf20Sopenharmony_ci			int enable)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	u32 val = 0;
7068c2ecf20Sopenharmony_ci	int is_tdm, is_tdm_split;
7078c2ecf20Sopenharmony_ci	int id = rsnd_mod_id(mod);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	is_tdm		= rsnd_runtime_is_tdm(io);
7108c2ecf20Sopenharmony_ci	is_tdm_split	= rsnd_runtime_is_tdm_split(io);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	if (rsnd_is_gen1(priv))
7138c2ecf20Sopenharmony_ci		return 0;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_parent(mod, io))
7168c2ecf20Sopenharmony_ci		return 0;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_run_mods(mod, io))
7198c2ecf20Sopenharmony_ci		return 0;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	if (enable)
7228c2ecf20Sopenharmony_ci		val = rsnd_ssi_is_dma_mode(mod) ? 0x0e000000 : 0x0f000000;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	if (is_tdm || is_tdm_split) {
7258c2ecf20Sopenharmony_ci		switch (id) {
7268c2ecf20Sopenharmony_ci		case 0:
7278c2ecf20Sopenharmony_ci		case 1:
7288c2ecf20Sopenharmony_ci		case 2:
7298c2ecf20Sopenharmony_ci		case 3:
7308c2ecf20Sopenharmony_ci		case 4:
7318c2ecf20Sopenharmony_ci		case 9:
7328c2ecf20Sopenharmony_ci			val |= 0x0000ff00;
7338c2ecf20Sopenharmony_ci			break;
7348c2ecf20Sopenharmony_ci		}
7358c2ecf20Sopenharmony_ci	}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, SSI_INT_ENABLE, val);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return 0;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistatic bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
7438c2ecf20Sopenharmony_ci				   struct rsnd_dai_stream *io);
7448c2ecf20Sopenharmony_cistatic void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
7458c2ecf20Sopenharmony_ci				 struct rsnd_dai_stream *io)
7468c2ecf20Sopenharmony_ci{
7478c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
7488c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
7498c2ecf20Sopenharmony_ci	int is_dma = rsnd_ssi_is_dma_mode(mod);
7508c2ecf20Sopenharmony_ci	u32 status;
7518c2ecf20Sopenharmony_ci	bool elapsed = false;
7528c2ecf20Sopenharmony_ci	bool stop = false;
7538c2ecf20Sopenharmony_ci	int id = rsnd_mod_id(mod);
7548c2ecf20Sopenharmony_ci	int i;
7558c2ecf20Sopenharmony_ci	int is_tdm, is_tdm_split;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	is_tdm		= rsnd_runtime_is_tdm(io);
7588c2ecf20Sopenharmony_ci	is_tdm_split	= rsnd_runtime_is_tdm_split(io);
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	spin_lock(&priv->lock);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	/* ignore all cases if not working */
7638c2ecf20Sopenharmony_ci	if (!rsnd_io_is_working(io))
7648c2ecf20Sopenharmony_ci		goto rsnd_ssi_interrupt_out;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	status = rsnd_ssi_status_get(mod);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	/* PIO only */
7698c2ecf20Sopenharmony_ci	if (!is_dma && (status & DIRQ))
7708c2ecf20Sopenharmony_ci		elapsed = rsnd_ssi_pio_interrupt(mod, io);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	/* DMA only */
7738c2ecf20Sopenharmony_ci	if (is_dma && (status & (UIRQ | OIRQ))) {
7748c2ecf20Sopenharmony_ci		rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n",
7758c2ecf20Sopenharmony_ci			rsnd_mod_name(mod), status);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci		stop = true;
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	status = 0;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (is_tdm || is_tdm_split) {
7838c2ecf20Sopenharmony_ci		switch (id) {
7848c2ecf20Sopenharmony_ci		case 0:
7858c2ecf20Sopenharmony_ci		case 1:
7868c2ecf20Sopenharmony_ci		case 2:
7878c2ecf20Sopenharmony_ci		case 3:
7888c2ecf20Sopenharmony_ci		case 4:
7898c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
7908c2ecf20Sopenharmony_ci				status = rsnd_mod_read(mod,
7918c2ecf20Sopenharmony_ci						       SSI_SYS_STATUS(i * 2));
7928c2ecf20Sopenharmony_ci				status &= 0xf << (id * 4);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci				if (status) {
7958c2ecf20Sopenharmony_ci					rsnd_dbg_irq_status(dev,
7968c2ecf20Sopenharmony_ci						"%s err status : 0x%08x\n",
7978c2ecf20Sopenharmony_ci						rsnd_mod_name(mod), status);
7988c2ecf20Sopenharmony_ci					rsnd_mod_write(mod,
7998c2ecf20Sopenharmony_ci						       SSI_SYS_STATUS(i * 2),
8008c2ecf20Sopenharmony_ci						       0xf << (id * 4));
8018c2ecf20Sopenharmony_ci					stop = true;
8028c2ecf20Sopenharmony_ci				}
8038c2ecf20Sopenharmony_ci			}
8048c2ecf20Sopenharmony_ci			break;
8058c2ecf20Sopenharmony_ci		case 9:
8068c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
8078c2ecf20Sopenharmony_ci				status = rsnd_mod_read(mod,
8088c2ecf20Sopenharmony_ci						SSI_SYS_STATUS((i * 2) + 1));
8098c2ecf20Sopenharmony_ci				status &= 0xf << 4;
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci				if (status) {
8128c2ecf20Sopenharmony_ci					rsnd_dbg_irq_status(dev,
8138c2ecf20Sopenharmony_ci						"%s err status : 0x%08x\n",
8148c2ecf20Sopenharmony_ci						rsnd_mod_name(mod), status);
8158c2ecf20Sopenharmony_ci					rsnd_mod_write(mod,
8168c2ecf20Sopenharmony_ci						SSI_SYS_STATUS((i * 2) + 1),
8178c2ecf20Sopenharmony_ci						0xf << 4);
8188c2ecf20Sopenharmony_ci					stop = true;
8198c2ecf20Sopenharmony_ci				}
8208c2ecf20Sopenharmony_ci			}
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci		}
8238c2ecf20Sopenharmony_ci	}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	rsnd_ssi_status_clear(mod);
8268c2ecf20Sopenharmony_cirsnd_ssi_interrupt_out:
8278c2ecf20Sopenharmony_ci	spin_unlock(&priv->lock);
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (elapsed)
8308c2ecf20Sopenharmony_ci		rsnd_dai_period_elapsed(io);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	if (stop)
8338c2ecf20Sopenharmony_ci		snd_pcm_stop_xrun(io->substream);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
8388c2ecf20Sopenharmony_ci{
8398c2ecf20Sopenharmony_ci	struct rsnd_mod *mod = data;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	rsnd_mod_interrupt(mod, __rsnd_ssi_interrupt);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic u32 *rsnd_ssi_get_status(struct rsnd_mod *mod,
8478c2ecf20Sopenharmony_ci				struct rsnd_dai_stream *io,
8488c2ecf20Sopenharmony_ci				enum rsnd_mod_type type)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	/*
8518c2ecf20Sopenharmony_ci	 * SSIP (= SSI parent) needs to be special, otherwise,
8528c2ecf20Sopenharmony_ci	 * 2nd SSI might doesn't start. see also rsnd_mod_call()
8538c2ecf20Sopenharmony_ci	 *
8548c2ecf20Sopenharmony_ci	 * We can't include parent SSI status on SSI, because we don't know
8558c2ecf20Sopenharmony_ci	 * how many SSI requests parent SSI. Thus, it is localed on "io" now.
8568c2ecf20Sopenharmony_ci	 * ex) trouble case
8578c2ecf20Sopenharmony_ci	 *	Playback: SSI0
8588c2ecf20Sopenharmony_ci	 *	Capture : SSI1 (needs SSI0)
8598c2ecf20Sopenharmony_ci	 *
8608c2ecf20Sopenharmony_ci	 * 1) start Capture  ->	SSI0/SSI1 are started.
8618c2ecf20Sopenharmony_ci	 * 2) start Playback ->	SSI0 doesn't work, because it is already
8628c2ecf20Sopenharmony_ci	 *			marked as "started" on 1)
8638c2ecf20Sopenharmony_ci	 *
8648c2ecf20Sopenharmony_ci	 * OTOH, using each mod's status is good for MUX case.
8658c2ecf20Sopenharmony_ci	 * It doesn't need to start in 2nd start
8668c2ecf20Sopenharmony_ci	 * ex)
8678c2ecf20Sopenharmony_ci	 *	IO-0: SRC0 -> CTU1 -+-> MUX -> DVC -> SSIU -> SSI0
8688c2ecf20Sopenharmony_ci	 *			    |
8698c2ecf20Sopenharmony_ci	 *	IO-1: SRC1 -> CTU2 -+
8708c2ecf20Sopenharmony_ci	 *
8718c2ecf20Sopenharmony_ci	 * 1) start IO-0 ->	start SSI0
8728c2ecf20Sopenharmony_ci	 * 2) start IO-1 ->	SSI0 doesn't need to start, because it is
8738c2ecf20Sopenharmony_ci	 *			already started on 1)
8748c2ecf20Sopenharmony_ci	 */
8758c2ecf20Sopenharmony_ci	if (type == RSND_MOD_SSIP)
8768c2ecf20Sopenharmony_ci		return &io->parent_ssi_status;
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	return rsnd_mod_get_status(mod, io, type);
8798c2ecf20Sopenharmony_ci}
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci/*
8828c2ecf20Sopenharmony_ci *		SSI PIO
8838c2ecf20Sopenharmony_ci */
8848c2ecf20Sopenharmony_cistatic void rsnd_ssi_parent_attach(struct rsnd_mod *mod,
8858c2ecf20Sopenharmony_ci				   struct rsnd_dai_stream *io)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
8888c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (!__rsnd_ssi_is_pin_sharing(mod))
8918c2ecf20Sopenharmony_ci		return;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (!rsnd_rdai_is_clk_master(rdai))
8948c2ecf20Sopenharmony_ci		return;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_multi_secondary(mod, io))
8978c2ecf20Sopenharmony_ci		return;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	switch (rsnd_mod_id(mod)) {
9008c2ecf20Sopenharmony_ci	case 1:
9018c2ecf20Sopenharmony_ci	case 2:
9028c2ecf20Sopenharmony_ci	case 9:
9038c2ecf20Sopenharmony_ci		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP);
9048c2ecf20Sopenharmony_ci		break;
9058c2ecf20Sopenharmony_ci	case 4:
9068c2ecf20Sopenharmony_ci		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP);
9078c2ecf20Sopenharmony_ci		break;
9088c2ecf20Sopenharmony_ci	case 8:
9098c2ecf20Sopenharmony_ci		rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP);
9108c2ecf20Sopenharmony_ci		break;
9118c2ecf20Sopenharmony_ci	}
9128c2ecf20Sopenharmony_ci}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_cistatic int rsnd_ssi_pcm_new(struct rsnd_mod *mod,
9158c2ecf20Sopenharmony_ci			    struct rsnd_dai_stream *io,
9168c2ecf20Sopenharmony_ci			    struct snd_soc_pcm_runtime *rtd)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	/*
9198c2ecf20Sopenharmony_ci	 * rsnd_rdai_is_clk_master() will be enabled after set_fmt,
9208c2ecf20Sopenharmony_ci	 * and, pcm_new will be called after it.
9218c2ecf20Sopenharmony_ci	 * This function reuse pcm_new at this point.
9228c2ecf20Sopenharmony_ci	 */
9238c2ecf20Sopenharmony_ci	rsnd_ssi_parent_attach(mod, io);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	return 0;
9268c2ecf20Sopenharmony_ci}
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_cistatic int rsnd_ssi_common_probe(struct rsnd_mod *mod,
9298c2ecf20Sopenharmony_ci				 struct rsnd_dai_stream *io,
9308c2ecf20Sopenharmony_ci				 struct rsnd_priv *priv)
9318c2ecf20Sopenharmony_ci{
9328c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
9338c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
9348c2ecf20Sopenharmony_ci	int ret = 0;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	/*
9378c2ecf20Sopenharmony_ci	 * SSIP/SSIU/IRQ are not needed on
9388c2ecf20Sopenharmony_ci	 * SSI Multi secondaries
9398c2ecf20Sopenharmony_ci	 */
9408c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_multi_secondary(mod, io))
9418c2ecf20Sopenharmony_ci		return 0;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	/*
9448c2ecf20Sopenharmony_ci	 * It can't judge ssi parent at this point
9458c2ecf20Sopenharmony_ci	 * see rsnd_ssi_pcm_new()
9468c2ecf20Sopenharmony_ci	 */
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	/*
9498c2ecf20Sopenharmony_ci	 * SSI might be called again as PIO fallback
9508c2ecf20Sopenharmony_ci	 * It is easy to manual handling for IRQ request/free
9518c2ecf20Sopenharmony_ci	 *
9528c2ecf20Sopenharmony_ci	 * OTOH, this function might be called many times if platform is
9538c2ecf20Sopenharmony_ci	 * using MIX. It needs xxx_attach() many times on xxx_probe().
9548c2ecf20Sopenharmony_ci	 * Because of it, we can't control .probe/.remove calling count by
9558c2ecf20Sopenharmony_ci	 * mod->status.
9568c2ecf20Sopenharmony_ci	 * But it don't need to call request_irq() many times.
9578c2ecf20Sopenharmony_ci	 * Let's control it by RSND_SSI_PROBED flag.
9588c2ecf20Sopenharmony_ci	 */
9598c2ecf20Sopenharmony_ci	if (!rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
9608c2ecf20Sopenharmony_ci		ret = request_irq(ssi->irq,
9618c2ecf20Sopenharmony_ci				  rsnd_ssi_interrupt,
9628c2ecf20Sopenharmony_ci				  IRQF_SHARED,
9638c2ecf20Sopenharmony_ci				  dev_name(dev), mod);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		rsnd_flags_set(ssi, RSND_SSI_PROBED);
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	return ret;
9698c2ecf20Sopenharmony_ci}
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_cistatic int rsnd_ssi_common_remove(struct rsnd_mod *mod,
9728c2ecf20Sopenharmony_ci				  struct rsnd_dai_stream *io,
9738c2ecf20Sopenharmony_ci				  struct rsnd_priv *priv)
9748c2ecf20Sopenharmony_ci{
9758c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
9768c2ecf20Sopenharmony_ci	struct rsnd_mod *pure_ssi_mod = rsnd_io_to_mod_ssi(io);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	/* Do nothing if non SSI (= SSI parent, multi SSI) mod */
9798c2ecf20Sopenharmony_ci	if (pure_ssi_mod != mod)
9808c2ecf20Sopenharmony_ci		return 0;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	/* PIO will request IRQ again */
9838c2ecf20Sopenharmony_ci	if (rsnd_flags_has(ssi, RSND_SSI_PROBED)) {
9848c2ecf20Sopenharmony_ci		free_irq(ssi->irq, mod);
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci		rsnd_flags_del(ssi, RSND_SSI_PROBED);
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	return 0;
9908c2ecf20Sopenharmony_ci}
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci/*
9938c2ecf20Sopenharmony_ci *	SSI PIO functions
9948c2ecf20Sopenharmony_ci */
9958c2ecf20Sopenharmony_cistatic bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
9968c2ecf20Sopenharmony_ci				   struct rsnd_dai_stream *io)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
9998c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
10008c2ecf20Sopenharmony_ci	u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
10018c2ecf20Sopenharmony_ci	int shift = 0;
10028c2ecf20Sopenharmony_ci	int byte_pos;
10038c2ecf20Sopenharmony_ci	bool elapsed = false;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (snd_pcm_format_width(runtime->format) == 24)
10068c2ecf20Sopenharmony_ci		shift = 8;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/*
10098c2ecf20Sopenharmony_ci	 * 8/16/32 data can be assesse to TDR/RDR register
10108c2ecf20Sopenharmony_ci	 * directly as 32bit data
10118c2ecf20Sopenharmony_ci	 * see rsnd_ssi_init()
10128c2ecf20Sopenharmony_ci	 */
10138c2ecf20Sopenharmony_ci	if (rsnd_io_is_play(io))
10148c2ecf20Sopenharmony_ci		rsnd_mod_write(mod, SSITDR, (*buf) << shift);
10158c2ecf20Sopenharmony_ci	else
10168c2ecf20Sopenharmony_ci		*buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci	byte_pos = ssi->byte_pos + sizeof(*buf);
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	if (byte_pos >= ssi->next_period_byte) {
10218c2ecf20Sopenharmony_ci		int period_pos = byte_pos / ssi->byte_per_period;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci		if (period_pos >= runtime->periods) {
10248c2ecf20Sopenharmony_ci			byte_pos = 0;
10258c2ecf20Sopenharmony_ci			period_pos = 0;
10268c2ecf20Sopenharmony_ci		}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci		ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci		elapsed = true;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	WRITE_ONCE(ssi->byte_pos, byte_pos);
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	return elapsed;
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic int rsnd_ssi_pio_init(struct rsnd_mod *mod,
10398c2ecf20Sopenharmony_ci			     struct rsnd_dai_stream *io,
10408c2ecf20Sopenharmony_ci			     struct rsnd_priv *priv)
10418c2ecf20Sopenharmony_ci{
10428c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
10438c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (!rsnd_ssi_is_parent(mod, io)) {
10468c2ecf20Sopenharmony_ci		ssi->byte_pos		= 0;
10478c2ecf20Sopenharmony_ci		ssi->byte_per_period	= runtime->period_size *
10488c2ecf20Sopenharmony_ci					  runtime->channels *
10498c2ecf20Sopenharmony_ci					  samples_to_bytes(runtime, 1);
10508c2ecf20Sopenharmony_ci		ssi->next_period_byte	= ssi->byte_per_period;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	return rsnd_ssi_init(mod, io, priv);
10548c2ecf20Sopenharmony_ci}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_cistatic int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
10578c2ecf20Sopenharmony_ci			    struct rsnd_dai_stream *io,
10588c2ecf20Sopenharmony_ci			    snd_pcm_uframes_t *pointer)
10598c2ecf20Sopenharmony_ci{
10608c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
10618c2ecf20Sopenharmony_ci	struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci	*pointer = bytes_to_frames(runtime, READ_ONCE(ssi->byte_pos));
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	return 0;
10668c2ecf20Sopenharmony_ci}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssi_pio_ops = {
10698c2ecf20Sopenharmony_ci	.name		= SSI_NAME,
10708c2ecf20Sopenharmony_ci	.probe		= rsnd_ssi_common_probe,
10718c2ecf20Sopenharmony_ci	.remove		= rsnd_ssi_common_remove,
10728c2ecf20Sopenharmony_ci	.init		= rsnd_ssi_pio_init,
10738c2ecf20Sopenharmony_ci	.quit		= rsnd_ssi_quit,
10748c2ecf20Sopenharmony_ci	.start		= rsnd_ssi_start,
10758c2ecf20Sopenharmony_ci	.stop		= rsnd_ssi_stop,
10768c2ecf20Sopenharmony_ci	.irq		= rsnd_ssi_irq,
10778c2ecf20Sopenharmony_ci	.pointer	= rsnd_ssi_pio_pointer,
10788c2ecf20Sopenharmony_ci	.pcm_new	= rsnd_ssi_pcm_new,
10798c2ecf20Sopenharmony_ci	.hw_params	= rsnd_ssi_hw_params,
10808c2ecf20Sopenharmony_ci	.get_status	= rsnd_ssi_get_status,
10818c2ecf20Sopenharmony_ci};
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_cistatic int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
10848c2ecf20Sopenharmony_ci			      struct rsnd_dai_stream *io,
10858c2ecf20Sopenharmony_ci			      struct rsnd_priv *priv)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	int ret;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	/*
10908c2ecf20Sopenharmony_ci	 * SSIP/SSIU/IRQ/DMA are not needed on
10918c2ecf20Sopenharmony_ci	 * SSI Multi secondaries
10928c2ecf20Sopenharmony_ci	 */
10938c2ecf20Sopenharmony_ci	if (rsnd_ssi_is_multi_secondary(mod, io))
10948c2ecf20Sopenharmony_ci		return 0;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	ret = rsnd_ssi_common_probe(mod, io, priv);
10978c2ecf20Sopenharmony_ci	if (ret)
10988c2ecf20Sopenharmony_ci		return ret;
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	/* SSI probe might be called many times in MUX multi path */
11018c2ecf20Sopenharmony_ci	ret = rsnd_dma_attach(io, mod, &io->dma);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	return ret;
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic int rsnd_ssi_fallback(struct rsnd_mod *mod,
11078c2ecf20Sopenharmony_ci			     struct rsnd_dai_stream *io,
11088c2ecf20Sopenharmony_ci			     struct rsnd_priv *priv)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	/*
11138c2ecf20Sopenharmony_ci	 * fallback to PIO
11148c2ecf20Sopenharmony_ci	 *
11158c2ecf20Sopenharmony_ci	 * SSI .probe might be called again.
11168c2ecf20Sopenharmony_ci	 * see
11178c2ecf20Sopenharmony_ci	 *	rsnd_rdai_continuance_probe()
11188c2ecf20Sopenharmony_ci	 */
11198c2ecf20Sopenharmony_ci	mod->ops = &rsnd_ssi_pio_ops;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	dev_info(dev, "%s fallback to PIO mode\n", rsnd_mod_name(mod));
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	return 0;
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_cistatic struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io,
11278c2ecf20Sopenharmony_ci					 struct rsnd_mod *mod)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
11308c2ecf20Sopenharmony_ci	int is_play = rsnd_io_is_play(io);
11318c2ecf20Sopenharmony_ci	char *name;
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	/*
11348c2ecf20Sopenharmony_ci	 * It should use "rcar_sound,ssiu" on DT.
11358c2ecf20Sopenharmony_ci	 * But, we need to keep compatibility for old version.
11368c2ecf20Sopenharmony_ci	 *
11378c2ecf20Sopenharmony_ci	 * If it has "rcar_sound.ssiu", it will be used.
11388c2ecf20Sopenharmony_ci	 * If not, "rcar_sound.ssi" will be used.
11398c2ecf20Sopenharmony_ci	 * see
11408c2ecf20Sopenharmony_ci	 *	rsnd_ssiu_dma_req()
11418c2ecf20Sopenharmony_ci	 *	rsnd_dma_of_path()
11428c2ecf20Sopenharmony_ci	 */
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	if (rsnd_ssi_use_busif(io))
11458c2ecf20Sopenharmony_ci		name = is_play ? "rxu" : "txu";
11468c2ecf20Sopenharmony_ci	else
11478c2ecf20Sopenharmony_ci		name = is_play ? "rx" : "tx";
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	return rsnd_dma_request_channel(rsnd_ssi_of_node(priv),
11508c2ecf20Sopenharmony_ci					mod, name);
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ssi_dma_ops = {
11548c2ecf20Sopenharmony_ci	.name		= SSI_NAME,
11558c2ecf20Sopenharmony_ci	.dma_req	= rsnd_ssi_dma_req,
11568c2ecf20Sopenharmony_ci	.probe		= rsnd_ssi_dma_probe,
11578c2ecf20Sopenharmony_ci	.remove		= rsnd_ssi_common_remove,
11588c2ecf20Sopenharmony_ci	.init		= rsnd_ssi_init,
11598c2ecf20Sopenharmony_ci	.quit		= rsnd_ssi_quit,
11608c2ecf20Sopenharmony_ci	.start		= rsnd_ssi_start,
11618c2ecf20Sopenharmony_ci	.stop		= rsnd_ssi_stop,
11628c2ecf20Sopenharmony_ci	.irq		= rsnd_ssi_irq,
11638c2ecf20Sopenharmony_ci	.pcm_new	= rsnd_ssi_pcm_new,
11648c2ecf20Sopenharmony_ci	.fallback	= rsnd_ssi_fallback,
11658c2ecf20Sopenharmony_ci	.hw_params	= rsnd_ssi_hw_params,
11668c2ecf20Sopenharmony_ci	.get_status	= rsnd_ssi_get_status,
11678c2ecf20Sopenharmony_ci};
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_cistatic int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
11708c2ecf20Sopenharmony_ci{
11718c2ecf20Sopenharmony_ci	return mod->ops == &rsnd_ssi_dma_ops;
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci/*
11758c2ecf20Sopenharmony_ci *		ssi mod function
11768c2ecf20Sopenharmony_ci */
11778c2ecf20Sopenharmony_cistatic void rsnd_ssi_connect(struct rsnd_mod *mod,
11788c2ecf20Sopenharmony_ci			     struct rsnd_dai_stream *io)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
11818c2ecf20Sopenharmony_ci	enum rsnd_mod_type types[] = {
11828c2ecf20Sopenharmony_ci		RSND_MOD_SSI,
11838c2ecf20Sopenharmony_ci		RSND_MOD_SSIM1,
11848c2ecf20Sopenharmony_ci		RSND_MOD_SSIM2,
11858c2ecf20Sopenharmony_ci		RSND_MOD_SSIM3,
11868c2ecf20Sopenharmony_ci	};
11878c2ecf20Sopenharmony_ci	enum rsnd_mod_type type;
11888c2ecf20Sopenharmony_ci	int i;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	/* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */
11918c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(types); i++) {
11928c2ecf20Sopenharmony_ci		type = types[i];
11938c2ecf20Sopenharmony_ci		if (!rsnd_io_to_mod(io, type)) {
11948c2ecf20Sopenharmony_ci			rsnd_dai_connect(mod, io, type);
11958c2ecf20Sopenharmony_ci			rsnd_rdai_channels_set(rdai, (i + 1) * 2);
11968c2ecf20Sopenharmony_ci			rsnd_rdai_ssi_lane_set(rdai, (i + 1));
11978c2ecf20Sopenharmony_ci			return;
11988c2ecf20Sopenharmony_ci		}
11998c2ecf20Sopenharmony_ci	}
12008c2ecf20Sopenharmony_ci}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_civoid rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
12038c2ecf20Sopenharmony_ci			    struct device_node *playback,
12048c2ecf20Sopenharmony_ci			    struct device_node *capture)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
12078c2ecf20Sopenharmony_ci	struct device_node *node;
12088c2ecf20Sopenharmony_ci	struct device_node *np;
12098c2ecf20Sopenharmony_ci	struct rsnd_mod *mod;
12108c2ecf20Sopenharmony_ci	int i;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	node = rsnd_ssi_of_node(priv);
12138c2ecf20Sopenharmony_ci	if (!node)
12148c2ecf20Sopenharmony_ci		return;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	i = 0;
12178c2ecf20Sopenharmony_ci	for_each_child_of_node(node, np) {
12188c2ecf20Sopenharmony_ci		mod = rsnd_ssi_mod_get(priv, i);
12198c2ecf20Sopenharmony_ci		if (np == playback)
12208c2ecf20Sopenharmony_ci			rsnd_ssi_connect(mod, &rdai->playback);
12218c2ecf20Sopenharmony_ci		if (np == capture)
12228c2ecf20Sopenharmony_ci			rsnd_ssi_connect(mod, &rdai->capture);
12238c2ecf20Sopenharmony_ci		i++;
12248c2ecf20Sopenharmony_ci	}
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	of_node_put(node);
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cistruct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv)))
12328c2ecf20Sopenharmony_ci		id = 0;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	return rsnd_mod_get(rsnd_ssi_get(priv, id));
12358c2ecf20Sopenharmony_ci}
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ciint __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	if (!mod)
12408c2ecf20Sopenharmony_ci		return 0;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	return !!(rsnd_flags_has(rsnd_mod_to_ssi(mod), RSND_SSI_CLK_PIN_SHARE));
12438c2ecf20Sopenharmony_ci}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ciint rsnd_ssi_probe(struct rsnd_priv *priv)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	struct device_node *node;
12488c2ecf20Sopenharmony_ci	struct device_node *np;
12498c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
12508c2ecf20Sopenharmony_ci	struct rsnd_mod_ops *ops;
12518c2ecf20Sopenharmony_ci	struct clk *clk;
12528c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi;
12538c2ecf20Sopenharmony_ci	char name[RSND_SSI_NAME_SIZE];
12548c2ecf20Sopenharmony_ci	int i, nr, ret;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	node = rsnd_ssi_of_node(priv);
12578c2ecf20Sopenharmony_ci	if (!node)
12588c2ecf20Sopenharmony_ci		return -EINVAL;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	nr = of_get_child_count(node);
12618c2ecf20Sopenharmony_ci	if (!nr) {
12628c2ecf20Sopenharmony_ci		ret = -EINVAL;
12638c2ecf20Sopenharmony_ci		goto rsnd_ssi_probe_done;
12648c2ecf20Sopenharmony_ci	}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	ssi	= devm_kcalloc(dev, nr, sizeof(*ssi), GFP_KERNEL);
12678c2ecf20Sopenharmony_ci	if (!ssi) {
12688c2ecf20Sopenharmony_ci		ret = -ENOMEM;
12698c2ecf20Sopenharmony_ci		goto rsnd_ssi_probe_done;
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	priv->ssi	= ssi;
12738c2ecf20Sopenharmony_ci	priv->ssi_nr	= nr;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	i = 0;
12768c2ecf20Sopenharmony_ci	for_each_child_of_node(node, np) {
12778c2ecf20Sopenharmony_ci		if (!of_device_is_available(np))
12788c2ecf20Sopenharmony_ci			goto skip;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci		ssi = rsnd_ssi_get(priv, i);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci		snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d",
12838c2ecf20Sopenharmony_ci			 SSI_NAME, i);
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci		clk = devm_clk_get(dev, name);
12868c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
12878c2ecf20Sopenharmony_ci			ret = PTR_ERR(clk);
12888c2ecf20Sopenharmony_ci			of_node_put(np);
12898c2ecf20Sopenharmony_ci			goto rsnd_ssi_probe_done;
12908c2ecf20Sopenharmony_ci		}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci		if (of_get_property(np, "shared-pin", NULL))
12938c2ecf20Sopenharmony_ci			rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE);
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci		if (of_get_property(np, "no-busif", NULL))
12968c2ecf20Sopenharmony_ci			rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci		ssi->irq = irq_of_parse_and_map(np, 0);
12998c2ecf20Sopenharmony_ci		if (!ssi->irq) {
13008c2ecf20Sopenharmony_ci			ret = -EINVAL;
13018c2ecf20Sopenharmony_ci			of_node_put(np);
13028c2ecf20Sopenharmony_ci			goto rsnd_ssi_probe_done;
13038c2ecf20Sopenharmony_ci		}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci		if (of_property_read_bool(np, "pio-transfer"))
13068c2ecf20Sopenharmony_ci			ops = &rsnd_ssi_pio_ops;
13078c2ecf20Sopenharmony_ci		else
13088c2ecf20Sopenharmony_ci			ops = &rsnd_ssi_dma_ops;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci		ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk,
13118c2ecf20Sopenharmony_ci				    RSND_MOD_SSI, i);
13128c2ecf20Sopenharmony_ci		if (ret) {
13138c2ecf20Sopenharmony_ci			of_node_put(np);
13148c2ecf20Sopenharmony_ci			goto rsnd_ssi_probe_done;
13158c2ecf20Sopenharmony_ci		}
13168c2ecf20Sopenharmony_ciskip:
13178c2ecf20Sopenharmony_ci		i++;
13188c2ecf20Sopenharmony_ci	}
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_ci	ret = 0;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_cirsnd_ssi_probe_done:
13238c2ecf20Sopenharmony_ci	of_node_put(node);
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	return ret;
13268c2ecf20Sopenharmony_ci}
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_civoid rsnd_ssi_remove(struct rsnd_priv *priv)
13298c2ecf20Sopenharmony_ci{
13308c2ecf20Sopenharmony_ci	struct rsnd_ssi *ssi;
13318c2ecf20Sopenharmony_ci	int i;
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	for_each_rsnd_ssi(ssi, priv, i) {
13348c2ecf20Sopenharmony_ci		rsnd_mod_quit(rsnd_mod_get(ssi));
13358c2ecf20Sopenharmony_ci	}
13368c2ecf20Sopenharmony_ci}
1337