1c087a94bSLad Prabhakar // SPDX-License-Identifier: GPL-2.0
2c087a94bSLad Prabhakar //
3c087a94bSLad Prabhakar // Helper routines for R-Car sound ADG.
4c087a94bSLad Prabhakar //
5c087a94bSLad Prabhakar // Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6c087a94bSLad Prabhakar #include <linux/clk-provider.h>
7c087a94bSLad Prabhakar #include <linux/clkdev.h>
8c087a94bSLad Prabhakar #include "rsnd.h"
9c087a94bSLad Prabhakar
10c087a94bSLad Prabhakar #define CLKA 0
11c087a94bSLad Prabhakar #define CLKB 1
12c087a94bSLad Prabhakar #define CLKC 2
13c087a94bSLad Prabhakar #define CLKI 3
14c087a94bSLad Prabhakar #define CLKINMAX 4
15c087a94bSLad Prabhakar
16c087a94bSLad Prabhakar #define CLKOUT 0
17c087a94bSLad Prabhakar #define CLKOUT1 1
18c087a94bSLad Prabhakar #define CLKOUT2 2
19c087a94bSLad Prabhakar #define CLKOUT3 3
20c087a94bSLad Prabhakar #define CLKOUTMAX 4
21c087a94bSLad Prabhakar
22c087a94bSLad Prabhakar #define BRRx_MASK(x) (0x3FF & x)
23c087a94bSLad Prabhakar
24c087a94bSLad Prabhakar static struct rsnd_mod_ops adg_ops = {
25c087a94bSLad Prabhakar .name = "adg",
26c087a94bSLad Prabhakar };
27c087a94bSLad Prabhakar
28c087a94bSLad Prabhakar #define ADG_HZ_441 0
29c087a94bSLad Prabhakar #define ADG_HZ_48 1
30c087a94bSLad Prabhakar #define ADG_HZ_SIZE 2
31c087a94bSLad Prabhakar
32c087a94bSLad Prabhakar struct rsnd_adg {
33c087a94bSLad Prabhakar struct clk *clkin[CLKINMAX];
34c087a94bSLad Prabhakar struct clk *clkout[CLKOUTMAX];
35c087a94bSLad Prabhakar struct clk *null_clk;
36c087a94bSLad Prabhakar struct clk_onecell_data onecell;
37c087a94bSLad Prabhakar struct rsnd_mod mod;
38c087a94bSLad Prabhakar int clkin_rate[CLKINMAX];
39c087a94bSLad Prabhakar int clkin_size;
40c087a94bSLad Prabhakar int clkout_size;
41c087a94bSLad Prabhakar u32 ckr;
42c087a94bSLad Prabhakar u32 brga;
43c087a94bSLad Prabhakar u32 brgb;
44c087a94bSLad Prabhakar
45c087a94bSLad Prabhakar int brg_rate[ADG_HZ_SIZE]; /* BRGA / BRGB */
46c087a94bSLad Prabhakar };
47c087a94bSLad Prabhakar
48c087a94bSLad Prabhakar #define for_each_rsnd_clkin(pos, adg, i) \
49c087a94bSLad Prabhakar for (i = 0; \
50c087a94bSLad Prabhakar (i < adg->clkin_size) && \
51c087a94bSLad Prabhakar ((pos) = adg->clkin[i]); \
52c087a94bSLad Prabhakar i++)
53c087a94bSLad Prabhakar #define for_each_rsnd_clkout(pos, adg, i) \
54c087a94bSLad Prabhakar for (i = 0; \
55c087a94bSLad Prabhakar (i < adg->clkout_size) && \
56c087a94bSLad Prabhakar ((pos) = adg->clkout[i]); \
57c087a94bSLad Prabhakar i++)
58c087a94bSLad Prabhakar #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
59c087a94bSLad Prabhakar
60c087a94bSLad Prabhakar static const char * const clkin_name_gen4[] = {
61c087a94bSLad Prabhakar [CLKA] = "clkin",
62c087a94bSLad Prabhakar };
63c087a94bSLad Prabhakar
64c087a94bSLad Prabhakar static const char * const clkin_name_gen2[] = {
65c087a94bSLad Prabhakar [CLKA] = "clk_a",
66c087a94bSLad Prabhakar [CLKB] = "clk_b",
67c087a94bSLad Prabhakar [CLKC] = "clk_c",
68c087a94bSLad Prabhakar [CLKI] = "clk_i",
69c087a94bSLad Prabhakar };
70c087a94bSLad Prabhakar
71c087a94bSLad Prabhakar static const char * const clkout_name_gen2[] = {
72c087a94bSLad Prabhakar [CLKOUT] = "audio_clkout",
73c087a94bSLad Prabhakar [CLKOUT1] = "audio_clkout1",
74c087a94bSLad Prabhakar [CLKOUT2] = "audio_clkout2",
75c087a94bSLad Prabhakar [CLKOUT3] = "audio_clkout3",
76c087a94bSLad Prabhakar };
77c087a94bSLad Prabhakar
rsnd_adg_calculate_brgx(unsigned long div)78c087a94bSLad Prabhakar static u32 rsnd_adg_calculate_brgx(unsigned long div)
79c087a94bSLad Prabhakar {
80c087a94bSLad Prabhakar int i;
81c087a94bSLad Prabhakar
82c087a94bSLad Prabhakar if (!div)
83c087a94bSLad Prabhakar return 0;
84c087a94bSLad Prabhakar
85c087a94bSLad Prabhakar for (i = 3; i >= 0; i--) {
86c087a94bSLad Prabhakar int ratio = 2 << (i * 2);
87c087a94bSLad Prabhakar if (0 == (div % ratio))
88c087a94bSLad Prabhakar return (u32)((i << 8) | ((div / ratio) - 1));
89c087a94bSLad Prabhakar }
90c087a94bSLad Prabhakar
91c087a94bSLad Prabhakar return ~0;
92c087a94bSLad Prabhakar }
93c087a94bSLad Prabhakar
rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream * io)94c087a94bSLad Prabhakar static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
95c087a94bSLad Prabhakar {
96c087a94bSLad Prabhakar struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
97c087a94bSLad Prabhakar int id = rsnd_mod_id(ssi_mod);
98c087a94bSLad Prabhakar int ws = id;
99c087a94bSLad Prabhakar
100c087a94bSLad Prabhakar if (rsnd_ssi_is_pin_sharing(io)) {
101c087a94bSLad Prabhakar switch (id) {
102c087a94bSLad Prabhakar case 1:
103c087a94bSLad Prabhakar case 2:
104c087a94bSLad Prabhakar case 9:
105c087a94bSLad Prabhakar ws = 0;
106c087a94bSLad Prabhakar break;
107c087a94bSLad Prabhakar case 4:
108c087a94bSLad Prabhakar ws = 3;
109c087a94bSLad Prabhakar break;
110c087a94bSLad Prabhakar case 8:
111c087a94bSLad Prabhakar ws = 7;
112c087a94bSLad Prabhakar break;
113c087a94bSLad Prabhakar }
114c087a94bSLad Prabhakar } else {
115c087a94bSLad Prabhakar /*
116c087a94bSLad Prabhakar * SSI8 is not connected to ADG.
117c087a94bSLad Prabhakar * Thus SSI9 is using ws = 8
118c087a94bSLad Prabhakar */
119c087a94bSLad Prabhakar if (id == 9)
120c087a94bSLad Prabhakar ws = 8;
121c087a94bSLad Prabhakar }
122c087a94bSLad Prabhakar
123c087a94bSLad Prabhakar return (0x6 + ws) << 8;
124c087a94bSLad Prabhakar }
125c087a94bSLad Prabhakar
__rsnd_adg_get_timesel_ratio(struct rsnd_priv * priv,struct rsnd_dai_stream * io,unsigned int target_rate,unsigned int * target_val,unsigned int * target_en)126c087a94bSLad Prabhakar static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
127c087a94bSLad Prabhakar struct rsnd_dai_stream *io,
128c087a94bSLad Prabhakar unsigned int target_rate,
129c087a94bSLad Prabhakar unsigned int *target_val,
130c087a94bSLad Prabhakar unsigned int *target_en)
131c087a94bSLad Prabhakar {
132c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
133c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
134c087a94bSLad Prabhakar int sel;
135c087a94bSLad Prabhakar unsigned int val, en;
136c087a94bSLad Prabhakar unsigned int min, diff;
137c087a94bSLad Prabhakar unsigned int sel_rate[] = {
138c087a94bSLad Prabhakar adg->clkin_rate[CLKA], /* 0000: CLKA */
139c087a94bSLad Prabhakar adg->clkin_rate[CLKB], /* 0001: CLKB */
140c087a94bSLad Prabhakar adg->clkin_rate[CLKC], /* 0010: CLKC */
141c087a94bSLad Prabhakar adg->brg_rate[ADG_HZ_441], /* 0011: BRGA */
142c087a94bSLad Prabhakar adg->brg_rate[ADG_HZ_48], /* 0100: BRGB */
143c087a94bSLad Prabhakar };
144c087a94bSLad Prabhakar
145c087a94bSLad Prabhakar min = ~0;
146c087a94bSLad Prabhakar val = 0;
147c087a94bSLad Prabhakar en = 0;
148c087a94bSLad Prabhakar for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
149c087a94bSLad Prabhakar int idx = 0;
150c087a94bSLad Prabhakar int step = 2;
151c087a94bSLad Prabhakar int div;
152c087a94bSLad Prabhakar
153c087a94bSLad Prabhakar if (!sel_rate[sel])
154c087a94bSLad Prabhakar continue;
155c087a94bSLad Prabhakar
156c087a94bSLad Prabhakar for (div = 2; div <= 98304; div += step) {
157c087a94bSLad Prabhakar diff = abs(target_rate - sel_rate[sel] / div);
158c087a94bSLad Prabhakar if (min > diff) {
159c087a94bSLad Prabhakar val = (sel << 8) | idx;
160c087a94bSLad Prabhakar min = diff;
161c087a94bSLad Prabhakar en = 1 << (sel + 1); /* fixme */
162c087a94bSLad Prabhakar }
163c087a94bSLad Prabhakar
164c087a94bSLad Prabhakar /*
165c087a94bSLad Prabhakar * step of 0_0000 / 0_0001 / 0_1101
166c087a94bSLad Prabhakar * are out of order
167c087a94bSLad Prabhakar */
168c087a94bSLad Prabhakar if ((idx > 2) && (idx % 2))
169c087a94bSLad Prabhakar step *= 2;
170c087a94bSLad Prabhakar if (idx == 0x1c) {
171c087a94bSLad Prabhakar div += step;
172c087a94bSLad Prabhakar step *= 2;
173c087a94bSLad Prabhakar }
174c087a94bSLad Prabhakar idx++;
175c087a94bSLad Prabhakar }
176c087a94bSLad Prabhakar }
177c087a94bSLad Prabhakar
178c087a94bSLad Prabhakar if (min == ~0) {
179c087a94bSLad Prabhakar dev_err(dev, "no Input clock\n");
180c087a94bSLad Prabhakar return;
181c087a94bSLad Prabhakar }
182c087a94bSLad Prabhakar
183c087a94bSLad Prabhakar *target_val = val;
184c087a94bSLad Prabhakar if (target_en)
185c087a94bSLad Prabhakar *target_en = en;
186c087a94bSLad Prabhakar }
187c087a94bSLad Prabhakar
rsnd_adg_get_timesel_ratio(struct rsnd_priv * priv,struct rsnd_dai_stream * io,unsigned int in_rate,unsigned int out_rate,u32 * in,u32 * out,u32 * en)188c087a94bSLad Prabhakar static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
189c087a94bSLad Prabhakar struct rsnd_dai_stream *io,
190c087a94bSLad Prabhakar unsigned int in_rate,
191c087a94bSLad Prabhakar unsigned int out_rate,
192c087a94bSLad Prabhakar u32 *in, u32 *out, u32 *en)
193c087a94bSLad Prabhakar {
194c087a94bSLad Prabhakar struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
195c087a94bSLad Prabhakar unsigned int target_rate;
196c087a94bSLad Prabhakar u32 *target_val;
197c087a94bSLad Prabhakar u32 _in;
198c087a94bSLad Prabhakar u32 _out;
199c087a94bSLad Prabhakar u32 _en;
200c087a94bSLad Prabhakar
201c087a94bSLad Prabhakar /* default = SSI WS */
202c087a94bSLad Prabhakar _in =
203c087a94bSLad Prabhakar _out = rsnd_adg_ssi_ws_timing_gen2(io);
204c087a94bSLad Prabhakar
205c087a94bSLad Prabhakar target_rate = 0;
206c087a94bSLad Prabhakar target_val = NULL;
207c087a94bSLad Prabhakar _en = 0;
208c087a94bSLad Prabhakar if (runtime->rate != in_rate) {
209c087a94bSLad Prabhakar target_rate = out_rate;
210c087a94bSLad Prabhakar target_val = &_out;
211c087a94bSLad Prabhakar } else if (runtime->rate != out_rate) {
212c087a94bSLad Prabhakar target_rate = in_rate;
213c087a94bSLad Prabhakar target_val = &_in;
214c087a94bSLad Prabhakar }
215c087a94bSLad Prabhakar
216c087a94bSLad Prabhakar if (target_rate)
217c087a94bSLad Prabhakar __rsnd_adg_get_timesel_ratio(priv, io,
218c087a94bSLad Prabhakar target_rate,
219c087a94bSLad Prabhakar target_val, &_en);
220c087a94bSLad Prabhakar
221c087a94bSLad Prabhakar if (in)
222c087a94bSLad Prabhakar *in = _in;
223c087a94bSLad Prabhakar if (out)
224c087a94bSLad Prabhakar *out = _out;
225c087a94bSLad Prabhakar if (en)
226c087a94bSLad Prabhakar *en = _en;
227c087a94bSLad Prabhakar }
228c087a94bSLad Prabhakar
rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod * cmd_mod,struct rsnd_dai_stream * io)229c087a94bSLad Prabhakar int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
230c087a94bSLad Prabhakar struct rsnd_dai_stream *io)
231c087a94bSLad Prabhakar {
232c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
233c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
234c087a94bSLad Prabhakar struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
235c087a94bSLad Prabhakar int id = rsnd_mod_id(cmd_mod);
236c087a94bSLad Prabhakar int shift = (id % 2) ? 16 : 0;
237c087a94bSLad Prabhakar u32 mask, val;
238c087a94bSLad Prabhakar
239c087a94bSLad Prabhakar rsnd_adg_get_timesel_ratio(priv, io,
240c087a94bSLad Prabhakar rsnd_src_get_in_rate(priv, io),
241c087a94bSLad Prabhakar rsnd_src_get_out_rate(priv, io),
242c087a94bSLad Prabhakar NULL, &val, NULL);
243c087a94bSLad Prabhakar
244c087a94bSLad Prabhakar val = val << shift;
245c087a94bSLad Prabhakar mask = 0x0f1f << shift;
246c087a94bSLad Prabhakar
247c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
248c087a94bSLad Prabhakar
249c087a94bSLad Prabhakar return 0;
250c087a94bSLad Prabhakar }
251c087a94bSLad Prabhakar
rsnd_adg_set_src_timesel_gen2(struct rsnd_mod * src_mod,struct rsnd_dai_stream * io,unsigned int in_rate,unsigned int out_rate)252c087a94bSLad Prabhakar int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
253c087a94bSLad Prabhakar struct rsnd_dai_stream *io,
254c087a94bSLad Prabhakar unsigned int in_rate,
255c087a94bSLad Prabhakar unsigned int out_rate)
256c087a94bSLad Prabhakar {
257c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
258c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
259c087a94bSLad Prabhakar struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
260c087a94bSLad Prabhakar u32 in, out;
261c087a94bSLad Prabhakar u32 mask, en;
262c087a94bSLad Prabhakar int id = rsnd_mod_id(src_mod);
263c087a94bSLad Prabhakar int shift = (id % 2) ? 16 : 0;
264c087a94bSLad Prabhakar
265c087a94bSLad Prabhakar rsnd_mod_make_sure(src_mod, RSND_MOD_SRC);
266c087a94bSLad Prabhakar
267c087a94bSLad Prabhakar rsnd_adg_get_timesel_ratio(priv, io,
268c087a94bSLad Prabhakar in_rate, out_rate,
269c087a94bSLad Prabhakar &in, &out, &en);
270c087a94bSLad Prabhakar
271c087a94bSLad Prabhakar in = in << shift;
272c087a94bSLad Prabhakar out = out << shift;
273c087a94bSLad Prabhakar mask = 0x0f1f << shift;
274c087a94bSLad Prabhakar
275c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, SRCIN_TIMSEL(id / 2), mask, in);
276c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL(id / 2), mask, out);
277c087a94bSLad Prabhakar
278c087a94bSLad Prabhakar if (en)
279c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, DIV_EN, en, en);
280c087a94bSLad Prabhakar
281c087a94bSLad Prabhakar return 0;
282c087a94bSLad Prabhakar }
283c087a94bSLad Prabhakar
rsnd_adg_set_ssi_clk(struct rsnd_mod * ssi_mod,u32 val)284c087a94bSLad Prabhakar static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
285c087a94bSLad Prabhakar {
286c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
287c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
288c087a94bSLad Prabhakar struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
289c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
290c087a94bSLad Prabhakar int id = rsnd_mod_id(ssi_mod);
291c087a94bSLad Prabhakar int shift = (id % 4) * 8;
292c087a94bSLad Prabhakar u32 mask = 0xFF << shift;
293c087a94bSLad Prabhakar
294c087a94bSLad Prabhakar rsnd_mod_make_sure(ssi_mod, RSND_MOD_SSI);
295c087a94bSLad Prabhakar
296c087a94bSLad Prabhakar val = val << shift;
297c087a94bSLad Prabhakar
298c087a94bSLad Prabhakar /*
299c087a94bSLad Prabhakar * SSI 8 is not connected to ADG.
300c087a94bSLad Prabhakar * it works with SSI 7
301c087a94bSLad Prabhakar */
302c087a94bSLad Prabhakar if (id == 8)
303c087a94bSLad Prabhakar return;
304c087a94bSLad Prabhakar
305c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL(id / 4), mask, val);
306c087a94bSLad Prabhakar
307c087a94bSLad Prabhakar dev_dbg(dev, "AUDIO_CLK_SEL is 0x%x\n", val);
308c087a94bSLad Prabhakar }
309c087a94bSLad Prabhakar
rsnd_adg_clk_query(struct rsnd_priv * priv,unsigned int rate)310c087a94bSLad Prabhakar int rsnd_adg_clk_query(struct rsnd_priv *priv, unsigned int rate)
311c087a94bSLad Prabhakar {
312c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
313c087a94bSLad Prabhakar struct clk *clk;
314c087a94bSLad Prabhakar int i;
315c087a94bSLad Prabhakar int sel_table[] = {
316c087a94bSLad Prabhakar [CLKA] = 0x1,
317c087a94bSLad Prabhakar [CLKB] = 0x2,
318c087a94bSLad Prabhakar [CLKC] = 0x3,
319c087a94bSLad Prabhakar [CLKI] = 0x0,
320c087a94bSLad Prabhakar };
321c087a94bSLad Prabhakar
322c087a94bSLad Prabhakar /*
323c087a94bSLad Prabhakar * find suitable clock from
324c087a94bSLad Prabhakar * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
325c087a94bSLad Prabhakar */
326c087a94bSLad Prabhakar for_each_rsnd_clkin(clk, adg, i)
327c087a94bSLad Prabhakar if (rate == adg->clkin_rate[i])
328c087a94bSLad Prabhakar return sel_table[i];
329c087a94bSLad Prabhakar
330c087a94bSLad Prabhakar /*
331c087a94bSLad Prabhakar * find divided clock from BRGA/BRGB
332c087a94bSLad Prabhakar */
333c087a94bSLad Prabhakar if (rate == adg->brg_rate[ADG_HZ_441])
334c087a94bSLad Prabhakar return 0x10;
335c087a94bSLad Prabhakar
336c087a94bSLad Prabhakar if (rate == adg->brg_rate[ADG_HZ_48])
337c087a94bSLad Prabhakar return 0x20;
338c087a94bSLad Prabhakar
339c087a94bSLad Prabhakar return -EIO;
340c087a94bSLad Prabhakar }
341c087a94bSLad Prabhakar
rsnd_adg_ssi_clk_stop(struct rsnd_mod * ssi_mod)342c087a94bSLad Prabhakar int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
343c087a94bSLad Prabhakar {
344c087a94bSLad Prabhakar rsnd_adg_set_ssi_clk(ssi_mod, 0);
345c087a94bSLad Prabhakar
346c087a94bSLad Prabhakar return 0;
347c087a94bSLad Prabhakar }
348c087a94bSLad Prabhakar
rsnd_adg_ssi_clk_try_start(struct rsnd_mod * ssi_mod,unsigned int rate)349c087a94bSLad Prabhakar int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
350c087a94bSLad Prabhakar {
351c087a94bSLad Prabhakar struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
352c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
353c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
354c087a94bSLad Prabhakar struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
355c087a94bSLad Prabhakar int data;
356c087a94bSLad Prabhakar u32 ckr = 0;
357c087a94bSLad Prabhakar
358c087a94bSLad Prabhakar data = rsnd_adg_clk_query(priv, rate);
359c087a94bSLad Prabhakar if (data < 0)
360c087a94bSLad Prabhakar return data;
361c087a94bSLad Prabhakar
362c087a94bSLad Prabhakar rsnd_adg_set_ssi_clk(ssi_mod, data);
363c087a94bSLad Prabhakar
364c087a94bSLad Prabhakar if (0 == (rate % 8000))
365c087a94bSLad Prabhakar ckr = 0x80000000; /* BRGB output = 48kHz */
366c087a94bSLad Prabhakar
367c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr | ckr);
368c087a94bSLad Prabhakar
369c087a94bSLad Prabhakar dev_dbg(dev, "CLKOUT is based on BRG%c (= %dHz)\n",
370c087a94bSLad Prabhakar (ckr) ? 'B' : 'A',
371c087a94bSLad Prabhakar (ckr) ? adg->brg_rate[ADG_HZ_48] :
372c087a94bSLad Prabhakar adg->brg_rate[ADG_HZ_441]);
373c087a94bSLad Prabhakar
374c087a94bSLad Prabhakar return 0;
375c087a94bSLad Prabhakar }
376c087a94bSLad Prabhakar
rsnd_adg_clk_control(struct rsnd_priv * priv,int enable)377*139fa599SKuninori Morimoto int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
378c087a94bSLad Prabhakar {
379c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
380c087a94bSLad Prabhakar struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
381c087a94bSLad Prabhakar struct clk *clk;
382*139fa599SKuninori Morimoto int ret = 0, i;
383c087a94bSLad Prabhakar
384c087a94bSLad Prabhakar if (enable) {
385c087a94bSLad Prabhakar rsnd_mod_bset(adg_mod, BRGCKR, 0x80770000, adg->ckr);
386c087a94bSLad Prabhakar rsnd_mod_write(adg_mod, BRRA, adg->brga);
387c087a94bSLad Prabhakar rsnd_mod_write(adg_mod, BRRB, adg->brgb);
388c087a94bSLad Prabhakar }
389c087a94bSLad Prabhakar
390c087a94bSLad Prabhakar for_each_rsnd_clkin(clk, adg, i) {
391c087a94bSLad Prabhakar if (enable) {
392*139fa599SKuninori Morimoto ret = clk_prepare_enable(clk);
393c087a94bSLad Prabhakar
394c087a94bSLad Prabhakar /*
395c087a94bSLad Prabhakar * We shouldn't use clk_get_rate() under
396c087a94bSLad Prabhakar * atomic context. Let's keep it when
397c087a94bSLad Prabhakar * rsnd_adg_clk_enable() was called
398c087a94bSLad Prabhakar */
399*139fa599SKuninori Morimoto if (ret < 0)
400*139fa599SKuninori Morimoto break;
401*139fa599SKuninori Morimoto
402c087a94bSLad Prabhakar adg->clkin_rate[i] = clk_get_rate(clk);
403c087a94bSLad Prabhakar } else {
404*139fa599SKuninori Morimoto if (adg->clkin_rate[i])
405c087a94bSLad Prabhakar clk_disable_unprepare(clk);
406*139fa599SKuninori Morimoto
407*139fa599SKuninori Morimoto adg->clkin_rate[i] = 0;
408c087a94bSLad Prabhakar }
409c087a94bSLad Prabhakar }
410*139fa599SKuninori Morimoto
411*139fa599SKuninori Morimoto /*
412*139fa599SKuninori Morimoto * rsnd_adg_clk_enable() might return error (_disable() will not).
413*139fa599SKuninori Morimoto * We need to rollback in such case
414*139fa599SKuninori Morimoto */
415*139fa599SKuninori Morimoto if (ret < 0)
416*139fa599SKuninori Morimoto rsnd_adg_clk_disable(priv);
417*139fa599SKuninori Morimoto
418*139fa599SKuninori Morimoto return ret;
419c087a94bSLad Prabhakar }
420c087a94bSLad Prabhakar
rsnd_adg_create_null_clk(struct rsnd_priv * priv,const char * const name,const char * parent)421c087a94bSLad Prabhakar static struct clk *rsnd_adg_create_null_clk(struct rsnd_priv *priv,
422c087a94bSLad Prabhakar const char * const name,
423c087a94bSLad Prabhakar const char *parent)
424c087a94bSLad Prabhakar {
425c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
426c087a94bSLad Prabhakar struct clk *clk;
427c087a94bSLad Prabhakar
428c087a94bSLad Prabhakar clk = clk_register_fixed_rate(dev, name, parent, 0, 0);
429c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(clk)) {
430c087a94bSLad Prabhakar dev_err(dev, "create null clk error\n");
431c087a94bSLad Prabhakar return ERR_CAST(clk);
432c087a94bSLad Prabhakar }
433c087a94bSLad Prabhakar
434c087a94bSLad Prabhakar return clk;
435c087a94bSLad Prabhakar }
436c087a94bSLad Prabhakar
rsnd_adg_null_clk_get(struct rsnd_priv * priv)437c087a94bSLad Prabhakar static struct clk *rsnd_adg_null_clk_get(struct rsnd_priv *priv)
438c087a94bSLad Prabhakar {
439c087a94bSLad Prabhakar struct rsnd_adg *adg = priv->adg;
440c087a94bSLad Prabhakar
441c087a94bSLad Prabhakar if (!adg->null_clk) {
442c087a94bSLad Prabhakar static const char * const name = "rsnd_adg_null";
443c087a94bSLad Prabhakar
444c087a94bSLad Prabhakar adg->null_clk = rsnd_adg_create_null_clk(priv, name, NULL);
445c087a94bSLad Prabhakar }
446c087a94bSLad Prabhakar
447c087a94bSLad Prabhakar return adg->null_clk;
448c087a94bSLad Prabhakar }
449c087a94bSLad Prabhakar
rsnd_adg_null_clk_clean(struct rsnd_priv * priv)450c087a94bSLad Prabhakar static void rsnd_adg_null_clk_clean(struct rsnd_priv *priv)
451c087a94bSLad Prabhakar {
452c087a94bSLad Prabhakar struct rsnd_adg *adg = priv->adg;
453c087a94bSLad Prabhakar
454c087a94bSLad Prabhakar if (adg->null_clk)
455c087a94bSLad Prabhakar clk_unregister_fixed_rate(adg->null_clk);
456c087a94bSLad Prabhakar }
457c087a94bSLad Prabhakar
rsnd_adg_get_clkin(struct rsnd_priv * priv)458c087a94bSLad Prabhakar static int rsnd_adg_get_clkin(struct rsnd_priv *priv)
459c087a94bSLad Prabhakar {
460c087a94bSLad Prabhakar struct rsnd_adg *adg = priv->adg;
461c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
462c087a94bSLad Prabhakar struct clk *clk;
463c087a94bSLad Prabhakar const char * const *clkin_name;
464c087a94bSLad Prabhakar int clkin_size;
465c087a94bSLad Prabhakar int i;
466c087a94bSLad Prabhakar
467c087a94bSLad Prabhakar clkin_name = clkin_name_gen2;
468c087a94bSLad Prabhakar clkin_size = ARRAY_SIZE(clkin_name_gen2);
469c087a94bSLad Prabhakar if (rsnd_is_gen4(priv)) {
470c087a94bSLad Prabhakar clkin_name = clkin_name_gen4;
471c087a94bSLad Prabhakar clkin_size = ARRAY_SIZE(clkin_name_gen4);
472c087a94bSLad Prabhakar }
473c087a94bSLad Prabhakar
474c087a94bSLad Prabhakar for (i = 0; i < clkin_size; i++) {
475c087a94bSLad Prabhakar clk = devm_clk_get(dev, clkin_name[i]);
476c087a94bSLad Prabhakar
477c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(clk))
478c087a94bSLad Prabhakar clk = rsnd_adg_null_clk_get(priv);
479c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(clk))
480c087a94bSLad Prabhakar goto err;
481c087a94bSLad Prabhakar
482c087a94bSLad Prabhakar adg->clkin[i] = clk;
483c087a94bSLad Prabhakar }
484c087a94bSLad Prabhakar
485c087a94bSLad Prabhakar adg->clkin_size = clkin_size;
486c087a94bSLad Prabhakar
487c087a94bSLad Prabhakar return 0;
488c087a94bSLad Prabhakar
489c087a94bSLad Prabhakar err:
490c087a94bSLad Prabhakar dev_err(dev, "adg clock IN get failed\n");
491c087a94bSLad Prabhakar
492c087a94bSLad Prabhakar rsnd_adg_null_clk_clean(priv);
493c087a94bSLad Prabhakar
494c087a94bSLad Prabhakar return -EIO;
495c087a94bSLad Prabhakar }
496c087a94bSLad Prabhakar
rsnd_adg_unregister_clkout(struct rsnd_priv * priv)497c087a94bSLad Prabhakar static void rsnd_adg_unregister_clkout(struct rsnd_priv *priv)
498c087a94bSLad Prabhakar {
499c087a94bSLad Prabhakar struct rsnd_adg *adg = priv->adg;
500c087a94bSLad Prabhakar struct clk *clk;
501c087a94bSLad Prabhakar int i;
502c087a94bSLad Prabhakar
503c087a94bSLad Prabhakar for_each_rsnd_clkout(clk, adg, i)
504c087a94bSLad Prabhakar clk_unregister_fixed_rate(clk);
505c087a94bSLad Prabhakar }
506c087a94bSLad Prabhakar
rsnd_adg_get_clkout(struct rsnd_priv * priv)507c087a94bSLad Prabhakar static int rsnd_adg_get_clkout(struct rsnd_priv *priv)
508c087a94bSLad Prabhakar {
509c087a94bSLad Prabhakar struct rsnd_adg *adg = priv->adg;
510c087a94bSLad Prabhakar struct clk *clk;
511c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
512c087a94bSLad Prabhakar struct device_node *np = dev->of_node;
513c087a94bSLad Prabhakar struct property *prop;
514c087a94bSLad Prabhakar u32 ckr, brgx, brga, brgb;
515c087a94bSLad Prabhakar u32 req_rate[ADG_HZ_SIZE] = {};
516c087a94bSLad Prabhakar uint32_t count = 0;
517c087a94bSLad Prabhakar unsigned long req_Hz[ADG_HZ_SIZE];
518c087a94bSLad Prabhakar int clkout_size;
519c087a94bSLad Prabhakar int i, req_size;
520c087a94bSLad Prabhakar int approximate = 0;
521c087a94bSLad Prabhakar const char *parent_clk_name = NULL;
522c087a94bSLad Prabhakar const char * const *clkout_name;
523c087a94bSLad Prabhakar int brg_table[] = {
524c087a94bSLad Prabhakar [CLKA] = 0x0,
525c087a94bSLad Prabhakar [CLKB] = 0x1,
526c087a94bSLad Prabhakar [CLKC] = 0x4,
527c087a94bSLad Prabhakar [CLKI] = 0x2,
528c087a94bSLad Prabhakar };
529c087a94bSLad Prabhakar
530c087a94bSLad Prabhakar ckr = 0;
531c087a94bSLad Prabhakar brga = 0xff; /* default */
532c087a94bSLad Prabhakar brgb = 0xff; /* default */
533c087a94bSLad Prabhakar
534c087a94bSLad Prabhakar /*
535c087a94bSLad Prabhakar * ADG supports BRRA/BRRB output only
536c087a94bSLad Prabhakar * this means all clkout0/1/2/3 will be same rate
537c087a94bSLad Prabhakar */
538c087a94bSLad Prabhakar prop = of_find_property(np, "clock-frequency", NULL);
539c087a94bSLad Prabhakar if (!prop)
540c087a94bSLad Prabhakar goto rsnd_adg_get_clkout_end;
541c087a94bSLad Prabhakar
542c087a94bSLad Prabhakar req_size = prop->length / sizeof(u32);
543c087a94bSLad Prabhakar if (req_size > ADG_HZ_SIZE) {
544c087a94bSLad Prabhakar dev_err(dev, "too many clock-frequency\n");
545c087a94bSLad Prabhakar return -EINVAL;
546c087a94bSLad Prabhakar }
547c087a94bSLad Prabhakar
548c087a94bSLad Prabhakar of_property_read_u32_array(np, "clock-frequency", req_rate, req_size);
549c087a94bSLad Prabhakar req_Hz[ADG_HZ_48] = 0;
550c087a94bSLad Prabhakar req_Hz[ADG_HZ_441] = 0;
551c087a94bSLad Prabhakar for (i = 0; i < req_size; i++) {
552c087a94bSLad Prabhakar if (0 == (req_rate[i] % 44100))
553c087a94bSLad Prabhakar req_Hz[ADG_HZ_441] = req_rate[i];
554c087a94bSLad Prabhakar if (0 == (req_rate[i] % 48000))
555c087a94bSLad Prabhakar req_Hz[ADG_HZ_48] = req_rate[i];
556c087a94bSLad Prabhakar }
557c087a94bSLad Prabhakar
558c087a94bSLad Prabhakar /*
559c087a94bSLad Prabhakar * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
560c087a94bSLad Prabhakar * have 44.1kHz or 48kHz base clocks for now.
561c087a94bSLad Prabhakar *
562c087a94bSLad Prabhakar * SSI itself can divide parent clock by 1/1 - 1/16
563c087a94bSLad Prabhakar * see
564c087a94bSLad Prabhakar * rsnd_adg_ssi_clk_try_start()
565c087a94bSLad Prabhakar * rsnd_ssi_master_clk_start()
566c087a94bSLad Prabhakar */
567c087a94bSLad Prabhakar
568c087a94bSLad Prabhakar /*
569c087a94bSLad Prabhakar * [APPROXIMATE]
570c087a94bSLad Prabhakar *
571c087a94bSLad Prabhakar * clk_i (internal clock) can't create accurate rate, it will be approximate rate.
572c087a94bSLad Prabhakar *
573c087a94bSLad Prabhakar * <Note>
574c087a94bSLad Prabhakar *
575c087a94bSLad Prabhakar * clk_i needs x2 of required maximum rate.
576c087a94bSLad Prabhakar * see
577c087a94bSLad Prabhakar * - Minimum division of BRRA/BRRB
578c087a94bSLad Prabhakar * - rsnd_ssi_clk_query()
579c087a94bSLad Prabhakar *
580c087a94bSLad Prabhakar * Sample Settings for TDM 8ch, 32bit width
581c087a94bSLad Prabhakar *
582c087a94bSLad Prabhakar * 8(ch) x 32(bit) x 44100(Hz) x 2<Note> = 22579200
583c087a94bSLad Prabhakar * 8(ch) x 32(bit) x 48000(Hz) x 2<Note> = 24576000
584c087a94bSLad Prabhakar *
585c087a94bSLad Prabhakar * clock-frequency = <22579200 24576000>;
586c087a94bSLad Prabhakar */
587c087a94bSLad Prabhakar for_each_rsnd_clkin(clk, adg, i) {
588c087a94bSLad Prabhakar u32 rate, div;
589c087a94bSLad Prabhakar
590c087a94bSLad Prabhakar rate = clk_get_rate(clk);
591c087a94bSLad Prabhakar
592c087a94bSLad Prabhakar if (0 == rate) /* not used */
593c087a94bSLad Prabhakar continue;
594c087a94bSLad Prabhakar
595c087a94bSLad Prabhakar /* BRGA */
596c087a94bSLad Prabhakar
597c087a94bSLad Prabhakar if (i == CLKI)
598c087a94bSLad Prabhakar /* see [APPROXIMATE] */
599c087a94bSLad Prabhakar rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_441]) * req_Hz[ADG_HZ_441];
600c087a94bSLad Prabhakar if (!adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441] && (0 == rate % 44100)) {
601c087a94bSLad Prabhakar div = rate / req_Hz[ADG_HZ_441];
602c087a94bSLad Prabhakar brgx = rsnd_adg_calculate_brgx(div);
603c087a94bSLad Prabhakar if (BRRx_MASK(brgx) == brgx) {
604c087a94bSLad Prabhakar brga = brgx;
605c087a94bSLad Prabhakar adg->brg_rate[ADG_HZ_441] = rate / div;
606c087a94bSLad Prabhakar ckr |= brg_table[i] << 20;
607c087a94bSLad Prabhakar if (req_Hz[ADG_HZ_441])
608c087a94bSLad Prabhakar parent_clk_name = __clk_get_name(clk);
609c087a94bSLad Prabhakar if (i == CLKI)
610c087a94bSLad Prabhakar approximate = 1;
611c087a94bSLad Prabhakar }
612c087a94bSLad Prabhakar }
613c087a94bSLad Prabhakar
614c087a94bSLad Prabhakar /* BRGB */
615c087a94bSLad Prabhakar
616c087a94bSLad Prabhakar if (i == CLKI)
617c087a94bSLad Prabhakar /* see [APPROXIMATE] */
618c087a94bSLad Prabhakar rate = (clk_get_rate(clk) / req_Hz[ADG_HZ_48]) * req_Hz[ADG_HZ_48];
619c087a94bSLad Prabhakar if (!adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48] && (0 == rate % 48000)) {
620c087a94bSLad Prabhakar div = rate / req_Hz[ADG_HZ_48];
621c087a94bSLad Prabhakar brgx = rsnd_adg_calculate_brgx(div);
622c087a94bSLad Prabhakar if (BRRx_MASK(brgx) == brgx) {
623c087a94bSLad Prabhakar brgb = brgx;
624c087a94bSLad Prabhakar adg->brg_rate[ADG_HZ_48] = rate / div;
625c087a94bSLad Prabhakar ckr |= brg_table[i] << 16;
626c087a94bSLad Prabhakar if (req_Hz[ADG_HZ_48])
627c087a94bSLad Prabhakar parent_clk_name = __clk_get_name(clk);
628c087a94bSLad Prabhakar if (i == CLKI)
629c087a94bSLad Prabhakar approximate = 1;
630c087a94bSLad Prabhakar }
631c087a94bSLad Prabhakar }
632c087a94bSLad Prabhakar }
633c087a94bSLad Prabhakar
634c087a94bSLad Prabhakar if (!(adg->brg_rate[ADG_HZ_48] && req_Hz[ADG_HZ_48]) &&
635c087a94bSLad Prabhakar !(adg->brg_rate[ADG_HZ_441] && req_Hz[ADG_HZ_441]))
636c087a94bSLad Prabhakar goto rsnd_adg_get_clkout_end;
637c087a94bSLad Prabhakar
638c087a94bSLad Prabhakar if (approximate)
639c087a94bSLad Prabhakar dev_info(dev, "It uses CLK_I as approximate rate");
640c087a94bSLad Prabhakar
641c087a94bSLad Prabhakar clkout_name = clkout_name_gen2;
642c087a94bSLad Prabhakar clkout_size = ARRAY_SIZE(clkout_name_gen2);
643c087a94bSLad Prabhakar if (rsnd_is_gen4(priv))
644c087a94bSLad Prabhakar clkout_size = 1; /* reuse clkout_name_gen2[] */
645c087a94bSLad Prabhakar
646c087a94bSLad Prabhakar /*
647c087a94bSLad Prabhakar * ADG supports BRRA/BRRB output only.
648c087a94bSLad Prabhakar * this means all clkout0/1/2/3 will be * same rate
649c087a94bSLad Prabhakar */
650c087a94bSLad Prabhakar
651c087a94bSLad Prabhakar of_property_read_u32(np, "#clock-cells", &count);
652c087a94bSLad Prabhakar /*
653c087a94bSLad Prabhakar * for clkout
654c087a94bSLad Prabhakar */
655c087a94bSLad Prabhakar if (!count) {
656c087a94bSLad Prabhakar clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
657c087a94bSLad Prabhakar parent_clk_name, 0, req_rate[0]);
658c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(clk))
659c087a94bSLad Prabhakar goto err;
660c087a94bSLad Prabhakar
661c087a94bSLad Prabhakar adg->clkout[CLKOUT] = clk;
662c087a94bSLad Prabhakar adg->clkout_size = 1;
663c087a94bSLad Prabhakar of_clk_add_provider(np, of_clk_src_simple_get, clk);
664c087a94bSLad Prabhakar }
665c087a94bSLad Prabhakar /*
666c087a94bSLad Prabhakar * for clkout0/1/2/3
667c087a94bSLad Prabhakar */
668c087a94bSLad Prabhakar else {
669c087a94bSLad Prabhakar for (i = 0; i < clkout_size; i++) {
670c087a94bSLad Prabhakar clk = clk_register_fixed_rate(dev, clkout_name[i],
671c087a94bSLad Prabhakar parent_clk_name, 0,
672c087a94bSLad Prabhakar req_rate[0]);
673c087a94bSLad Prabhakar if (IS_ERR_OR_NULL(clk))
674c087a94bSLad Prabhakar goto err;
675c087a94bSLad Prabhakar
676c087a94bSLad Prabhakar adg->clkout[i] = clk;
677c087a94bSLad Prabhakar }
678c087a94bSLad Prabhakar adg->onecell.clks = adg->clkout;
679c087a94bSLad Prabhakar adg->onecell.clk_num = clkout_size;
680c087a94bSLad Prabhakar adg->clkout_size = clkout_size;
681c087a94bSLad Prabhakar of_clk_add_provider(np, of_clk_src_onecell_get,
682c087a94bSLad Prabhakar &adg->onecell);
683c087a94bSLad Prabhakar }
684c087a94bSLad Prabhakar
685c087a94bSLad Prabhakar rsnd_adg_get_clkout_end:
686c087a94bSLad Prabhakar adg->ckr = ckr;
687c087a94bSLad Prabhakar adg->brga = brga;
688c087a94bSLad Prabhakar adg->brgb = brgb;
689c087a94bSLad Prabhakar
690c087a94bSLad Prabhakar return 0;
691c087a94bSLad Prabhakar
692c087a94bSLad Prabhakar err:
693c087a94bSLad Prabhakar dev_err(dev, "adg clock OUT get failed\n");
694c087a94bSLad Prabhakar
695c087a94bSLad Prabhakar rsnd_adg_unregister_clkout(priv);
696c087a94bSLad Prabhakar
697c087a94bSLad Prabhakar return -EIO;
698c087a94bSLad Prabhakar }
699c087a94bSLad Prabhakar
700c087a94bSLad Prabhakar #if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
701c087a94bSLad Prabhakar __printf(3, 4)
dbg_msg(struct device * dev,struct seq_file * m,const char * fmt,...)702c087a94bSLad Prabhakar static void dbg_msg(struct device *dev, struct seq_file *m,
703c087a94bSLad Prabhakar const char *fmt, ...)
704c087a94bSLad Prabhakar {
705c087a94bSLad Prabhakar char msg[128];
706c087a94bSLad Prabhakar va_list args;
707c087a94bSLad Prabhakar
708c087a94bSLad Prabhakar va_start(args, fmt);
709c087a94bSLad Prabhakar vsnprintf(msg, sizeof(msg), fmt, args);
710c087a94bSLad Prabhakar va_end(args);
711c087a94bSLad Prabhakar
712c087a94bSLad Prabhakar if (m)
713c087a94bSLad Prabhakar seq_puts(m, msg);
714c087a94bSLad Prabhakar else
715c087a94bSLad Prabhakar dev_dbg(dev, "%s", msg);
716c087a94bSLad Prabhakar }
717c087a94bSLad Prabhakar
rsnd_adg_clk_dbg_info(struct rsnd_priv * priv,struct seq_file * m)718c087a94bSLad Prabhakar void rsnd_adg_clk_dbg_info(struct rsnd_priv *priv, struct seq_file *m)
719c087a94bSLad Prabhakar {
720c087a94bSLad Prabhakar struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
721c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
722c087a94bSLad Prabhakar struct clk *clk;
723c087a94bSLad Prabhakar int i;
724c087a94bSLad Prabhakar
725c087a94bSLad Prabhakar for_each_rsnd_clkin(clk, adg, i)
726c087a94bSLad Prabhakar dbg_msg(dev, m, "%-18s : %pa : %ld\n",
727c087a94bSLad Prabhakar __clk_get_name(clk), clk, clk_get_rate(clk));
728c087a94bSLad Prabhakar
729c087a94bSLad Prabhakar dbg_msg(dev, m, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
730c087a94bSLad Prabhakar adg->ckr, adg->brga, adg->brgb);
731c087a94bSLad Prabhakar dbg_msg(dev, m, "BRGA (for 44100 base) = %d\n", adg->brg_rate[ADG_HZ_441]);
732c087a94bSLad Prabhakar dbg_msg(dev, m, "BRGB (for 48000 base) = %d\n", adg->brg_rate[ADG_HZ_48]);
733c087a94bSLad Prabhakar
734c087a94bSLad Prabhakar /*
735c087a94bSLad Prabhakar * Actual CLKOUT will be exchanged in rsnd_adg_ssi_clk_try_start()
736c087a94bSLad Prabhakar * by BRGCKR::BRGCKR_31
737c087a94bSLad Prabhakar */
738c087a94bSLad Prabhakar for_each_rsnd_clkout(clk, adg, i)
739c087a94bSLad Prabhakar dbg_msg(dev, m, "%-18s : %pa : %ld\n",
740c087a94bSLad Prabhakar __clk_get_name(clk), clk, clk_get_rate(clk));
741c087a94bSLad Prabhakar }
742c087a94bSLad Prabhakar #else
743c087a94bSLad Prabhakar #define rsnd_adg_clk_dbg_info(priv, m)
744c087a94bSLad Prabhakar #endif
745c087a94bSLad Prabhakar
rsnd_adg_probe(struct rsnd_priv * priv)746c087a94bSLad Prabhakar int rsnd_adg_probe(struct rsnd_priv *priv)
747c087a94bSLad Prabhakar {
748c087a94bSLad Prabhakar struct rsnd_adg *adg;
749c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
750c087a94bSLad Prabhakar int ret;
751c087a94bSLad Prabhakar
752c087a94bSLad Prabhakar adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
753c087a94bSLad Prabhakar if (!adg)
754c087a94bSLad Prabhakar return -ENOMEM;
755c087a94bSLad Prabhakar
756c087a94bSLad Prabhakar ret = rsnd_mod_init(priv, &adg->mod, &adg_ops,
757c087a94bSLad Prabhakar NULL, 0, 0);
758c087a94bSLad Prabhakar if (ret)
759c087a94bSLad Prabhakar return ret;
760c087a94bSLad Prabhakar
761c087a94bSLad Prabhakar priv->adg = adg;
762c087a94bSLad Prabhakar
763c087a94bSLad Prabhakar ret = rsnd_adg_get_clkin(priv);
764c087a94bSLad Prabhakar if (ret)
765c087a94bSLad Prabhakar return ret;
766c087a94bSLad Prabhakar
767c087a94bSLad Prabhakar ret = rsnd_adg_get_clkout(priv);
768c087a94bSLad Prabhakar if (ret)
769c087a94bSLad Prabhakar return ret;
770c087a94bSLad Prabhakar
771*139fa599SKuninori Morimoto ret = rsnd_adg_clk_enable(priv);
772*139fa599SKuninori Morimoto if (ret)
773*139fa599SKuninori Morimoto return ret;
774*139fa599SKuninori Morimoto
775c087a94bSLad Prabhakar rsnd_adg_clk_dbg_info(priv, NULL);
776c087a94bSLad Prabhakar
777c087a94bSLad Prabhakar return 0;
778c087a94bSLad Prabhakar }
779c087a94bSLad Prabhakar
rsnd_adg_remove(struct rsnd_priv * priv)780c087a94bSLad Prabhakar void rsnd_adg_remove(struct rsnd_priv *priv)
781c087a94bSLad Prabhakar {
782c087a94bSLad Prabhakar struct device *dev = rsnd_priv_to_dev(priv);
783c087a94bSLad Prabhakar struct device_node *np = dev->of_node;
784c087a94bSLad Prabhakar
785c087a94bSLad Prabhakar rsnd_adg_unregister_clkout(priv);
786c087a94bSLad Prabhakar
787c087a94bSLad Prabhakar of_clk_del_provider(np);
788c087a94bSLad Prabhakar
789c087a94bSLad Prabhakar rsnd_adg_clk_disable(priv);
790c087a94bSLad Prabhakar
791c087a94bSLad Prabhakar /* It should be called after rsnd_adg_clk_disable() */
792c087a94bSLad Prabhakar rsnd_adg_null_clk_clean(priv);
793c087a94bSLad Prabhakar }
794