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

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

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Helper routines for R-Car sound ADG.
  3  *
  4  *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  5  *
  6  * This file is subject to the terms and conditions of the GNU General Public
  7  * License.  See the file "COPYING" in the main directory of this archive
  8  * for more details.
  9  */
 10 #include <linux/clk-provider.h>
 11 #include "rsnd.h"
 12 
 13 #define CLKA    0
 14 #define CLKB    1
 15 #define CLKC    2
 16 #define CLKI    3
 17 #define CLKMAX  4
 18 
 19 #define CLKOUT  0
 20 #define CLKOUT1 1
 21 #define CLKOUT2 2
 22 #define CLKOUT3 3
 23 #define CLKOUTMAX 4
 24 
 25 #define BRRx_MASK(x) (0x3FF & x)
 26 
 27 static struct rsnd_mod_ops adg_ops = {
 28         .name = "adg",
 29 };
 30 
 31 struct rsnd_adg {
 32         struct clk *clk[CLKMAX];
 33         struct clk *clkout[CLKOUTMAX];
 34         struct clk_onecell_data onecell;
 35         struct rsnd_mod mod;
 36         u32 flags;
 37         u32 ckr;
 38         u32 rbga;
 39         u32 rbgb;
 40 
 41         int rbga_rate_for_441khz; /* RBGA */
 42         int rbgb_rate_for_48khz;  /* RBGB */
 43 };
 44 
 45 #define LRCLK_ASYNC     (1 << 0)
 46 #define adg_mode_flags(adg)     (adg->flags)
 47 
 48 #define for_each_rsnd_clk(pos, adg, i)          \
 49         for (i = 0;                             \
 50              (i < CLKMAX) &&                    \
 51              ((pos) = adg->clk[i]);             \
 52              i++)
 53 #define for_each_rsnd_clkout(pos, adg, i)       \
 54         for (i = 0;                             \
 55              (i < CLKOUTMAX) &&                 \
 56              ((pos) = adg->clkout[i]);  \
 57              i++)
 58 #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
 59 
 60 static u32 rsnd_adg_calculate_rbgx(unsigned long div)
 61 {
 62         int i, ratio;
 63 
 64         if (!div)
 65                 return 0;
 66 
 67         for (i = 3; i >= 0; i--) {
 68                 ratio = 2 << (i * 2);
 69                 if (0 == (div % ratio))
 70                         return (u32)((i << 8) | ((div / ratio) - 1));
 71         }
 72 
 73         return ~0;
 74 }
 75 
 76 static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
 77 {
 78         struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
 79         int id = rsnd_mod_id(ssi_mod);
 80         int ws = id;
 81 
 82         if (rsnd_ssi_is_pin_sharing(io)) {
 83                 switch (id) {
 84                 case 1:
 85                 case 2:
 86                         ws = 0;
 87                         break;
 88                 case 4:
 89                         ws = 3;
 90                         break;
 91                 case 8:
 92                         ws = 7;
 93                         break;
 94                 }
 95         }
 96 
 97         return (0x6 + ws) << 8;
 98 }
 99 
100 static void __rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
101                                        struct rsnd_dai_stream *io,
102                                        unsigned int target_rate,
103                                        unsigned int *target_val,
104                                        unsigned int *target_en)
105 {
106         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
107         struct device *dev = rsnd_priv_to_dev(priv);
108         int idx, sel, div, step;
109         unsigned int val, en;
110         unsigned int min, diff;
111         unsigned int sel_rate[] = {
112                 clk_get_rate(adg->clk[CLKA]),   /* 0000: CLKA */
113                 clk_get_rate(adg->clk[CLKB]),   /* 0001: CLKB */
114                 clk_get_rate(adg->clk[CLKC]),   /* 0010: CLKC */
115                 adg->rbga_rate_for_441khz,      /* 0011: RBGA */
116                 adg->rbgb_rate_for_48khz,       /* 0100: RBGB */
117         };
118 
119         min = ~0;
120         val = 0;
121         en = 0;
122         for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) {
123                 idx = 0;
124                 step = 2;
125 
126                 if (!sel_rate[sel])
127                         continue;
128 
129                 for (div = 2; div <= 98304; div += step) {
130                         diff = abs(target_rate - sel_rate[sel] / div);
131                         if (min > diff) {
132                                 val = (sel << 8) | idx;
133                                 min = diff;
134                                 en = 1 << (sel + 1); /* fixme */
135                         }
136 
137                         /*
138                          * step of 0_0000 / 0_0001 / 0_1101
139                          * are out of order
140                          */
141                         if ((idx > 2) && (idx % 2))
142                                 step *= 2;
143                         if (idx == 0x1c) {
144                                 div += step;
145                                 step *= 2;
146                         }
147                         idx++;
148                 }
149         }
150 
151         if (min == ~0) {
152                 dev_err(dev, "no Input clock\n");
153                 return;
154         }
155 
156         *target_val = val;
157         if (target_en)
158                 *target_en = en;
159 }
160 
161 static void rsnd_adg_get_timesel_ratio(struct rsnd_priv *priv,
162                                        struct rsnd_dai_stream *io,
163                                        unsigned int in_rate,
164                                        unsigned int out_rate,
165                                        u32 *in, u32 *out, u32 *en)
166 {
167         struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
168         unsigned int target_rate;
169         u32 *target_val;
170         u32 _in;
171         u32 _out;
172         u32 _en;
173 
174         /* default = SSI WS */
175         _in =
176         _out = rsnd_adg_ssi_ws_timing_gen2(io);
177 
178         target_rate = 0;
179         target_val = NULL;
180         _en = 0;
181         if (runtime->rate != in_rate) {
182                 target_rate = out_rate;
183                 target_val  = &_out;
184         } else if (runtime->rate != out_rate) {
185                 target_rate = in_rate;
186                 target_val  = &_in;
187         }
188 
189         if (target_rate)
190                 __rsnd_adg_get_timesel_ratio(priv, io,
191                                              target_rate,
192                                              target_val, &_en);
193 
194         if (in)
195                 *in = _in;
196         if (out)
197                 *out = _out;
198         if (en)
199                 *en = _en;
200 }
201 
202 int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod,
203                                  struct rsnd_dai_stream *io)
204 {
205         struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod);
206         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
207         struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
208         int id = rsnd_mod_id(cmd_mod);
209         int shift = (id % 2) ? 16 : 0;
210         u32 mask, val;
211 
212         rsnd_adg_get_timesel_ratio(priv, io,
213                                    rsnd_src_get_in_rate(priv, io),
214                                    rsnd_src_get_out_rate(priv, io),
215                                    NULL, &val, NULL);
216 
217         val  = val      << shift;
218         mask = 0xffff   << shift;
219 
220         rsnd_mod_bset(adg_mod, CMDOUT_TIMSEL, mask, val);
221 
222         return 0;
223 }
224 
225 int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod,
226                                   struct rsnd_dai_stream *io,
227                                   unsigned int in_rate,
228                                   unsigned int out_rate)
229 {
230         struct rsnd_priv *priv = rsnd_mod_to_priv(src_mod);
231         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
232         struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
233         u32 in, out;
234         u32 mask, en;
235         int id = rsnd_mod_id(src_mod);
236         int shift = (id % 2) ? 16 : 0;
237 
238         rsnd_mod_confirm_src(src_mod);
239 
240         rsnd_adg_get_timesel_ratio(priv, io,
241                                    in_rate, out_rate,
242                                    &in, &out, &en);
243 
244         in   = in       << shift;
245         out  = out      << shift;
246         mask = 0xffff   << shift;
247 
248         switch (id / 2) {
249         case 0:
250                 rsnd_mod_bset(adg_mod, SRCIN_TIMSEL0,  mask, in);
251                 rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL0, mask, out);
252                 break;
253         case 1:
254                 rsnd_mod_bset(adg_mod, SRCIN_TIMSEL1,  mask, in);
255                 rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL1, mask, out);
256                 break;
257         case 2:
258                 rsnd_mod_bset(adg_mod, SRCIN_TIMSEL2,  mask, in);
259                 rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL2, mask, out);
260                 break;
261         case 3:
262                 rsnd_mod_bset(adg_mod, SRCIN_TIMSEL3,  mask, in);
263                 rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL3, mask, out);
264                 break;
265         case 4:
266                 rsnd_mod_bset(adg_mod, SRCIN_TIMSEL4,  mask, in);
267                 rsnd_mod_bset(adg_mod, SRCOUT_TIMSEL4, mask, out);
268                 break;
269         }
270 
271         if (en)
272                 rsnd_mod_bset(adg_mod, DIV_EN, en, en);
273 
274         return 0;
275 }
276 
277 static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val)
278 {
279         struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
280         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
281         struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
282         int id = rsnd_mod_id(ssi_mod);
283         int shift = (id % 4) * 8;
284         u32 mask = 0xFF << shift;
285 
286         rsnd_mod_confirm_ssi(ssi_mod);
287 
288         val = val << shift;
289 
290         /*
291          * SSI 8 is not connected to ADG.
292          * it works with SSI 7
293          */
294         if (id == 8)
295                 return;
296 
297         switch (id / 4) {
298         case 0:
299                 rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL0, mask, val);
300                 break;
301         case 1:
302                 rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL1, mask, val);
303                 break;
304         case 2:
305                 rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL2, mask, val);
306                 break;
307         }
308 }
309 
310 int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod)
311 {
312         rsnd_adg_set_ssi_clk(ssi_mod, 0);
313 
314         return 0;
315 }
316 
317 int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate)
318 {
319         struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
320         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
321         struct device *dev = rsnd_priv_to_dev(priv);
322         struct rsnd_mod *adg_mod = rsnd_mod_get(adg);
323         struct clk *clk;
324         int i;
325         u32 data;
326         u32 ckr = 0;
327         int sel_table[] = {
328                 [CLKA] = 0x1,
329                 [CLKB] = 0x2,
330                 [CLKC] = 0x3,
331                 [CLKI] = 0x0,
332         };
333 
334         dev_dbg(dev, "request clock = %d\n", rate);
335 
336         /*
337          * find suitable clock from
338          * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
339          */
340         data = 0;
341         for_each_rsnd_clk(clk, adg, i) {
342                 if (rate == clk_get_rate(clk)) {
343                         data = sel_table[i];
344                         goto found_clock;
345                 }
346         }
347 
348         /*
349          * find divided clock from BRGA/BRGB
350          */
351         if (rate  == adg->rbga_rate_for_441khz) {
352                 data = 0x10;
353                 goto found_clock;
354         }
355 
356         if (rate == adg->rbgb_rate_for_48khz) {
357                 data = 0x20;
358                 goto found_clock;
359         }
360 
361         return -EIO;
362 
363 found_clock:
364 
365         rsnd_adg_set_ssi_clk(ssi_mod, data);
366 
367         if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) {
368                 if (0 == (rate % 8000))
369                         ckr = 0x80000000;
370         }
371 
372         rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr);
373         rsnd_mod_write(adg_mod, BRRA,  adg->rbga);
374         rsnd_mod_write(adg_mod, BRRB,  adg->rbgb);
375 
376         dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n",
377                 rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod),
378                 data, rate);
379 
380         return 0;
381 }
382 
383 void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable)
384 {
385         struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
386         struct device *dev = rsnd_priv_to_dev(priv);
387         struct clk *clk;
388         int i, ret;
389 
390         for_each_rsnd_clk(clk, adg, i) {
391                 ret = 0;
392                 if (enable)
393                         ret = clk_prepare_enable(clk);
394                 else
395                         clk_disable_unprepare(clk);
396 
397                 if (ret < 0)
398                         dev_warn(dev, "can't use clk %d\n", i);
399         }
400 }
401 
402 static void rsnd_adg_get_clkin(struct rsnd_priv *priv,
403                                struct rsnd_adg *adg)
404 {
405         struct device *dev = rsnd_priv_to_dev(priv);
406         struct clk *clk;
407         static const char * const clk_name[] = {
408                 [CLKA]  = "clk_a",
409                 [CLKB]  = "clk_b",
410                 [CLKC]  = "clk_c",
411                 [CLKI]  = "clk_i",
412         };
413         int i;
414 
415         for (i = 0; i < CLKMAX; i++) {
416                 clk = devm_clk_get(dev, clk_name[i]);
417                 adg->clk[i] = IS_ERR(clk) ? NULL : clk;
418         }
419 
420         for_each_rsnd_clk(clk, adg, i)
421                 dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
422 }
423 
424 static void rsnd_adg_get_clkout(struct rsnd_priv *priv,
425                                 struct rsnd_adg *adg)
426 {
427         struct clk *clk;
428         struct device *dev = rsnd_priv_to_dev(priv);
429         struct device_node *np = dev->of_node;
430         u32 ckr, rbgx, rbga, rbgb;
431         u32 rate, req_rate = 0, div;
432         uint32_t count = 0;
433         unsigned long req_48kHz_rate, req_441kHz_rate;
434         int i;
435         const char *parent_clk_name = NULL;
436         static const char * const clkout_name[] = {
437                 [CLKOUT]  = "audio_clkout",
438                 [CLKOUT1] = "audio_clkout1",
439                 [CLKOUT2] = "audio_clkout2",
440                 [CLKOUT3] = "audio_clkout3",
441         };
442         int brg_table[] = {
443                 [CLKA] = 0x0,
444                 [CLKB] = 0x1,
445                 [CLKC] = 0x4,
446                 [CLKI] = 0x2,
447         };
448 
449         of_property_read_u32(np, "#clock-cells", &count);
450 
451         /*
452          * ADG supports BRRA/BRRB output only
453          * this means all clkout0/1/2/3 will be same rate
454          */
455         of_property_read_u32(np, "clock-frequency", &req_rate);
456         req_48kHz_rate = 0;
457         req_441kHz_rate = 0;
458         if (0 == (req_rate % 44100))
459                 req_441kHz_rate = req_rate;
460         if (0 == (req_rate % 48000))
461                 req_48kHz_rate = req_rate;
462 
463         /*
464          * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
465          * have 44.1kHz or 48kHz base clocks for now.
466          *
467          * SSI itself can divide parent clock by 1/1 - 1/16
468          * see
469          *      rsnd_adg_ssi_clk_try_start()
470          *      rsnd_ssi_master_clk_start()
471          */
472         ckr = 0;
473         rbga = 2; /* default 1/6 */
474         rbgb = 2; /* default 1/6 */
475         adg->rbga_rate_for_441khz       = 0;
476         adg->rbgb_rate_for_48khz        = 0;
477         for_each_rsnd_clk(clk, adg, i) {
478                 rate = clk_get_rate(clk);
479 
480                 if (0 == rate) /* not used */
481                         continue;
482 
483                 /* RBGA */
484                 if (!adg->rbga_rate_for_441khz && (0 == rate % 44100)) {
485                         div = 6;
486                         if (req_441kHz_rate)
487                                 div = rate / req_441kHz_rate;
488                         rbgx = rsnd_adg_calculate_rbgx(div);
489                         if (BRRx_MASK(rbgx) == rbgx) {
490                                 rbga = rbgx;
491                                 adg->rbga_rate_for_441khz = rate / div;
492                                 ckr |= brg_table[i] << 20;
493                                 if (req_441kHz_rate)
494                                         parent_clk_name = __clk_get_name(clk);
495                         }
496                 }
497 
498                 /* RBGB */
499                 if (!adg->rbgb_rate_for_48khz && (0 == rate % 48000)) {
500                         div = 6;
501                         if (req_48kHz_rate)
502                                 div = rate / req_48kHz_rate;
503                         rbgx = rsnd_adg_calculate_rbgx(div);
504                         if (BRRx_MASK(rbgx) == rbgx) {
505                                 rbgb = rbgx;
506                                 adg->rbgb_rate_for_48khz = rate / div;
507                                 ckr |= brg_table[i] << 16;
508                                 if (req_48kHz_rate) {
509                                         parent_clk_name = __clk_get_name(clk);
510                                         ckr |= 0x80000000;
511                                 }
512                         }
513                 }
514         }
515 
516         /*
517          * ADG supports BRRA/BRRB output only.
518          * this means all clkout0/1/2/3 will be * same rate
519          */
520 
521         /*
522          * for clkout
523          */
524         if (!count) {
525                 clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT],
526                                               parent_clk_name, 0, req_rate);
527                 if (!IS_ERR(clk)) {
528                         adg->clkout[CLKOUT] = clk;
529                         of_clk_add_provider(np, of_clk_src_simple_get, clk);
530                 }
531         }
532         /*
533          * for clkout0/1/2/3
534          */
535         else {
536                 for (i = 0; i < CLKOUTMAX; i++) {
537                         clk = clk_register_fixed_rate(dev, clkout_name[i],
538                                                       parent_clk_name, 0,
539                                                       req_rate);
540                         if (!IS_ERR(clk)) {
541                                 adg->onecell.clks       = adg->clkout;
542                                 adg->onecell.clk_num    = CLKOUTMAX;
543 
544                                 adg->clkout[i] = clk;
545 
546                                 of_clk_add_provider(np, of_clk_src_onecell_get,
547                                                     &adg->onecell);
548                         }
549                 }
550         }
551 
552         adg->ckr = ckr;
553         adg->rbga = rbga;
554         adg->rbgb = rbgb;
555 
556         for_each_rsnd_clkout(clk, adg, i)
557                 dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk));
558         dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n",
559                 ckr, rbga, rbgb);
560 }
561 
562 int rsnd_adg_probe(struct rsnd_priv *priv)
563 {
564         struct rsnd_adg *adg;
565         struct device *dev = rsnd_priv_to_dev(priv);
566         struct device_node *np = dev->of_node;
567 
568         adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
569         if (!adg) {
570                 dev_err(dev, "ADG allocate failed\n");
571                 return -ENOMEM;
572         }
573 
574         rsnd_mod_init(priv, &adg->mod, &adg_ops,
575                       NULL, NULL, 0, 0);
576 
577         rsnd_adg_get_clkin(priv, adg);
578         rsnd_adg_get_clkout(priv, adg);
579 
580         if (of_get_property(np, "clkout-lr-asynchronous", NULL))
581                 adg->flags = LRCLK_ASYNC;
582 
583         priv->adg = adg;
584 
585         rsnd_adg_clk_enable(priv);
586 
587         return 0;
588 }
589 
590 void rsnd_adg_remove(struct rsnd_priv *priv)
591 {
592         rsnd_adg_clk_disable(priv);
593 }
594 

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

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | 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.

osdn.jp