1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // ctu.c
4*4882a593Smuzhiyun //
5*4882a593Smuzhiyun // Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "rsnd.h"
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define CTU_NAME_SIZE 16
10*4882a593Smuzhiyun #define CTU_NAME "ctu"
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun /*
13*4882a593Smuzhiyun * User needs to setup CTU by amixer, and its settings are
14*4882a593Smuzhiyun * based on below registers
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * CTUn_CPMDR : amixser set "CTU Pass"
17*4882a593Smuzhiyun * CTUn_SV0xR : amixser set "CTU SV0"
18*4882a593Smuzhiyun * CTUn_SV1xR : amixser set "CTU SV1"
19*4882a593Smuzhiyun * CTUn_SV2xR : amixser set "CTU SV2"
20*4882a593Smuzhiyun * CTUn_SV3xR : amixser set "CTU SV3"
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * [CTU Pass]
23*4882a593Smuzhiyun * 0000: default
24*4882a593Smuzhiyun * 0001: Connect input data of channel 0
25*4882a593Smuzhiyun * 0010: Connect input data of channel 1
26*4882a593Smuzhiyun * 0011: Connect input data of channel 2
27*4882a593Smuzhiyun * 0100: Connect input data of channel 3
28*4882a593Smuzhiyun * 0101: Connect input data of channel 4
29*4882a593Smuzhiyun * 0110: Connect input data of channel 5
30*4882a593Smuzhiyun * 0111: Connect input data of channel 6
31*4882a593Smuzhiyun * 1000: Connect input data of channel 7
32*4882a593Smuzhiyun * 1001: Connect calculated data by scale values of matrix row 0
33*4882a593Smuzhiyun * 1010: Connect calculated data by scale values of matrix row 1
34*4882a593Smuzhiyun * 1011: Connect calculated data by scale values of matrix row 2
35*4882a593Smuzhiyun * 1100: Connect calculated data by scale values of matrix row 3
36*4882a593Smuzhiyun *
37*4882a593Smuzhiyun * [CTU SVx]
38*4882a593Smuzhiyun * [Output0] = [SV00, SV01, SV02, SV03, SV04, SV05, SV06, SV07]
39*4882a593Smuzhiyun * [Output1] = [SV10, SV11, SV12, SV13, SV14, SV15, SV16, SV17]
40*4882a593Smuzhiyun * [Output2] = [SV20, SV21, SV22, SV23, SV24, SV25, SV26, SV27]
41*4882a593Smuzhiyun * [Output3] = [SV30, SV31, SV32, SV33, SV34, SV35, SV36, SV37]
42*4882a593Smuzhiyun * [Output4] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
43*4882a593Smuzhiyun * [Output5] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
44*4882a593Smuzhiyun * [Output6] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
45*4882a593Smuzhiyun * [Output7] = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
46*4882a593Smuzhiyun *
47*4882a593Smuzhiyun * [SVxx]
48*4882a593Smuzhiyun * Plus Minus
49*4882a593Smuzhiyun * value time dB value time dB
50*4882a593Smuzhiyun * -----------------------------------------------------------------------
51*4882a593Smuzhiyun * H'7F_FFFF 2 6 H'80_0000 2 6
52*4882a593Smuzhiyun * ...
53*4882a593Smuzhiyun * H'40_0000 1 0 H'C0_0000 1 0
54*4882a593Smuzhiyun * ...
55*4882a593Smuzhiyun * H'00_0001 2.38 x 10^-7 -132
56*4882a593Smuzhiyun * H'00_0000 0 Mute H'FF_FFFF 2.38 x 10^-7 -132
57*4882a593Smuzhiyun *
58*4882a593Smuzhiyun *
59*4882a593Smuzhiyun * Ex) Input ch -> Output ch
60*4882a593Smuzhiyun * 1ch -> 0ch
61*4882a593Smuzhiyun * 0ch -> 1ch
62*4882a593Smuzhiyun *
63*4882a593Smuzhiyun * amixer set "CTU Reset" on
64*4882a593Smuzhiyun * amixer set "CTU Pass" 9,10
65*4882a593Smuzhiyun * amixer set "CTU SV0" 0,4194304
66*4882a593Smuzhiyun * amixer set "CTU SV1" 4194304,0
67*4882a593Smuzhiyun * or
68*4882a593Smuzhiyun * amixer set "CTU Reset" on
69*4882a593Smuzhiyun * amixer set "CTU Pass" 2,1
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun struct rsnd_ctu {
73*4882a593Smuzhiyun struct rsnd_mod mod;
74*4882a593Smuzhiyun struct rsnd_kctrl_cfg_m pass;
75*4882a593Smuzhiyun struct rsnd_kctrl_cfg_m sv[4];
76*4882a593Smuzhiyun struct rsnd_kctrl_cfg_s reset;
77*4882a593Smuzhiyun int channels;
78*4882a593Smuzhiyun u32 flags;
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #define KCTRL_INITIALIZED (1 << 0)
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun #define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
84*4882a593Smuzhiyun #define for_each_rsnd_ctu(pos, priv, i) \
85*4882a593Smuzhiyun for ((i) = 0; \
86*4882a593Smuzhiyun ((i) < rsnd_ctu_nr(priv)) && \
87*4882a593Smuzhiyun ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \
88*4882a593Smuzhiyun i++)
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun #define rsnd_mod_to_ctu(_mod) \
91*4882a593Smuzhiyun container_of((_mod), struct rsnd_ctu, mod)
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id)
94*4882a593Smuzhiyun
rsnd_ctu_activation(struct rsnd_mod * mod)95*4882a593Smuzhiyun static void rsnd_ctu_activation(struct rsnd_mod *mod)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_SWRSR, 0);
98*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_SWRSR, 1);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
rsnd_ctu_halt(struct rsnd_mod * mod)101*4882a593Smuzhiyun static void rsnd_ctu_halt(struct rsnd_mod *mod)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_CTUIR, 1);
104*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_SWRSR, 0);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
rsnd_ctu_probe_(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)107*4882a593Smuzhiyun static int rsnd_ctu_probe_(struct rsnd_mod *mod,
108*4882a593Smuzhiyun struct rsnd_dai_stream *io,
109*4882a593Smuzhiyun struct rsnd_priv *priv)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun return rsnd_cmd_attach(io, rsnd_mod_id(mod));
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
rsnd_ctu_value_init(struct rsnd_dai_stream * io,struct rsnd_mod * mod)114*4882a593Smuzhiyun static void rsnd_ctu_value_init(struct rsnd_dai_stream *io,
115*4882a593Smuzhiyun struct rsnd_mod *mod)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
118*4882a593Smuzhiyun u32 cpmdr = 0;
119*4882a593Smuzhiyun u32 scmdr = 0;
120*4882a593Smuzhiyun int i, j;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun for (i = 0; i < RSND_MAX_CHANNELS; i++) {
123*4882a593Smuzhiyun u32 val = rsnd_kctrl_valm(ctu->pass, i);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun cpmdr |= val << (28 - (i * 4));
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if ((val > 0x8) && (scmdr < (val - 0x8)))
128*4882a593Smuzhiyun scmdr = val - 0x8;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_CTUIR, 1);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_ADINR, rsnd_runtime_channel_original(io));
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_CPMDR, cpmdr);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_SCMDR, scmdr);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun if (i >= scmdr)
142*4882a593Smuzhiyun break;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun for (j = 0; j < RSND_MAX_CHANNELS; j++)
145*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_SVxxR(i, j), rsnd_kctrl_valm(ctu->sv[i], j));
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun rsnd_mod_write(mod, CTU_CTUIR, 0);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
rsnd_ctu_value_reset(struct rsnd_dai_stream * io,struct rsnd_mod * mod)151*4882a593Smuzhiyun static void rsnd_ctu_value_reset(struct rsnd_dai_stream *io,
152*4882a593Smuzhiyun struct rsnd_mod *mod)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
155*4882a593Smuzhiyun int i;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun if (!rsnd_kctrl_vals(ctu->reset))
158*4882a593Smuzhiyun return;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun for (i = 0; i < RSND_MAX_CHANNELS; i++) {
161*4882a593Smuzhiyun rsnd_kctrl_valm(ctu->pass, i) = 0;
162*4882a593Smuzhiyun rsnd_kctrl_valm(ctu->sv[0], i) = 0;
163*4882a593Smuzhiyun rsnd_kctrl_valm(ctu->sv[1], i) = 0;
164*4882a593Smuzhiyun rsnd_kctrl_valm(ctu->sv[2], i) = 0;
165*4882a593Smuzhiyun rsnd_kctrl_valm(ctu->sv[3], i) = 0;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun rsnd_kctrl_vals(ctu->reset) = 0;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
rsnd_ctu_init(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)170*4882a593Smuzhiyun static int rsnd_ctu_init(struct rsnd_mod *mod,
171*4882a593Smuzhiyun struct rsnd_dai_stream *io,
172*4882a593Smuzhiyun struct rsnd_priv *priv)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun int ret;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun ret = rsnd_mod_power_on(mod);
177*4882a593Smuzhiyun if (ret < 0)
178*4882a593Smuzhiyun return ret;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun rsnd_ctu_activation(mod);
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun rsnd_ctu_value_init(io, mod);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
rsnd_ctu_quit(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct rsnd_priv * priv)187*4882a593Smuzhiyun static int rsnd_ctu_quit(struct rsnd_mod *mod,
188*4882a593Smuzhiyun struct rsnd_dai_stream *io,
189*4882a593Smuzhiyun struct rsnd_priv *priv)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun rsnd_ctu_halt(mod);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun rsnd_mod_power_off(mod);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun return 0;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
rsnd_ctu_pcm_new(struct rsnd_mod * mod,struct rsnd_dai_stream * io,struct snd_soc_pcm_runtime * rtd)198*4882a593Smuzhiyun static int rsnd_ctu_pcm_new(struct rsnd_mod *mod,
199*4882a593Smuzhiyun struct rsnd_dai_stream *io,
200*4882a593Smuzhiyun struct snd_soc_pcm_runtime *rtd)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun struct rsnd_ctu *ctu = rsnd_mod_to_ctu(mod);
203*4882a593Smuzhiyun int ret;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (rsnd_flags_has(ctu, KCTRL_INITIALIZED))
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* CTU Pass */
209*4882a593Smuzhiyun ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU Pass",
210*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
211*4882a593Smuzhiyun NULL,
212*4882a593Smuzhiyun &ctu->pass, RSND_MAX_CHANNELS,
213*4882a593Smuzhiyun 0xC);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* ROW0 */
216*4882a593Smuzhiyun ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV0",
217*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
218*4882a593Smuzhiyun NULL,
219*4882a593Smuzhiyun &ctu->sv[0], RSND_MAX_CHANNELS,
220*4882a593Smuzhiyun 0x00FFFFFF);
221*4882a593Smuzhiyun if (ret < 0)
222*4882a593Smuzhiyun return ret;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun /* ROW1 */
225*4882a593Smuzhiyun ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV1",
226*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
227*4882a593Smuzhiyun NULL,
228*4882a593Smuzhiyun &ctu->sv[1], RSND_MAX_CHANNELS,
229*4882a593Smuzhiyun 0x00FFFFFF);
230*4882a593Smuzhiyun if (ret < 0)
231*4882a593Smuzhiyun return ret;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun /* ROW2 */
234*4882a593Smuzhiyun ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV2",
235*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
236*4882a593Smuzhiyun NULL,
237*4882a593Smuzhiyun &ctu->sv[2], RSND_MAX_CHANNELS,
238*4882a593Smuzhiyun 0x00FFFFFF);
239*4882a593Smuzhiyun if (ret < 0)
240*4882a593Smuzhiyun return ret;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun /* ROW3 */
243*4882a593Smuzhiyun ret = rsnd_kctrl_new_m(mod, io, rtd, "CTU SV3",
244*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
245*4882a593Smuzhiyun NULL,
246*4882a593Smuzhiyun &ctu->sv[3], RSND_MAX_CHANNELS,
247*4882a593Smuzhiyun 0x00FFFFFF);
248*4882a593Smuzhiyun if (ret < 0)
249*4882a593Smuzhiyun return ret;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Reset */
252*4882a593Smuzhiyun ret = rsnd_kctrl_new_s(mod, io, rtd, "CTU Reset",
253*4882a593Smuzhiyun rsnd_kctrl_accept_anytime,
254*4882a593Smuzhiyun rsnd_ctu_value_reset,
255*4882a593Smuzhiyun &ctu->reset, 1);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun rsnd_flags_set(ctu, KCTRL_INITIALIZED);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun return ret;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
rsnd_ctu_id(struct rsnd_mod * mod)262*4882a593Smuzhiyun static int rsnd_ctu_id(struct rsnd_mod *mod)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun /*
265*4882a593Smuzhiyun * ctu00: -> 0, ctu01: -> 0, ctu02: -> 0, ctu03: -> 0
266*4882a593Smuzhiyun * ctu10: -> 1, ctu11: -> 1, ctu12: -> 1, ctu13: -> 1
267*4882a593Smuzhiyun */
268*4882a593Smuzhiyun return mod->id / 4;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
rsnd_ctu_id_sub(struct rsnd_mod * mod)271*4882a593Smuzhiyun static int rsnd_ctu_id_sub(struct rsnd_mod *mod)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun /*
274*4882a593Smuzhiyun * ctu00: -> 0, ctu01: -> 1, ctu02: -> 2, ctu03: -> 3
275*4882a593Smuzhiyun * ctu10: -> 0, ctu11: -> 1, ctu12: -> 2, ctu13: -> 3
276*4882a593Smuzhiyun */
277*4882a593Smuzhiyun return mod->id % 4;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun static struct rsnd_mod_ops rsnd_ctu_ops = {
281*4882a593Smuzhiyun .name = CTU_NAME,
282*4882a593Smuzhiyun .probe = rsnd_ctu_probe_,
283*4882a593Smuzhiyun .init = rsnd_ctu_init,
284*4882a593Smuzhiyun .quit = rsnd_ctu_quit,
285*4882a593Smuzhiyun .pcm_new = rsnd_ctu_pcm_new,
286*4882a593Smuzhiyun .get_status = rsnd_mod_get_status,
287*4882a593Smuzhiyun .id = rsnd_ctu_id,
288*4882a593Smuzhiyun .id_sub = rsnd_ctu_id_sub,
289*4882a593Smuzhiyun .id_cmd = rsnd_mod_id_raw,
290*4882a593Smuzhiyun };
291*4882a593Smuzhiyun
rsnd_ctu_mod_get(struct rsnd_priv * priv,int id)292*4882a593Smuzhiyun struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
295*4882a593Smuzhiyun id = 0;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun return rsnd_mod_get(rsnd_ctu_get(priv, id));
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
rsnd_ctu_probe(struct rsnd_priv * priv)300*4882a593Smuzhiyun int rsnd_ctu_probe(struct rsnd_priv *priv)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun struct device_node *node;
303*4882a593Smuzhiyun struct device_node *np;
304*4882a593Smuzhiyun struct device *dev = rsnd_priv_to_dev(priv);
305*4882a593Smuzhiyun struct rsnd_ctu *ctu;
306*4882a593Smuzhiyun struct clk *clk;
307*4882a593Smuzhiyun char name[CTU_NAME_SIZE];
308*4882a593Smuzhiyun int i, nr, ret;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun /* This driver doesn't support Gen1 at this point */
311*4882a593Smuzhiyun if (rsnd_is_gen1(priv))
312*4882a593Smuzhiyun return 0;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun node = rsnd_ctu_of_node(priv);
315*4882a593Smuzhiyun if (!node)
316*4882a593Smuzhiyun return 0; /* not used is not error */
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun nr = of_get_child_count(node);
319*4882a593Smuzhiyun if (!nr) {
320*4882a593Smuzhiyun ret = -EINVAL;
321*4882a593Smuzhiyun goto rsnd_ctu_probe_done;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun ctu = devm_kcalloc(dev, nr, sizeof(*ctu), GFP_KERNEL);
325*4882a593Smuzhiyun if (!ctu) {
326*4882a593Smuzhiyun ret = -ENOMEM;
327*4882a593Smuzhiyun goto rsnd_ctu_probe_done;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun priv->ctu_nr = nr;
331*4882a593Smuzhiyun priv->ctu = ctu;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun i = 0;
334*4882a593Smuzhiyun ret = 0;
335*4882a593Smuzhiyun for_each_child_of_node(node, np) {
336*4882a593Smuzhiyun ctu = rsnd_ctu_get(priv, i);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /*
339*4882a593Smuzhiyun * CTU00, CTU01, CTU02, CTU03 => CTU0
340*4882a593Smuzhiyun * CTU10, CTU11, CTU12, CTU13 => CTU1
341*4882a593Smuzhiyun */
342*4882a593Smuzhiyun snprintf(name, CTU_NAME_SIZE, "%s.%d",
343*4882a593Smuzhiyun CTU_NAME, i / 4);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun clk = devm_clk_get(dev, name);
346*4882a593Smuzhiyun if (IS_ERR(clk)) {
347*4882a593Smuzhiyun ret = PTR_ERR(clk);
348*4882a593Smuzhiyun of_node_put(np);
349*4882a593Smuzhiyun goto rsnd_ctu_probe_done;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops,
353*4882a593Smuzhiyun clk, RSND_MOD_CTU, i);
354*4882a593Smuzhiyun if (ret) {
355*4882a593Smuzhiyun of_node_put(np);
356*4882a593Smuzhiyun goto rsnd_ctu_probe_done;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun i++;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun rsnd_ctu_probe_done:
364*4882a593Smuzhiyun of_node_put(node);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun return ret;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
rsnd_ctu_remove(struct rsnd_priv * priv)369*4882a593Smuzhiyun void rsnd_ctu_remove(struct rsnd_priv *priv)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct rsnd_ctu *ctu;
372*4882a593Smuzhiyun int i;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun for_each_rsnd_ctu(ctu, priv, i) {
375*4882a593Smuzhiyun rsnd_mod_quit(rsnd_mod_get(ctu));
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun }
378