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