18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// mix.c 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci/* 88c2ecf20Sopenharmony_ci * CTUn MIXn 98c2ecf20Sopenharmony_ci * +------+ +------+ 108c2ecf20Sopenharmony_ci * [SRC3 / SRC6] -> |CTU n0| -> [MIX n0| -> 118c2ecf20Sopenharmony_ci * [SRC4 / SRC9] -> |CTU n1| -> [MIX n1| -> 128c2ecf20Sopenharmony_ci * [SRC0 / SRC1] -> |CTU n2| -> [MIX n2| -> 138c2ecf20Sopenharmony_ci * [SRC2 / SRC5] -> |CTU n3| -> [MIX n3| -> 148c2ecf20Sopenharmony_ci * +------+ +------+ 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * ex) 178c2ecf20Sopenharmony_ci * DAI0 : playback = <&src0 &ctu02 &mix0 &dvc0 &ssi0>; 188c2ecf20Sopenharmony_ci * DAI1 : playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * MIX Volume 218c2ecf20Sopenharmony_ci * amixer set "MIX",0 100% // DAI0 Volume 228c2ecf20Sopenharmony_ci * amixer set "MIX",1 100% // DAI1 Volume 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Volume Ramp 258c2ecf20Sopenharmony_ci * amixer set "MIX Ramp Up Rate" "0.125 dB/1 step" 268c2ecf20Sopenharmony_ci * amixer set "MIX Ramp Down Rate" "4 dB/1 step" 278c2ecf20Sopenharmony_ci * amixer set "MIX Ramp" on 288c2ecf20Sopenharmony_ci * aplay xxx.wav & 298c2ecf20Sopenharmony_ci * amixer set "MIX",0 80% // DAI0 Volume Down 308c2ecf20Sopenharmony_ci * amixer set "MIX",1 100% // DAI1 Volume Up 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "rsnd.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define MIX_NAME_SIZE 16 368c2ecf20Sopenharmony_ci#define MIX_NAME "mix" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct rsnd_mix { 398c2ecf20Sopenharmony_ci struct rsnd_mod mod; 408c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s volumeA; /* MDBAR */ 418c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s volumeB; /* MDBBR */ 428c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s volumeC; /* MDBCR */ 438c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s volumeD; /* MDBDR */ 448c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ 458c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ 468c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s rdw; /* Ramp Rate Down */ 478c2ecf20Sopenharmony_ci u32 flags; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define ONCE_KCTRL_INITIALIZED (1 << 0) 518c2ecf20Sopenharmony_ci#define HAS_VOLA (1 << 1) 528c2ecf20Sopenharmony_ci#define HAS_VOLB (1 << 2) 538c2ecf20Sopenharmony_ci#define HAS_VOLC (1 << 3) 548c2ecf20Sopenharmony_ci#define HAS_VOLD (1 << 4) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define VOL_MAX 0x3ff 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define rsnd_mod_to_mix(_mod) \ 598c2ecf20Sopenharmony_ci container_of((_mod), struct rsnd_mix, mod) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) 628c2ecf20Sopenharmony_ci#define rsnd_mix_nr(priv) ((priv)->mix_nr) 638c2ecf20Sopenharmony_ci#define for_each_rsnd_mix(pos, priv, i) \ 648c2ecf20Sopenharmony_ci for ((i) = 0; \ 658c2ecf20Sopenharmony_ci ((i) < rsnd_mix_nr(priv)) && \ 668c2ecf20Sopenharmony_ci ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ 678c2ecf20Sopenharmony_ci i++) 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void rsnd_mix_activation(struct rsnd_mod *mod) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_SWRSR, 0); 728c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_SWRSR, 1); 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic void rsnd_mix_halt(struct rsnd_mod *mod) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MIXIR, 1); 788c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_SWRSR, 0); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define rsnd_mix_get_vol(mix, X) \ 828c2ecf20Sopenharmony_ci rsnd_flags_has(mix, HAS_VOL##X) ? \ 838c2ecf20Sopenharmony_ci (VOL_MAX - rsnd_kctrl_vals(mix->volume##X)) : 0 848c2ecf20Sopenharmony_cistatic void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, 858c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 888c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 898c2ecf20Sopenharmony_ci struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 908c2ecf20Sopenharmony_ci u32 volA = rsnd_mix_get_vol(mix, A); 918c2ecf20Sopenharmony_ci u32 volB = rsnd_mix_get_vol(mix, B); 928c2ecf20Sopenharmony_ci u32 volC = rsnd_mix_get_vol(mix, C); 938c2ecf20Sopenharmony_ci u32 volD = rsnd_mix_get_vol(mix, D); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci dev_dbg(dev, "MIX A/B/C/D = %02x/%02x/%02x/%02x\n", 968c2ecf20Sopenharmony_ci volA, volB, volC, volD); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBAR, volA); 998c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBBR, volB); 1008c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBCR, volC); 1018c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBDR, volD); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void rsnd_mix_volume_init(struct rsnd_dai_stream *io, 1058c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MIXIR, 1); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* General Information */ 1128c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_ADINR, rsnd_runtime_channel_after_ctu(io)); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* volume step */ 1158c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MIXMR, rsnd_kctrl_vals(mix->ren)); 1168c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MVPDR, rsnd_kctrl_vals(mix->rup) << 8 | 1178c2ecf20Sopenharmony_ci rsnd_kctrl_vals(mix->rdw)); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* common volume parameter */ 1208c2ecf20Sopenharmony_ci rsnd_mix_volume_parameter(io, mod); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MIXIR, 0); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic void rsnd_mix_volume_update(struct rsnd_dai_stream *io, 1268c2ecf20Sopenharmony_ci struct rsnd_mod *mod) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci /* Disable MIX dB setting */ 1298c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBER, 0); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* common volume parameter */ 1328c2ecf20Sopenharmony_ci rsnd_mix_volume_parameter(io, mod); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Enable MIX dB setting */ 1358c2ecf20Sopenharmony_ci rsnd_mod_write(mod, MIX_MDBER, 1); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int rsnd_mix_probe_(struct rsnd_mod *mod, 1398c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1408c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci return rsnd_cmd_attach(io, rsnd_mod_id(mod)); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int rsnd_mix_init(struct rsnd_mod *mod, 1468c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1478c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci int ret; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci ret = rsnd_mod_power_on(mod); 1528c2ecf20Sopenharmony_ci if (ret < 0) 1538c2ecf20Sopenharmony_ci return ret; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci rsnd_mix_activation(mod); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci rsnd_mix_volume_init(io, mod); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci rsnd_mix_volume_update(io, mod); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int rsnd_mix_quit(struct rsnd_mod *mod, 1658c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1668c2ecf20Sopenharmony_ci struct rsnd_priv *priv) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci rsnd_mix_halt(mod); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci rsnd_mod_power_off(mod); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int rsnd_mix_pcm_new(struct rsnd_mod *mod, 1768c2ecf20Sopenharmony_ci struct rsnd_dai_stream *io, 1778c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct rsnd_priv *priv = rsnd_mod_to_priv(mod); 1808c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 1818c2ecf20Sopenharmony_ci struct rsnd_mix *mix = rsnd_mod_to_mix(mod); 1828c2ecf20Sopenharmony_ci struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); 1838c2ecf20Sopenharmony_ci struct rsnd_kctrl_cfg_s *volume; 1848c2ecf20Sopenharmony_ci int ret; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (rsnd_mod_id(src_mod)) { 1878c2ecf20Sopenharmony_ci case 3: 1888c2ecf20Sopenharmony_ci case 6: /* MDBAR */ 1898c2ecf20Sopenharmony_ci volume = &mix->volumeA; 1908c2ecf20Sopenharmony_ci rsnd_flags_set(mix, HAS_VOLA); 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci case 4: 1938c2ecf20Sopenharmony_ci case 9: /* MDBBR */ 1948c2ecf20Sopenharmony_ci volume = &mix->volumeB; 1958c2ecf20Sopenharmony_ci rsnd_flags_set(mix, HAS_VOLB); 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case 0: 1988c2ecf20Sopenharmony_ci case 1: /* MDBCR */ 1998c2ecf20Sopenharmony_ci volume = &mix->volumeC; 2008c2ecf20Sopenharmony_ci rsnd_flags_set(mix, HAS_VOLC); 2018c2ecf20Sopenharmony_ci break; 2028c2ecf20Sopenharmony_ci case 2: 2038c2ecf20Sopenharmony_ci case 5: /* MDBDR */ 2048c2ecf20Sopenharmony_ci volume = &mix->volumeD; 2058c2ecf20Sopenharmony_ci rsnd_flags_set(mix, HAS_VOLD); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci default: 2088c2ecf20Sopenharmony_ci dev_err(dev, "unknown SRC is connected\n"); 2098c2ecf20Sopenharmony_ci return -EINVAL; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* Volume */ 2138c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_s(mod, io, rtd, 2148c2ecf20Sopenharmony_ci "MIX Playback Volume", 2158c2ecf20Sopenharmony_ci rsnd_kctrl_accept_anytime, 2168c2ecf20Sopenharmony_ci rsnd_mix_volume_update, 2178c2ecf20Sopenharmony_ci volume, VOL_MAX); 2188c2ecf20Sopenharmony_ci if (ret < 0) 2198c2ecf20Sopenharmony_ci return ret; 2208c2ecf20Sopenharmony_ci rsnd_kctrl_vals(*volume) = VOL_MAX; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (rsnd_flags_has(mix, ONCE_KCTRL_INITIALIZED)) 2238c2ecf20Sopenharmony_ci return ret; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Ramp */ 2268c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_s(mod, io, rtd, 2278c2ecf20Sopenharmony_ci "MIX Ramp Switch", 2288c2ecf20Sopenharmony_ci rsnd_kctrl_accept_anytime, 2298c2ecf20Sopenharmony_ci rsnd_mix_volume_update, 2308c2ecf20Sopenharmony_ci &mix->ren, 1); 2318c2ecf20Sopenharmony_ci if (ret < 0) 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_e(mod, io, rtd, 2358c2ecf20Sopenharmony_ci "MIX Ramp Up Rate", 2368c2ecf20Sopenharmony_ci rsnd_kctrl_accept_anytime, 2378c2ecf20Sopenharmony_ci rsnd_mix_volume_update, 2388c2ecf20Sopenharmony_ci &mix->rup, 2398c2ecf20Sopenharmony_ci volume_ramp_rate, 2408c2ecf20Sopenharmony_ci VOLUME_RAMP_MAX_MIX); 2418c2ecf20Sopenharmony_ci if (ret < 0) 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = rsnd_kctrl_new_e(mod, io, rtd, 2458c2ecf20Sopenharmony_ci "MIX Ramp Down Rate", 2468c2ecf20Sopenharmony_ci rsnd_kctrl_accept_anytime, 2478c2ecf20Sopenharmony_ci rsnd_mix_volume_update, 2488c2ecf20Sopenharmony_ci &mix->rdw, 2498c2ecf20Sopenharmony_ci volume_ramp_rate, 2508c2ecf20Sopenharmony_ci VOLUME_RAMP_MAX_MIX); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci rsnd_flags_set(mix, ONCE_KCTRL_INITIALIZED); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return ret; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct rsnd_mod_ops rsnd_mix_ops = { 2588c2ecf20Sopenharmony_ci .name = MIX_NAME, 2598c2ecf20Sopenharmony_ci .probe = rsnd_mix_probe_, 2608c2ecf20Sopenharmony_ci .init = rsnd_mix_init, 2618c2ecf20Sopenharmony_ci .quit = rsnd_mix_quit, 2628c2ecf20Sopenharmony_ci .pcm_new = rsnd_mix_pcm_new, 2638c2ecf20Sopenharmony_ci .get_status = rsnd_mod_get_status, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistruct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) 2698c2ecf20Sopenharmony_ci id = 0; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci return rsnd_mod_get(rsnd_mix_get(priv, id)); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ciint rsnd_mix_probe(struct rsnd_priv *priv) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct device_node *node; 2778c2ecf20Sopenharmony_ci struct device_node *np; 2788c2ecf20Sopenharmony_ci struct device *dev = rsnd_priv_to_dev(priv); 2798c2ecf20Sopenharmony_ci struct rsnd_mix *mix; 2808c2ecf20Sopenharmony_ci struct clk *clk; 2818c2ecf20Sopenharmony_ci char name[MIX_NAME_SIZE]; 2828c2ecf20Sopenharmony_ci int i, nr, ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* This driver doesn't support Gen1 at this point */ 2858c2ecf20Sopenharmony_ci if (rsnd_is_gen1(priv)) 2868c2ecf20Sopenharmony_ci return 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci node = rsnd_mix_of_node(priv); 2898c2ecf20Sopenharmony_ci if (!node) 2908c2ecf20Sopenharmony_ci return 0; /* not used is not error */ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci nr = of_get_child_count(node); 2938c2ecf20Sopenharmony_ci if (!nr) { 2948c2ecf20Sopenharmony_ci ret = -EINVAL; 2958c2ecf20Sopenharmony_ci goto rsnd_mix_probe_done; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci mix = devm_kcalloc(dev, nr, sizeof(*mix), GFP_KERNEL); 2998c2ecf20Sopenharmony_ci if (!mix) { 3008c2ecf20Sopenharmony_ci ret = -ENOMEM; 3018c2ecf20Sopenharmony_ci goto rsnd_mix_probe_done; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci priv->mix_nr = nr; 3058c2ecf20Sopenharmony_ci priv->mix = mix; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci i = 0; 3088c2ecf20Sopenharmony_ci ret = 0; 3098c2ecf20Sopenharmony_ci for_each_child_of_node(node, np) { 3108c2ecf20Sopenharmony_ci mix = rsnd_mix_get(priv, i); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci snprintf(name, MIX_NAME_SIZE, "%s.%d", 3138c2ecf20Sopenharmony_ci MIX_NAME, i); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci clk = devm_clk_get(dev, name); 3168c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 3178c2ecf20Sopenharmony_ci ret = PTR_ERR(clk); 3188c2ecf20Sopenharmony_ci of_node_put(np); 3198c2ecf20Sopenharmony_ci goto rsnd_mix_probe_done; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, 3238c2ecf20Sopenharmony_ci clk, RSND_MOD_MIX, i); 3248c2ecf20Sopenharmony_ci if (ret) { 3258c2ecf20Sopenharmony_ci of_node_put(np); 3268c2ecf20Sopenharmony_ci goto rsnd_mix_probe_done; 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci i++; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cirsnd_mix_probe_done: 3338c2ecf20Sopenharmony_ci of_node_put(node); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return ret; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_civoid rsnd_mix_remove(struct rsnd_priv *priv) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct rsnd_mix *mix; 3418c2ecf20Sopenharmony_ci int i; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci for_each_rsnd_mix(mix, priv, i) { 3448c2ecf20Sopenharmony_ci rsnd_mod_quit(rsnd_mod_get(mix)); 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci} 347