~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/sh/rcar/adg.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php