xref: /kernel/linux/linux-5.10/sound/soc/sh/rcar/ctu.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// ctu.c
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 CTU_NAME_SIZE	16
108c2ecf20Sopenharmony_ci#define CTU_NAME "ctu"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/*
138c2ecf20Sopenharmony_ci * User needs to setup CTU by amixer, and its settings are
148c2ecf20Sopenharmony_ci * based on below registers
158c2ecf20Sopenharmony_ci *
168c2ecf20Sopenharmony_ci * CTUn_CPMDR : amixser set "CTU Pass"
178c2ecf20Sopenharmony_ci * CTUn_SV0xR : amixser set "CTU SV0"
188c2ecf20Sopenharmony_ci * CTUn_SV1xR : amixser set "CTU SV1"
198c2ecf20Sopenharmony_ci * CTUn_SV2xR : amixser set "CTU SV2"
208c2ecf20Sopenharmony_ci * CTUn_SV3xR : amixser set "CTU SV3"
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * [CTU Pass]
238c2ecf20Sopenharmony_ci * 0000: default
248c2ecf20Sopenharmony_ci * 0001: Connect input data of channel 0
258c2ecf20Sopenharmony_ci * 0010: Connect input data of channel 1
268c2ecf20Sopenharmony_ci * 0011: Connect input data of channel 2
278c2ecf20Sopenharmony_ci * 0100: Connect input data of channel 3
288c2ecf20Sopenharmony_ci * 0101: Connect input data of channel 4
298c2ecf20Sopenharmony_ci * 0110: Connect input data of channel 5
308c2ecf20Sopenharmony_ci * 0111: Connect input data of channel 6
318c2ecf20Sopenharmony_ci * 1000: Connect input data of channel 7
328c2ecf20Sopenharmony_ci * 1001: Connect calculated data by scale values of matrix row 0
338c2ecf20Sopenharmony_ci * 1010: Connect calculated data by scale values of matrix row 1
348c2ecf20Sopenharmony_ci * 1011: Connect calculated data by scale values of matrix row 2
358c2ecf20Sopenharmony_ci * 1100: Connect calculated data by scale values of matrix row 3
368c2ecf20Sopenharmony_ci *
378c2ecf20Sopenharmony_ci * [CTU SVx]
388c2ecf20Sopenharmony_ci * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
398c2ecf20Sopenharmony_ci * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
408c2ecf20Sopenharmony_ci * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
418c2ecf20Sopenharmony_ci * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
428c2ecf20Sopenharmony_ci * [Output4] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
438c2ecf20Sopenharmony_ci * [Output5] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
448c2ecf20Sopenharmony_ci * [Output6] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
458c2ecf20Sopenharmony_ci * [Output7] = [ 0,   0,    0,    0,    0,    0,    0,    0   ]
468c2ecf20Sopenharmony_ci *
478c2ecf20Sopenharmony_ci * [SVxx]
488c2ecf20Sopenharmony_ci * Plus					Minus
498c2ecf20Sopenharmony_ci * value	time		dB	value		time		dB
508c2ecf20Sopenharmony_ci * -----------------------------------------------------------------------
518c2ecf20Sopenharmony_ci * H'7F_FFFF	2		6	H'80_0000	2		6
528c2ecf20Sopenharmony_ci * ...
538c2ecf20Sopenharmony_ci * H'40_0000	1		0	H'C0_0000	1		0
548c2ecf20Sopenharmony_ci * ...
558c2ecf20Sopenharmony_ci * H'00_0001	2.38 x 10^-7	-132
568c2ecf20Sopenharmony_ci * H'00_0000	0		Mute	H'FF_FFFF	2.38 x 10^-7	-132
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci *
598c2ecf20Sopenharmony_ci * Ex) Input ch -> Output ch
608c2ecf20Sopenharmony_ci *	1ch     ->  0ch
618c2ecf20Sopenharmony_ci *	0ch     ->  1ch
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci *	amixer set "CTU Reset" on
648c2ecf20Sopenharmony_ci *	amixer set "CTU Pass" 9,10
658c2ecf20Sopenharmony_ci *	amixer set "CTU SV0" 0,4194304
668c2ecf20Sopenharmony_ci *	amixer set "CTU SV1" 4194304,0
678c2ecf20Sopenharmony_ci * or
688c2ecf20Sopenharmony_ci *	amixer set "CTU Reset" on
698c2ecf20Sopenharmony_ci *	amixer set "CTU Pass" 2,1
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistruct rsnd_ctu {
738c2ecf20Sopenharmony_ci	struct rsnd_mod mod;
748c2ecf20Sopenharmony_ci	struct rsnd_kctrl_cfg_m pass;
758c2ecf20Sopenharmony_ci	struct rsnd_kctrl_cfg_m sv[4];
768c2ecf20Sopenharmony_ci	struct rsnd_kctrl_cfg_s reset;
778c2ecf20Sopenharmony_ci	int channels;
788c2ecf20Sopenharmony_ci	u32 flags;
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#define KCTRL_INITIALIZED	(1 << 0)
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
848c2ecf20Sopenharmony_ci#define for_each_rsnd_ctu(pos, priv, i)					\
858c2ecf20Sopenharmony_ci	for ((i) = 0;							\
868c2ecf20Sopenharmony_ci	     ((i) < rsnd_ctu_nr(priv)) &&				\
878c2ecf20Sopenharmony_ci		     ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);	\
888c2ecf20Sopenharmony_ci	     i++)
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define rsnd_mod_to_ctu(_mod)	\
918c2ecf20Sopenharmony_ci	container_of((_mod), struct rsnd_ctu, mod)
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic void rsnd_ctu_activation(struct rsnd_mod *mod)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_SWRSR, 0);
988c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_SWRSR, 1);
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic void rsnd_ctu_halt(struct rsnd_mod *mod)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_CTUIR, 1);
1048c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_SWRSR, 0);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int rsnd_ctu_probe_(struct rsnd_mod *mod,
1088c2ecf20Sopenharmony_ci			   struct rsnd_dai_stream *io,
1098c2ecf20Sopenharmony_ci			   struct rsnd_priv *priv)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return rsnd_cmd_attach(io, rsnd_mod_id(mod));
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
1158c2ecf20Sopenharmony_ci			       struct rsnd_mod *mod)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
1188c2ecf20Sopenharmony_ci	u32 cpmdr = 0;
1198c2ecf20Sopenharmony_ci	u32 scmdr = 0;
1208c2ecf20Sopenharmony_ci	int i, j;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	for (i = 0; i < RSND_MAX_CHANNELS; i++) {
1238c2ecf20Sopenharmony_ci		u32 val = rsnd_kctrl_valm(ctu->pass, i);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		cpmdr |= val << (28 - (i * 4));
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		if ((val > 0x8) && (scmdr < (val - 0x8)))
1288c2ecf20Sopenharmony_ci			scmdr = val - 0x8;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_CTUIR, 1);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_SCMDR, scmdr);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		if (i >= scmdr)
1428c2ecf20Sopenharmony_ci			break;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		for (j = 0; j < RSND_MAX_CHANNELS; j++)
1458c2ecf20Sopenharmony_ci			rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	rsnd_mod_write(mod, CTU_CTUIR, 0);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
1528c2ecf20Sopenharmony_ci				 struct rsnd_mod *mod)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
1558c2ecf20Sopenharmony_ci	int i;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	if (!rsnd_kctrl_vals(ctu->reset))
1588c2ecf20Sopenharmony_ci		return;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	for (i = 0; i < RSND_MAX_CHANNELS; i++) {
1618c2ecf20Sopenharmony_ci		rsnd_kctrl_valm(ctu->pass, i) = 0;
1628c2ecf20Sopenharmony_ci		rsnd_kctrl_valm(ctu->sv[0],  i) = 0;
1638c2ecf20Sopenharmony_ci		rsnd_kctrl_valm(ctu->sv[1],  i) = 0;
1648c2ecf20Sopenharmony_ci		rsnd_kctrl_valm(ctu->sv[2],  i) = 0;
1658c2ecf20Sopenharmony_ci		rsnd_kctrl_valm(ctu->sv[3],  i) = 0;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci	rsnd_kctrl_vals(ctu->reset) = 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_cistatic int rsnd_ctu_init(struct rsnd_mod *mod,
1718c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
1728c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	int ret;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	ret = rsnd_mod_power_on(mod);
1778c2ecf20Sopenharmony_ci	if (ret < 0)
1788c2ecf20Sopenharmony_ci		return ret;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	rsnd_ctu_activation(mod);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	rsnd_ctu_value_init(io, mod);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int rsnd_ctu_quit(struct rsnd_mod *mod,
1888c2ecf20Sopenharmony_ci			 struct rsnd_dai_stream *io,
1898c2ecf20Sopenharmony_ci			 struct rsnd_priv *priv)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	rsnd_ctu_halt(mod);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	rsnd_mod_power_off(mod);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
1998c2ecf20Sopenharmony_ci			    struct rsnd_dai_stream *io,
2008c2ecf20Sopenharmony_ci			    struct snd_soc_pcm_runtime *rtd)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
2038c2ecf20Sopenharmony_ci	int ret;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
2068c2ecf20Sopenharmony_ci		return 0;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* CTU Pass */
2098c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
2108c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2118c2ecf20Sopenharmony_ci			       NULL,
2128c2ecf20Sopenharmony_ci			       &ctu->pass, RSND_MAX_CHANNELS,
2138c2ecf20Sopenharmony_ci			       0xC);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* ROW0 */
2168c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
2178c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2188c2ecf20Sopenharmony_ci			       NULL,
2198c2ecf20Sopenharmony_ci			       &ctu->sv[0], RSND_MAX_CHANNELS,
2208c2ecf20Sopenharmony_ci			       0x00FFFFFF);
2218c2ecf20Sopenharmony_ci	if (ret < 0)
2228c2ecf20Sopenharmony_ci		return ret;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* ROW1 */
2258c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
2268c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2278c2ecf20Sopenharmony_ci			       NULL,
2288c2ecf20Sopenharmony_ci			       &ctu->sv[1], RSND_MAX_CHANNELS,
2298c2ecf20Sopenharmony_ci			       0x00FFFFFF);
2308c2ecf20Sopenharmony_ci	if (ret < 0)
2318c2ecf20Sopenharmony_ci		return ret;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* ROW2 */
2348c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
2358c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2368c2ecf20Sopenharmony_ci			       NULL,
2378c2ecf20Sopenharmony_ci			       &ctu->sv[2], RSND_MAX_CHANNELS,
2388c2ecf20Sopenharmony_ci			       0x00FFFFFF);
2398c2ecf20Sopenharmony_ci	if (ret < 0)
2408c2ecf20Sopenharmony_ci		return ret;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	/* ROW3 */
2438c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
2448c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2458c2ecf20Sopenharmony_ci			       NULL,
2468c2ecf20Sopenharmony_ci			       &ctu->sv[3], RSND_MAX_CHANNELS,
2478c2ecf20Sopenharmony_ci			       0x00FFFFFF);
2488c2ecf20Sopenharmony_ci	if (ret < 0)
2498c2ecf20Sopenharmony_ci		return ret;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* Reset */
2528c2ecf20Sopenharmony_ci	ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
2538c2ecf20Sopenharmony_ci			       rsnd_kctrl_accept_anytime,
2548c2ecf20Sopenharmony_ci			       rsnd_ctu_value_reset,
2558c2ecf20Sopenharmony_ci			       &ctu->reset, 1);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	rsnd_flags_set(ctu, KCTRL_INITIALIZED);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return ret;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic int rsnd_ctu_id(struct rsnd_mod *mod)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	/*
2658c2ecf20Sopenharmony_ci	 * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
2668c2ecf20Sopenharmony_ci	 * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
2678c2ecf20Sopenharmony_ci	 */
2688c2ecf20Sopenharmony_ci	return mod->id / 4;
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic int rsnd_ctu_id_sub(struct rsnd_mod *mod)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	/*
2748c2ecf20Sopenharmony_ci	 * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
2758c2ecf20Sopenharmony_ci	 * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
2768c2ecf20Sopenharmony_ci	 */
2778c2ecf20Sopenharmony_ci	return mod->id % 4;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_ctu_ops = {
2818c2ecf20Sopenharmony_ci	.name		= CTU_NAME,
2828c2ecf20Sopenharmony_ci	.probe		= rsnd_ctu_probe_,
2838c2ecf20Sopenharmony_ci	.init		= rsnd_ctu_init,
2848c2ecf20Sopenharmony_ci	.quit		= rsnd_ctu_quit,
2858c2ecf20Sopenharmony_ci	.pcm_new	= rsnd_ctu_pcm_new,
2868c2ecf20Sopenharmony_ci	.get_status	= rsnd_mod_get_status,
2878c2ecf20Sopenharmony_ci	.id		= rsnd_ctu_id,
2888c2ecf20Sopenharmony_ci	.id_sub		= rsnd_ctu_id_sub,
2898c2ecf20Sopenharmony_ci	.id_cmd		= rsnd_mod_id_raw,
2908c2ecf20Sopenharmony_ci};
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistruct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
2958c2ecf20Sopenharmony_ci		id = 0;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	return rsnd_mod_get(rsnd_ctu_get(priv, id));
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ciint rsnd_ctu_probe(struct rsnd_priv *priv)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct device_node *node;
3038c2ecf20Sopenharmony_ci	struct device_node *np;
3048c2ecf20Sopenharmony_ci	struct device *dev = rsnd_priv_to_dev(priv);
3058c2ecf20Sopenharmony_ci	struct rsnd_ctu *ctu;
3068c2ecf20Sopenharmony_ci	struct clk *clk;
3078c2ecf20Sopenharmony_ci	char name[CTU_NAME_SIZE];
3088c2ecf20Sopenharmony_ci	int i, nr, ret;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* This driver doesn't support Gen1 at this point */
3118c2ecf20Sopenharmony_ci	if (rsnd_is_gen1(priv))
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	node = rsnd_ctu_of_node(priv);
3158c2ecf20Sopenharmony_ci	if (!node)
3168c2ecf20Sopenharmony_ci		return 0; /* not used is not error */
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	nr = of_get_child_count(node);
3198c2ecf20Sopenharmony_ci	if (!nr) {
3208c2ecf20Sopenharmony_ci		ret = -EINVAL;
3218c2ecf20Sopenharmony_ci		goto rsnd_ctu_probe_done;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL);
3258c2ecf20Sopenharmony_ci	if (!ctu) {
3268c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3278c2ecf20Sopenharmony_ci		goto rsnd_ctu_probe_done;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	priv->ctu_nr	= nr;
3318c2ecf20Sopenharmony_ci	priv->ctu	= ctu;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	i = 0;
3348c2ecf20Sopenharmony_ci	ret = 0;
3358c2ecf20Sopenharmony_ci	for_each_child_of_node(node, np) {
3368c2ecf20Sopenharmony_ci		ctu = rsnd_ctu_get(priv, i);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		/*
3398c2ecf20Sopenharmony_ci		 * CTU00, CTU01, CTU02, CTU03 => CTU0
3408c2ecf20Sopenharmony_ci		 * CTU10, CTU11, CTU12, CTU13 => CTU1
3418c2ecf20Sopenharmony_ci		 */
3428c2ecf20Sopenharmony_ci		snprintf(name, CTU_NAME_SIZE, "%s.%d",
3438c2ecf20Sopenharmony_ci			 CTU_NAME, i / 4);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		clk = devm_clk_get(dev, name);
3468c2ecf20Sopenharmony_ci		if (IS_ERR(clk)) {
3478c2ecf20Sopenharmony_ci			ret = PTR_ERR(clk);
3488c2ecf20Sopenharmony_ci			of_node_put(np);
3498c2ecf20Sopenharmony_ci			goto rsnd_ctu_probe_done;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
3538c2ecf20Sopenharmony_ci				    clk, RSND_MOD_CTU, i);
3548c2ecf20Sopenharmony_ci		if (ret) {
3558c2ecf20Sopenharmony_ci			of_node_put(np);
3568c2ecf20Sopenharmony_ci			goto rsnd_ctu_probe_done;
3578c2ecf20Sopenharmony_ci		}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		i++;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cirsnd_ctu_probe_done:
3648c2ecf20Sopenharmony_ci	of_node_put(node);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return ret;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_civoid rsnd_ctu_remove(struct rsnd_priv *priv)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	struct rsnd_ctu *ctu;
3728c2ecf20Sopenharmony_ci	int i;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	for_each_rsnd_ctu(ctu, priv, i) {
3758c2ecf20Sopenharmony_ci		rsnd_mod_quit(rsnd_mod_get(ctu));
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci}
378