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

TOMOYO Linux Cross Reference
Linux/sound/soc/generic/audio-graph-card2.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 // ASoC Audio Graph Card2 support
  4 //
  5 // Copyright (C) 2020 Renesas Electronics Corp.
  6 // Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
  7 //
  8 // based on ${LINUX}/sound/soc/generic/audio-graph-card.c
  9 #include <linux/clk.h>
 10 #include <linux/device.h>
 11 #include <linux/gpio/consumer.h>
 12 #include <linux/module.h>
 13 #include <linux/of.h>
 14 #include <linux/of_graph.h>
 15 #include <linux/platform_device.h>
 16 #include <linux/string.h>
 17 #include <sound/graph_card.h>
 18 
 19 /************************************
 20         daifmt
 21  ************************************
 22         ports {
 23                 format = "left_j";
 24                 port@0 {
 25                         bitclock-master;
 26                         sample0: endpoint@0 {
 27                                 frame-master;
 28                         };
 29                         sample1: endpoint@1 {
 30                                 format = "i2s";
 31                         };
 32                 };
 33                 ...
 34         };
 35 
 36  You can set daifmt at ports/port/endpoint.
 37  It uses *latest* format, and *share* master settings.
 38  In above case,
 39         sample0: left_j, bitclock-master, frame-master
 40         sample1: i2s,    bitclock-master
 41 
 42  If there was no settings, *Codec* will be
 43  bitclock/frame provider as default.
 44  see
 45         graph_parse_daifmt().
 46 
 47  "format" property is no longer needed on DT if both CPU/Codec drivers are
 48  supporting snd_soc_dai_ops :: .auto_selectable_formats.
 49  see
 50         snd_soc_runtime_get_dai_fmt()
 51 
 52         sample driver
 53                 linux/sound/soc/sh/rcar/core.c
 54                 linux/sound/soc/codecs/ak4613.c
 55                 linux/sound/soc/codecs/pcm3168a.c
 56                 linux/sound/soc/soc-utils.c
 57                 linux/sound/soc/generic/test-component.c
 58 
 59  ************************************
 60         Normal Audio-Graph
 61  ************************************
 62 
 63  CPU <---> Codec
 64 
 65  sound {
 66         compatible = "audio-graph-card2";
 67         links = <&cpu>;
 68  };
 69 
 70  CPU {
 71         cpu: port {
 72                 bitclock-master;
 73                 frame-master;
 74                 cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; };
 75  };
 76 
 77  Codec {
 78         port {  codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; };
 79  };
 80 
 81  ************************************
 82         Multi-CPU/Codec
 83  ************************************
 84 
 85 It has link connection part (= X,x) and list part (= A,B,a,b).
 86 "links" is connection part of CPU side (= @).
 87 
 88         +----+          +---+
 89  CPU1 --|A  X| <-@----> |x a|-- Codec1
 90  CPU2 --|B   |          |  b|-- Codec2
 91         +----+          +---+
 92 
 93  sound {
 94         compatible = "audio-graph-card2";
 95 
 96 (@)     links = <&mcpu>;
 97 
 98         multi {
 99                 ports@0 {
100 (@)             mcpu:   port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>;  }; };   // (X) to pair
101                         port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>;     }; };   // (A) Multi Element
102                         port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>;     }; };   // (B) Multi Element
103                 };
104                 ports@1 {
105                         port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>;  }; };   // (x) to pair
106                         port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };   // (a) Multi Element
107                         port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };   // (b) Multi Element
108                 };
109         };
110  };
111 
112  CPU {
113         ports {
114                 bitclock-master;
115                 frame-master;
116                 port@0 { cpu1_ep: endpoint { remote-endpoint = <&mcpu1_ep>; }; };
117                 port@1 { cpu2_ep: endpoint { remote-endpoint = <&mcpu2_ep>; }; };
118         };
119  };
120 
121  Codec {
122         ports {
123                 port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
124                 port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
125         };
126  };
127 
128  ************************************
129         DPCM
130  ************************************
131 
132                 DSP
133            ************
134  PCM0 <--> * fe0  be0 * <--> DAI0: Codec Headset
135  PCM1 <--> * fe1  be1 * <--> DAI1: Codec Speakers
136  PCM2 <--> * fe2  be2 * <--> DAI2: MODEM
137  PCM3 <--> * fe3  be3 * <--> DAI3: BT
138            *      be4 * <--> DAI4: DMIC
139            *      be5 * <--> DAI5: FM
140            ************
141 
142  sound {
143         compatible = "audio-graph-card2";
144 
145         // indicate routing
146         routing = "xxx Playback", "xxx Playback",
147                   "xxx Playback", "xxx Playback",
148                   "xxx Playback", "xxx Playback";
149 
150         // indicate all Front-End, Back-End
151         links = <&fe0, &fe1, ...,
152                  &be0, &be1, ...>;
153 
154         dpcm {
155                 // Front-End
156                 ports@0 {
157                         fe0: port@0 { fe0_ep: endpoint { remote-endpoint = <&pcm0_ep>; }; };
158                         fe1: port@1 { fe1_ep: endpoint { remote-endpoint = <&pcm1_ep>; }; };
159                         ...
160                 };
161                 // Back-End
162                 ports@1 {
163                         be0: port@0 { be0_ep: endpoint { remote-endpoint = <&dai0_ep>; }; };
164                         be1: port@1 { be1_ep: endpoint { remote-endpoint = <&dai1_ep>; }; };
165                         ...
166                 };
167         };
168  };
169 
170  CPU {
171         ports {
172                 bitclock-master;
173                 frame-master;
174                 port@0 { pcm0_ep: endpoint { remote-endpoint = <&fe0_ep>; }; };
175                 port@1 { pcm1_ep: endpoint { remote-endpoint = <&fe1_ep>; }; };
176                 ...
177         };
178  };
179 
180  Codec {
181         ports {
182                 port@0 { dai0_ep: endpoint { remote-endpoint = <&be0_ep>; }; };
183                 port@1 { dai1_ep: endpoint { remote-endpoint = <&be1_ep>; }; };
184                 ...
185         };
186  };
187 
188  ************************************
189         Codec to Codec
190  ************************************
191 
192  +--+
193  |  |<-- Codec0 <- IN
194  |  |--> Codec1 -> OUT
195  +--+
196 
197  sound {
198         compatible = "audio-graph-card2";
199 
200         routing = "OUT" ,"DAI1 Playback",
201                   "DAI0 Capture", "IN";
202 
203         links = <&c2c>;
204 
205         codec2codec {
206                 ports {
207                         rate = <48000>;
208                 c2c:    port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
209                         port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
210         };
211  };
212 
213  Codec {
214         ports {
215                 port@0 {
216                         bitclock-master;
217                         frame-master;
218                          codec0_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; };
219                 port@1 { codec1_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; };
220         };
221  };
222 
223 */
224 
225 enum graph_type {
226         GRAPH_NORMAL,
227         GRAPH_DPCM,
228         GRAPH_C2C,
229 
230         GRAPH_MULTI,    /* don't use ! Use this only in __graph_get_type() */
231 };
232 
233 #define GRAPH_NODENAME_MULTI    "multi"
234 #define GRAPH_NODENAME_DPCM     "dpcm"
235 #define GRAPH_NODENAME_C2C      "codec2codec"
236 
237 #define port_to_endpoint(port) of_get_child_by_name(port, "endpoint")
238 
239 #define ep_to_port(ep)  of_get_parent(ep)
240 static struct device_node *port_to_ports(struct device_node *port)
241 {
242         struct device_node *ports = of_get_parent(port);
243 
244         if (!of_node_name_eq(ports, "ports")) {
245                 of_node_put(ports);
246                 return NULL;
247         }
248         return ports;
249 }
250 
251 static enum graph_type __graph_get_type(struct device_node *lnk)
252 {
253         struct device_node *np, *parent_np;
254         enum graph_type ret;
255 
256         /*
257          * target {
258          *      ports {
259          * =>           lnk:    port@0 { ... };
260          *                      port@1 { ... };
261          *      };
262          * };
263          */
264         np = of_get_parent(lnk);
265         if (of_node_name_eq(np, "ports")) {
266                 parent_np = of_get_parent(np);
267                 of_node_put(np);
268                 np = parent_np;
269         }
270 
271         if (of_node_name_eq(np, GRAPH_NODENAME_MULTI)) {
272                 ret = GRAPH_MULTI;
273                 goto out_put;
274         }
275 
276         if (of_node_name_eq(np, GRAPH_NODENAME_DPCM)) {
277                 ret = GRAPH_DPCM;
278                 goto out_put;
279         }
280 
281         if (of_node_name_eq(np, GRAPH_NODENAME_C2C)) {
282                 ret = GRAPH_C2C;
283                 goto out_put;
284         }
285 
286         ret = GRAPH_NORMAL;
287 
288 out_put:
289         of_node_put(np);
290         return ret;
291 
292 }
293 
294 static enum graph_type graph_get_type(struct simple_util_priv *priv,
295                                       struct device_node *lnk)
296 {
297         enum graph_type type = __graph_get_type(lnk);
298 
299         /* GRAPH_MULTI here means GRAPH_NORMAL */
300         if (type == GRAPH_MULTI)
301                 type = GRAPH_NORMAL;
302 
303 #ifdef DEBUG
304         {
305                 struct device *dev = simple_priv_to_dev(priv);
306                 const char *str = "Normal";
307 
308                 switch (type) {
309                 case GRAPH_DPCM:
310                         if (graph_util_is_ports0(lnk))
311                                 str = "DPCM Front-End";
312                         else
313                                 str = "DPCM Back-End";
314                         break;
315                 case GRAPH_C2C:
316                         str = "Codec2Codec";
317                         break;
318                 default:
319                         break;
320                 }
321 
322                 dev_dbg(dev, "%pOF (%s)", lnk, str);
323         }
324 #endif
325         return type;
326 }
327 
328 static int graph_lnk_is_multi(struct device_node *lnk)
329 {
330         return __graph_get_type(lnk) == GRAPH_MULTI;
331 }
332 
333 static struct device_node *graph_get_next_multi_ep(struct device_node **port)
334 {
335         struct device_node *ports = port_to_ports(*port);
336         struct device_node *ep = NULL;
337         struct device_node *rep = NULL;
338 
339         /*
340          * multi {
341          *      ports {
342          * =>   lnk:    port@0 { ...               }; // to pair
343          *              port@1 { ep { ... = rep0 } }; // Multi Element
344          *              port@2 { ep { ... = rep1 } }; // Multi Element
345          *              ...
346          *      };
347          * };
348          *
349          * xxx {
350          *      port@0 { rep0 };
351          *      port@1 { rep1 };
352          * };
353          */
354         do {
355                 *port = of_get_next_child(ports, *port);
356                 if (!*port)
357                         break;
358         } while (!of_node_name_eq(*port, "port"));
359 
360         if (*port) {
361                 ep  = port_to_endpoint(*port);
362                 rep = of_graph_get_remote_endpoint(ep);
363         }
364 
365         of_node_put(ep);
366         of_node_put(ports);
367 
368         return rep;
369 }
370 
371 static const struct snd_soc_ops graph_ops = {
372         .startup        = simple_util_startup,
373         .shutdown       = simple_util_shutdown,
374         .hw_params      = simple_util_hw_params,
375 };
376 
377 static void graph_parse_convert(struct device_node *ep,
378                                 struct simple_dai_props *props)
379 {
380         struct device_node *port = ep_to_port(ep);
381         struct device_node *ports = port_to_ports(port);
382         struct simple_util_data *adata = &props->adata;
383 
384         simple_util_parse_convert(ports, NULL, adata);
385         simple_util_parse_convert(port, NULL, adata);
386         simple_util_parse_convert(ep,   NULL, adata);
387 
388         of_node_put(port);
389         of_node_put(ports);
390 }
391 
392 static int __graph_parse_node(struct simple_util_priv *priv,
393                               enum graph_type gtype,
394                               struct device_node *ep,
395                               struct link_info *li,
396                               int is_cpu, int idx)
397 {
398         struct device *dev = simple_priv_to_dev(priv);
399         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
400         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
401         struct snd_soc_dai_link_component *dlc;
402         struct simple_util_dai *dai;
403         int ret, is_single_links = 0;
404 
405         if (is_cpu) {
406                 dlc = snd_soc_link_to_cpu(dai_link, idx);
407                 dai = simple_props_to_dai_cpu(dai_props, idx);
408         } else {
409                 dlc = snd_soc_link_to_codec(dai_link, idx);
410                 dai = simple_props_to_dai_codec(dai_props, idx);
411         }
412 
413         ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links);
414         if (ret < 0)
415                 return ret;
416 
417         ret = simple_util_parse_tdm(ep, dai);
418         if (ret < 0)
419                 return ret;
420 
421         ret = simple_util_parse_tdm_width_map(dev, ep, dai);
422         if (ret < 0)
423                 return ret;
424 
425         ret = simple_util_parse_clk(dev, ep, dai, dlc);
426         if (ret < 0)
427                 return ret;
428 
429         /*
430          * set DAI Name
431          */
432         if (!dai_link->name) {
433                 struct snd_soc_dai_link_component *cpus = dlc;
434                 struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
435                 char *cpu_multi   = "";
436                 char *codec_multi = "";
437 
438                 if (dai_link->num_cpus > 1)
439                         cpu_multi = "_multi";
440                 if (dai_link->num_codecs > 1)
441                         codec_multi = "_multi";
442 
443                 switch (gtype) {
444                 case GRAPH_NORMAL:
445                         /* run is_cpu only. see audio_graph2_link_normal() */
446                         if (is_cpu)
447                                 simple_util_set_dailink_name(dev, dai_link, "%s%s-%s%s",
448                                                                cpus->dai_name,   cpu_multi,
449                                                              codecs->dai_name, codec_multi);
450                         break;
451                 case GRAPH_DPCM:
452                         if (is_cpu)
453                                 simple_util_set_dailink_name(dev, dai_link, "fe.%pOFP.%s%s",
454                                                 cpus->of_node, cpus->dai_name, cpu_multi);
455                         else
456                                 simple_util_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s",
457                                                 codecs->of_node, codecs->dai_name, codec_multi);
458                         break;
459                 case GRAPH_C2C:
460                         /* run is_cpu only. see audio_graph2_link_c2c() */
461                         if (is_cpu)
462                                 simple_util_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s",
463                                                              cpus->dai_name,   cpu_multi,
464                                                              codecs->dai_name, codec_multi);
465                         break;
466                 default:
467                         break;
468                 }
469         }
470 
471         /*
472          * Check "prefix" from top node
473          * if DPCM-BE case
474          */
475         if (!is_cpu && gtype == GRAPH_DPCM) {
476                 struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, idx);
477                 struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, idx);
478                 struct device_node *rport  = ep_to_port(ep);
479                 struct device_node *rports = port_to_ports(rport);
480 
481                 snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix");
482                 snd_soc_of_parse_node_prefix(rport,  cconf, codecs->of_node, "prefix");
483 
484                 of_node_put(rport);
485                 of_node_put(rports);
486         }
487 
488         if (is_cpu) {
489                 struct snd_soc_dai_link_component *cpus = dlc;
490                 struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, idx);
491 
492                 simple_util_canonicalize_cpu(cpus, is_single_links);
493                 simple_util_canonicalize_platform(platforms, cpus);
494         }
495 
496         return 0;
497 }
498 
499 static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link,
500                                      int *nm_idx, int cpu_idx,
501                                      struct device_node *mcpu_port)
502 {
503         /*
504          *              +---+           +---+
505          *              |  X|<-@------->|x  |
506          *              |   |           |   |
507          *      cpu0 <--|A 1|<--------->|4 a|-> codec0
508          *      cpu1 <--|B 2|<-----+--->|5 b|-> codec1
509          *      cpu2 <--|C 3|<----/     +---+
510          *              +---+
511          *
512          * multi {
513          *      ports {
514          *              port@0 { mcpu_top_ep    {...  = mcodec_ep;      }; };   // (X) to pair
515          * <mcpu_port>  port@1 { mcpu0_ep       { ... = cpu0_ep;        };      // (A) Multi Element
516          *                       mcpu0_ep_0     { ... = mcodec0_ep_0;   }; };   // (1) connected Codec
517          *              port@2 { mcpu1_ep       { ... = cpu1_ep;        };      // (B) Multi Element
518          *                       mcpu1_ep_0     { ... = mcodec1_ep_0;   }; };   // (2) connected Codec
519          *              port@3 { mcpu2_ep       { ... = cpu2_ep;        };      // (C) Multi Element
520          *                       mcpu2_ep_0     { ... = mcodec1_ep_1;   }; };   // (3) connected Codec
521          *      };
522          *
523          *      ports {
524          *              port@0 { mcodec_top_ep  {...  = mcpu_ep;        }; };   // (x) to pair
525          * <mcodec_port>port@1 { mcodec0_ep     { ... = codec0_ep;      };      // (a) Multi Element
526          *                       mcodec0_ep_0   { ... = mcpu0_ep_0;     }; };   // (4) connected CPU
527          *              port@2 { mcodec1_ep     { ... = codec1_ep;      };      // (b) Multi Element
528          *                       mcodec1_ep_0   { ... = mcpu1_ep_0;     };      // (5) connected CPU
529          *                       mcodec1_ep_1   { ... = mcpu2_ep_0;     }; };   // (5) connected CPU
530          *      };
531          * };
532          */
533         struct device_node *mcpu_ep             = port_to_endpoint(mcpu_port);
534         struct device_node *mcpu_ep_n           = mcpu_ep;
535         struct device_node *mcpu_port_top       = of_get_next_child(port_to_ports(mcpu_port), NULL);
536         struct device_node *mcpu_ep_top         = port_to_endpoint(mcpu_port_top);
537         struct device_node *mcodec_ep_top       = of_graph_get_remote_endpoint(mcpu_ep_top);
538         struct device_node *mcodec_port_top     = ep_to_port(mcodec_ep_top);
539         struct device_node *mcodec_ports        = port_to_ports(mcodec_port_top);
540         int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
541         int ret = -EINVAL;
542 
543         if (cpu_idx > dai_link->num_cpus)
544                 goto mcpu_err;
545 
546         while (1) {
547                 struct device_node *mcodec_ep_n;
548                 struct device_node *mcodec_port_i;
549                 struct device_node *mcodec_port;
550                 int codec_idx;
551 
552                 if (*nm_idx > nm_max)
553                         break;
554 
555                 mcpu_ep_n = of_get_next_child(mcpu_port, mcpu_ep_n);
556                 if (!mcpu_ep_n) {
557                         ret = 0;
558                         break;
559                 }
560 
561                 mcodec_ep_n     = of_graph_get_remote_endpoint(mcpu_ep_n);
562                 mcodec_port     = ep_to_port(mcodec_ep_n);
563 
564                 if (mcodec_ports != port_to_ports(mcodec_port))
565                         goto mcpu_err;
566 
567                 codec_idx = 0;
568                 mcodec_port_i = of_get_next_child(mcodec_ports, NULL);
569                 while (1) {
570                         if (codec_idx > dai_link->num_codecs)
571                                 goto mcodec_err;
572 
573                         mcodec_port_i = of_get_next_child(mcodec_ports, mcodec_port_i);
574 
575                         if (!mcodec_port_i)
576                                 goto mcodec_err;
577 
578                         if (mcodec_port_i == mcodec_port)
579                                 break;
580 
581                         codec_idx++;
582                 }
583 
584                 dai_link->ch_maps[*nm_idx].cpu          = cpu_idx;
585                 dai_link->ch_maps[*nm_idx].codec        = codec_idx;
586 
587                 (*nm_idx)++;
588 
589                 of_node_put(mcodec_port_i);
590 mcodec_err:
591                 of_node_put(mcodec_port);
592                 of_node_put(mcpu_ep_n);
593                 of_node_put(mcodec_ep_n);
594         }
595 mcpu_err:
596         of_node_put(mcpu_ep);
597         of_node_put(mcpu_port_top);
598         of_node_put(mcpu_ep_top);
599         of_node_put(mcodec_ep_top);
600         of_node_put(mcodec_port_top);
601         of_node_put(mcodec_ports);
602 
603         return ret;
604 }
605 
606 static int graph_parse_node_multi(struct simple_util_priv *priv,
607                                   enum graph_type gtype,
608                                   struct device_node *port,
609                                   struct link_info *li, int is_cpu)
610 {
611         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
612         struct device *dev = simple_priv_to_dev(priv);
613         struct device_node *ep;
614         int ret = -ENOMEM;
615         int nm_idx = 0;
616         int nm_max = max(dai_link->num_cpus, dai_link->num_codecs);
617 
618         /*
619          * create ch_maps if CPU:Codec = N:M
620          * DPCM is out of scope
621          */
622         if (gtype != GRAPH_DPCM && !dai_link->ch_maps &&
623             dai_link->num_cpus > 1 && dai_link->num_codecs > 1 &&
624             dai_link->num_cpus != dai_link->num_codecs) {
625 
626                 dai_link->ch_maps = devm_kcalloc(dev, nm_max,
627                                         sizeof(struct snd_soc_dai_link_ch_map), GFP_KERNEL);
628                 if (!dai_link->ch_maps)
629                         goto multi_err;
630         }
631 
632         for (int idx = 0;; idx++) {
633                 /*
634                  * multi {
635                  *      ports {
636                  * <port>       port@0 { ...                        }; // to pair
637                  *              port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element
638                  *              port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element
639                  *      };
640                  * };
641                  *
642                  * cpu {
643                  *      ports {
644                  * <ep>         port@0 { cpu1_ep   { ... = mcpu1_ep };};
645                  *      };
646                  * };
647                  */
648                 ep = graph_get_next_multi_ep(&port);
649                 if (!ep)
650                         break;
651 
652                 ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, idx);
653                 of_node_put(ep);
654                 if (ret < 0)
655                         goto multi_err;
656 
657                 /* CPU:Codec = N:M */
658                 if (is_cpu && dai_link->ch_maps) {
659                         ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port);
660                         if (ret < 0)
661                                 goto multi_err;
662                 }
663         }
664 
665         if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max))
666                 ret = -EINVAL;
667 
668 multi_err:
669         return ret;
670 }
671 
672 static int graph_parse_node_single(struct simple_util_priv *priv,
673                                    enum graph_type gtype,
674                                    struct device_node *port,
675                                    struct link_info *li, int is_cpu)
676 {
677         struct device_node *ep = port_to_endpoint(port);
678         int ret = __graph_parse_node(priv, gtype, ep, li, is_cpu, 0);
679 
680         of_node_put(ep);
681 
682         return ret;
683 }
684 
685 static int graph_parse_node(struct simple_util_priv *priv,
686                             enum graph_type gtype,
687                             struct device_node *port,
688                             struct link_info *li, int is_cpu)
689 {
690         if (graph_lnk_is_multi(port))
691                 return graph_parse_node_multi(priv, gtype, port, li, is_cpu);
692         else
693                 return graph_parse_node_single(priv, gtype, port, li, is_cpu);
694 }
695 
696 static void graph_parse_daifmt(struct device_node *node,
697                                unsigned int *daifmt, unsigned int *bit_frame)
698 {
699         unsigned int fmt;
700 
701         if (!node)
702                 return;
703 
704         /*
705          * see also above "daifmt" explanation
706          * and samples.
707          */
708 
709         /*
710          *      ports {
711          * (A)
712          *              port {
713          * (B)
714          *                      endpoint {
715          * (C)
716          *                      };
717          *              };
718          *      };
719          * };
720          */
721 
722         /*
723          * clock_provider:
724          *
725          * It can be judged it is provider
726          * if (A) or (B) or (C) has bitclock-master / frame-master flag.
727          *
728          * use "or"
729          */
730         *bit_frame |= snd_soc_daifmt_parse_clock_provider_as_bitmap(node, NULL);
731 
732 #define update_daifmt(name)                                     \
733         if (!(*daifmt & SND_SOC_DAIFMT_##name##_MASK) &&        \
734                  (fmt & SND_SOC_DAIFMT_##name##_MASK))          \
735                 *daifmt |= fmt & SND_SOC_DAIFMT_##name##_MASK
736 
737         /*
738          * format
739          *
740          * This function is called by (C) -> (B) -> (A) order.
741          * Set if applicable part was not yet set.
742          */
743         fmt = snd_soc_daifmt_parse_format(node, NULL);
744         update_daifmt(FORMAT);
745         update_daifmt(CLOCK);
746         update_daifmt(INV);
747 }
748 
749 static void graph_link_init(struct simple_util_priv *priv,
750                             struct device_node *lnk,
751                             struct device_node *port_cpu,
752                             struct device_node *port_codec,
753                             struct link_info *li,
754                             int is_cpu_node)
755 {
756         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
757         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
758         struct device_node *ep_cpu, *ep_codec;
759         struct device_node *ports_cpu, *ports_codec;
760         unsigned int daifmt = 0, daiclk = 0;
761         bool playback_only = 0, capture_only = 0;
762         enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
763         enum snd_soc_trigger_order trigger_stop  = SND_SOC_TRIGGER_ORDER_DEFAULT;
764         unsigned int bit_frame = 0;
765 
766         of_node_get(port_cpu);
767         if (graph_lnk_is_multi(port_cpu)) {
768                 ep_cpu = graph_get_next_multi_ep(&port_cpu);
769                 of_node_put(port_cpu);
770                 port_cpu = ep_to_port(ep_cpu);
771         } else {
772                 ep_cpu = port_to_endpoint(port_cpu);
773         }
774         ports_cpu = port_to_ports(port_cpu);
775 
776         of_node_get(port_codec);
777         if (graph_lnk_is_multi(port_codec)) {
778                 ep_codec = graph_get_next_multi_ep(&port_codec);
779                 of_node_put(port_cpu);
780                 port_codec = ep_to_port(ep_codec);
781         } else {
782                 ep_codec = port_to_endpoint(port_codec);
783         }
784         ports_codec = port_to_ports(port_codec);
785 
786 
787         graph_parse_daifmt(ep_cpu,      &daifmt, &bit_frame);
788         graph_parse_daifmt(ep_codec,    &daifmt, &bit_frame);
789         graph_parse_daifmt(port_cpu,    &daifmt, &bit_frame);
790         graph_parse_daifmt(port_codec,  &daifmt, &bit_frame);
791         graph_parse_daifmt(ports_cpu,   &daifmt, &bit_frame);
792         graph_parse_daifmt(ports_codec, &daifmt, &bit_frame);
793         graph_parse_daifmt(lnk,         &daifmt, &bit_frame);
794 
795         graph_util_parse_link_direction(lnk,            &playback_only, &capture_only);
796         graph_util_parse_link_direction(ports_cpu,      &playback_only, &capture_only);
797         graph_util_parse_link_direction(ports_codec,    &playback_only, &capture_only);
798         graph_util_parse_link_direction(port_cpu,       &playback_only, &capture_only);
799         graph_util_parse_link_direction(port_codec,     &playback_only, &capture_only);
800         graph_util_parse_link_direction(ep_cpu,         &playback_only, &capture_only);
801         graph_util_parse_link_direction(ep_codec,       &playback_only, &capture_only);
802 
803         of_property_read_u32(lnk,               "mclk-fs", &dai_props->mclk_fs);
804         of_property_read_u32(ports_cpu,         "mclk-fs", &dai_props->mclk_fs);
805         of_property_read_u32(ports_codec,       "mclk-fs", &dai_props->mclk_fs);
806         of_property_read_u32(port_cpu,          "mclk-fs", &dai_props->mclk_fs);
807         of_property_read_u32(port_codec,        "mclk-fs", &dai_props->mclk_fs);
808         of_property_read_u32(ep_cpu,            "mclk-fs", &dai_props->mclk_fs);
809         of_property_read_u32(ep_codec,          "mclk-fs", &dai_props->mclk_fs);
810 
811         graph_util_parse_trigger_order(priv, lnk,               &trigger_start, &trigger_stop);
812         graph_util_parse_trigger_order(priv, ports_cpu,         &trigger_start, &trigger_stop);
813         graph_util_parse_trigger_order(priv, ports_codec,       &trigger_start, &trigger_stop);
814         graph_util_parse_trigger_order(priv, port_cpu,          &trigger_start, &trigger_stop);
815         graph_util_parse_trigger_order(priv, port_cpu,          &trigger_start, &trigger_stop);
816         graph_util_parse_trigger_order(priv, ep_cpu,            &trigger_start, &trigger_stop);
817         graph_util_parse_trigger_order(priv, ep_codec,          &trigger_start, &trigger_stop);
818 
819         /*
820          * convert bit_frame
821          * We need to flip clock_provider if it was CPU node,
822          * because it is Codec base.
823          */
824         daiclk = snd_soc_daifmt_clock_provider_from_bitmap(bit_frame);
825         if (is_cpu_node)
826                 daiclk = snd_soc_daifmt_clock_provider_flipped(daiclk);
827 
828         dai_link->playback_only = playback_only;
829         dai_link->capture_only  = capture_only;
830 
831         dai_link->trigger_start = trigger_start;
832         dai_link->trigger_stop  = trigger_stop;
833 
834         dai_link->dai_fmt       = daifmt | daiclk;
835         dai_link->init          = simple_util_dai_init;
836         dai_link->ops           = &graph_ops;
837         if (priv->ops)
838                 dai_link->ops   = priv->ops;
839 
840         of_node_put(ports_cpu);
841         of_node_put(ports_codec);
842         of_node_put(port_cpu);
843         of_node_put(port_codec);
844         of_node_put(ep_cpu);
845         of_node_put(ep_codec);
846 }
847 
848 int audio_graph2_link_normal(struct simple_util_priv *priv,
849                              struct device_node *lnk,
850                              struct link_info *li)
851 {
852         struct device_node *cpu_port = lnk;
853         struct device_node *cpu_ep = port_to_endpoint(cpu_port);
854         struct device_node *codec_port = of_graph_get_remote_port(cpu_ep);
855         int ret;
856 
857         /*
858          * call Codec first.
859          * see
860          *      __graph_parse_node() :: DAI Naming
861          */
862         ret = graph_parse_node(priv, GRAPH_NORMAL, codec_port, li, 0);
863         if (ret < 0)
864                 goto err;
865 
866         /*
867          * call CPU, and set DAI Name
868          */
869         ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_port, li, 1);
870         if (ret < 0)
871                 goto err;
872 
873         graph_link_init(priv, lnk, cpu_port, codec_port, li, 1);
874 err:
875         of_node_put(codec_port);
876         of_node_put(cpu_ep);
877 
878         return ret;
879 }
880 EXPORT_SYMBOL_GPL(audio_graph2_link_normal);
881 
882 int audio_graph2_link_dpcm(struct simple_util_priv *priv,
883                            struct device_node *lnk,
884                            struct link_info *li)
885 {
886         struct device_node *ep = port_to_endpoint(lnk);
887         struct device_node *rep = of_graph_get_remote_endpoint(ep);
888         struct device_node *cpu_port = NULL;
889         struct device_node *codec_port = NULL;
890         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
891         struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
892         int is_cpu = graph_util_is_ports0(lnk);
893         int ret;
894 
895         if (is_cpu) {
896                 cpu_port = of_graph_get_remote_port(ep); /* rport */
897 
898                 /*
899                  * dpcm {
900                  *      // Front-End
901                  *      ports@0 {
902                  * =>           lnk: port@0 { ep: { ... = rep }; };
903                  *               ...
904                  *      };
905                  *      // Back-End
906                  *      ports@0 {
907                  *               ...
908                  *      };
909                  * };
910                  *
911                  * CPU {
912                  *      rports: ports {
913                  *              rport: port@0 { rep: { ... = ep } };
914                  *      }
915                  * }
916                  */
917                 /*
918                  * setup CPU here, Codec is already set as dummy.
919                  * see
920                  *      simple_util_init_priv()
921                  */
922                 dai_link->dynamic               = 1;
923                 dai_link->dpcm_merged_format    = 1;
924 
925                 ret = graph_parse_node(priv, GRAPH_DPCM, cpu_port, li, 1);
926                 if (ret)
927                         goto err;
928 
929         } else {
930                 codec_port = of_graph_get_remote_port(ep); /* rport */
931 
932                 /*
933                  * dpcm {
934                  *      // Front-End
935                  *      ports@0 {
936                  *               ...
937                  *      };
938                  *      // Back-End
939                  *      ports@0 {
940                  * =>           lnk: port@0 { ep: { ... = rep; }; };
941                  *               ...
942                  *      };
943                  * };
944                  *
945                  * Codec {
946                  *      rports: ports {
947                  *              rport: port@0 { rep: { ... = ep; }; };
948                  *      }
949                  * }
950                  */
951                 /*
952                  * setup Codec here, CPU is already set as dummy.
953                  * see
954                  *      simple_util_init_priv()
955                  */
956 
957                 /* BE settings */
958                 dai_link->no_pcm                = 1;
959                 dai_link->be_hw_params_fixup    = simple_util_be_hw_params_fixup;
960 
961                 ret = graph_parse_node(priv, GRAPH_DPCM, codec_port, li, 0);
962                 if (ret < 0)
963                         goto err;
964         }
965 
966         graph_parse_convert(ep,  dai_props); /* at node of <dpcm> */
967         graph_parse_convert(rep, dai_props); /* at node of <CPU/Codec> */
968 
969         snd_soc_dai_link_set_capabilities(dai_link);
970 
971         graph_link_init(priv, lnk, cpu_port, codec_port, li, is_cpu);
972 err:
973         of_node_put(ep);
974         of_node_put(rep);
975         of_node_put(cpu_port);
976         of_node_put(codec_port);
977 
978         return ret;
979 }
980 EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm);
981 
982 int audio_graph2_link_c2c(struct simple_util_priv *priv,
983                           struct device_node *lnk,
984                           struct link_info *li)
985 {
986         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
987         struct device_node *port0, *port1, *ports;
988         struct device_node *codec0_port, *codec1_port;
989         struct device_node *ep0, *ep1;
990         u32 val = 0;
991         int ret = -EINVAL;
992 
993         /*
994          * codec2codec {
995          *      ports {
996          *              rate = <48000>;
997          * =>   lnk:    port@0 { c2c0_ep: { ... = codec0_ep; }; };
998          *              port@1 { c2c1_ep: { ... = codec1_ep; }; };
999          *      };
1000          * };
1001          *
1002          * Codec {
1003          *      ports {
1004          *              port@0 { codec0_ep: ... }; };
1005          *              port@1 { codec1_ep: ... }; };
1006          *      };
1007          * };
1008          */
1009         of_node_get(lnk);
1010         port0 = lnk;
1011         ports = port_to_ports(port0);
1012         port1 = of_get_next_child(ports, lnk);
1013 
1014         /*
1015          * Card2 can use original Codec2Codec settings if DT has.
1016          * It will use default settings if no settings on DT.
1017          * see
1018          *      simple_util_init_for_codec2codec()
1019          *
1020          * Add more settings here if needed
1021          */
1022         of_property_read_u32(ports, "rate", &val);
1023         if (val) {
1024                 struct device *dev = simple_priv_to_dev(priv);
1025                 struct snd_soc_pcm_stream *c2c_conf;
1026 
1027                 c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL);
1028                 if (!c2c_conf)
1029                         goto err1;
1030 
1031                 c2c_conf->formats       = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */
1032                 c2c_conf->rates         = SNDRV_PCM_RATE_8000_384000;
1033                 c2c_conf->rate_min      =
1034                 c2c_conf->rate_max      = val;
1035                 c2c_conf->channels_min  =
1036                 c2c_conf->channels_max  = 2; /* update ME */
1037 
1038                 dai_link->c2c_params            = c2c_conf;
1039                 dai_link->num_c2c_params        = 1;
1040         }
1041 
1042         ep0 = port_to_endpoint(port0);
1043         ep1 = port_to_endpoint(port1);
1044 
1045         codec0_port = of_graph_get_remote_port(ep0);
1046         codec1_port = of_graph_get_remote_port(ep1);
1047 
1048         /*
1049          * call Codec first.
1050          * see
1051          *      __graph_parse_node() :: DAI Naming
1052          */
1053         ret = graph_parse_node(priv, GRAPH_C2C, codec1_port, li, 0);
1054         if (ret < 0)
1055                 goto err2;
1056 
1057         /*
1058          * call CPU, and set DAI Name
1059          */
1060         ret = graph_parse_node(priv, GRAPH_C2C, codec0_port, li, 1);
1061         if (ret < 0)
1062                 goto err2;
1063 
1064         graph_link_init(priv, lnk, codec0_port, codec1_port, li, 1);
1065 err2:
1066         of_node_put(ep0);
1067         of_node_put(ep1);
1068         of_node_put(codec0_port);
1069         of_node_put(codec1_port);
1070 err1:
1071         of_node_put(ports);
1072         of_node_put(port0);
1073         of_node_put(port1);
1074 
1075         return ret;
1076 }
1077 EXPORT_SYMBOL_GPL(audio_graph2_link_c2c);
1078 
1079 static int graph_link(struct simple_util_priv *priv,
1080                       struct graph2_custom_hooks *hooks,
1081                       enum graph_type gtype,
1082                       struct device_node *lnk,
1083                       struct link_info *li)
1084 {
1085         struct device *dev = simple_priv_to_dev(priv);
1086         GRAPH2_CUSTOM func = NULL;
1087         int ret = -EINVAL;
1088 
1089         switch (gtype) {
1090         case GRAPH_NORMAL:
1091                 if (hooks && hooks->custom_normal)
1092                         func = hooks->custom_normal;
1093                 else
1094                         func = audio_graph2_link_normal;
1095                 break;
1096         case GRAPH_DPCM:
1097                 if (hooks && hooks->custom_dpcm)
1098                         func = hooks->custom_dpcm;
1099                 else
1100                         func = audio_graph2_link_dpcm;
1101                 break;
1102         case GRAPH_C2C:
1103                 if (hooks && hooks->custom_c2c)
1104                         func = hooks->custom_c2c;
1105                 else
1106                         func = audio_graph2_link_c2c;
1107                 break;
1108         default:
1109                 break;
1110         }
1111 
1112         if (!func) {
1113                 dev_err(dev, "non supported gtype (%d)\n", gtype);
1114                 goto err;
1115         }
1116 
1117         ret = func(priv, lnk, li);
1118         if (ret < 0)
1119                 goto err;
1120 
1121         li->link++;
1122 err:
1123         return ret;
1124 }
1125 
1126 static int graph_counter(struct device_node *lnk)
1127 {
1128         /*
1129          * Multi CPU / Codec
1130          *
1131          * multi {
1132          *      ports {
1133          * =>           lnk:    port@0 { ... }; // to pair
1134          *                      port@1 { ... }; // Multi Element
1135          *                      port@2 { ... }; // Multi Element
1136          *                      ...
1137          *      };
1138          * };
1139          *
1140          * ignore first lnk part
1141          */
1142         if (graph_lnk_is_multi(lnk)) {
1143                 struct device_node *ports = port_to_ports(lnk);
1144                 struct device_node *port = NULL;
1145                 int cnt = 0;
1146 
1147                 /*
1148                  * CPU/Codec = N:M case has many endpoints.
1149                  * We can't use of_graph_get_endpoint_count() here
1150                  */
1151                 while(1) {
1152                         port = of_get_next_child(ports, port);
1153                         if (!port)
1154                                 break;
1155                         cnt++;
1156                 }
1157 
1158                 return cnt - 1;
1159         }
1160         /*
1161          * Single CPU / Codec
1162          */
1163         else
1164                 return 1;
1165 }
1166 
1167 static int graph_count_normal(struct simple_util_priv *priv,
1168                               struct device_node *lnk,
1169                               struct link_info *li)
1170 {
1171         struct device_node *cpu_port = lnk;
1172         struct device_node *cpu_ep = port_to_endpoint(cpu_port);
1173         struct device_node *codec_port = of_graph_get_remote_port(cpu_ep);
1174 
1175         /*
1176          *      CPU {
1177          * =>           lnk: port { endpoint { .. }; };
1178          *      };
1179          */
1180         /*
1181          * DON'T REMOVE platforms
1182          * see
1183          *      simple-card.c :: simple_count_noml()
1184          */
1185         li->num[li->link].cpus          =
1186         li->num[li->link].platforms     = graph_counter(cpu_port);
1187 
1188         li->num[li->link].codecs        = graph_counter(codec_port);
1189 
1190         of_node_put(cpu_ep);
1191         of_node_put(codec_port);
1192 
1193         return 0;
1194 }
1195 
1196 static int graph_count_dpcm(struct simple_util_priv *priv,
1197                             struct device_node *lnk,
1198                             struct link_info *li)
1199 {
1200         struct device_node *ep = port_to_endpoint(lnk);
1201         struct device_node *rport = of_graph_get_remote_port(ep);
1202 
1203         /*
1204          * dpcm {
1205          *      // Front-End
1206          *      ports@0 {
1207          * =>           lnk: port@0 { endpoint { ... }; };
1208          *               ...
1209          *      };
1210          *      // Back-End
1211          *      ports@1 {
1212          * =>           lnk: port@0 { endpoint { ... }; };
1213          *               ...
1214          *      };
1215          * };
1216          */
1217 
1218         if (graph_util_is_ports0(lnk)) {
1219                 /*
1220                  * DON'T REMOVE platforms
1221                  * see
1222                  *      simple-card.c :: simple_count_noml()
1223                  */
1224                 li->num[li->link].cpus          = graph_counter(rport); /* FE */
1225                 li->num[li->link].platforms     = graph_counter(rport);
1226         } else {
1227                 li->num[li->link].codecs        = graph_counter(rport); /* BE */
1228         }
1229 
1230         of_node_put(ep);
1231         of_node_put(rport);
1232 
1233         return 0;
1234 }
1235 
1236 static int graph_count_c2c(struct simple_util_priv *priv,
1237                            struct device_node *lnk,
1238                            struct link_info *li)
1239 {
1240         struct device_node *ports = port_to_ports(lnk);
1241         struct device_node *port0 = lnk;
1242         struct device_node *port1 = of_get_next_child(ports, of_node_get(lnk));
1243         struct device_node *ep0 = port_to_endpoint(port0);
1244         struct device_node *ep1 = port_to_endpoint(port1);
1245         struct device_node *codec0 = of_graph_get_remote_port(ep0);
1246         struct device_node *codec1 = of_graph_get_remote_port(ep1);
1247 
1248         /*
1249          * codec2codec {
1250          *      ports {
1251          * =>   lnk:    port@0 { endpoint { ... }; };
1252          *              port@1 { endpoint { ... }; };
1253          *      };
1254          * };
1255          */
1256         /*
1257          * DON'T REMOVE platforms
1258          * see
1259          *      simple-card.c :: simple_count_noml()
1260          */
1261         li->num[li->link].cpus          =
1262         li->num[li->link].platforms     = graph_counter(codec0);
1263 
1264         li->num[li->link].codecs        = graph_counter(codec1);
1265 
1266         of_node_put(ports);
1267         of_node_put(port1);
1268         of_node_put(ep0);
1269         of_node_put(ep1);
1270         of_node_put(codec0);
1271         of_node_put(codec1);
1272 
1273         return 0;
1274 }
1275 
1276 static int graph_count(struct simple_util_priv *priv,
1277                        struct graph2_custom_hooks *hooks,
1278                        enum graph_type gtype,
1279                        struct device_node *lnk,
1280                        struct link_info *li)
1281 {
1282         struct device *dev = simple_priv_to_dev(priv);
1283         GRAPH2_CUSTOM func = NULL;
1284         int ret = -EINVAL;
1285 
1286         if (li->link >= SNDRV_MAX_LINKS) {
1287                 dev_err(dev, "too many links\n");
1288                 return ret;
1289         }
1290 
1291         switch (gtype) {
1292         case GRAPH_NORMAL:
1293                 func = graph_count_normal;
1294                 break;
1295         case GRAPH_DPCM:
1296                 func = graph_count_dpcm;
1297                 break;
1298         case GRAPH_C2C:
1299                 func = graph_count_c2c;
1300                 break;
1301         default:
1302                 break;
1303         }
1304 
1305         if (!func) {
1306                 dev_err(dev, "non supported gtype (%d)\n", gtype);
1307                 goto err;
1308         }
1309 
1310         ret = func(priv, lnk, li);
1311         if (ret < 0)
1312                 goto err;
1313 
1314         li->link++;
1315 err:
1316         return ret;
1317 }
1318 
1319 static int graph_for_each_link(struct simple_util_priv *priv,
1320                                struct graph2_custom_hooks *hooks,
1321                                struct link_info *li,
1322                                int (*func)(struct simple_util_priv *priv,
1323                                            struct graph2_custom_hooks *hooks,
1324                                            enum graph_type gtype,
1325                                            struct device_node *lnk,
1326                                            struct link_info *li))
1327 {
1328         struct of_phandle_iterator it;
1329         struct device *dev = simple_priv_to_dev(priv);
1330         struct device_node *node = dev->of_node;
1331         struct device_node *lnk;
1332         enum graph_type gtype;
1333         int rc, ret;
1334 
1335         /* loop for all listed CPU port */
1336         of_for_each_phandle(&it, rc, node, "links", NULL, 0) {
1337                 lnk = it.node;
1338 
1339                 gtype = graph_get_type(priv, lnk);
1340 
1341                 ret = func(priv, hooks, gtype, lnk, li);
1342                 if (ret < 0)
1343                         return ret;
1344         }
1345 
1346         return 0;
1347 }
1348 
1349 int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev,
1350                           struct graph2_custom_hooks *hooks)
1351 {
1352         struct snd_soc_card *card = simple_priv_to_card(priv);
1353         int ret;
1354 
1355         struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
1356         if (!li)
1357                 return -ENOMEM;
1358 
1359         card->probe     = graph_util_card_probe;
1360         card->owner     = THIS_MODULE;
1361         card->dev       = dev;
1362 
1363         if ((hooks) && (hooks)->hook_pre) {
1364                 ret = (hooks)->hook_pre(priv);
1365                 if (ret < 0)
1366                         goto err;
1367         }
1368 
1369         ret = graph_for_each_link(priv, hooks, li, graph_count);
1370         if (!li->link)
1371                 ret = -EINVAL;
1372         if (ret < 0)
1373                 goto err;
1374 
1375         ret = simple_util_init_priv(priv, li);
1376         if (ret < 0)
1377                 goto err;
1378 
1379         priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
1380         if (IS_ERR(priv->pa_gpio)) {
1381                 ret = PTR_ERR(priv->pa_gpio);
1382                 dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
1383                 goto err;
1384         }
1385 
1386         ret = simple_util_parse_widgets(card, NULL);
1387         if (ret < 0)
1388                 goto err;
1389 
1390         ret = simple_util_parse_routing(card, NULL);
1391         if (ret < 0)
1392                 goto err;
1393 
1394         memset(li, 0, sizeof(*li));
1395         ret = graph_for_each_link(priv, hooks, li, graph_link);
1396         if (ret < 0)
1397                 goto err;
1398 
1399         ret = simple_util_parse_card_name(card, NULL);
1400         if (ret < 0)
1401                 goto err;
1402 
1403         snd_soc_card_set_drvdata(card, priv);
1404 
1405         if ((hooks) && (hooks)->hook_post) {
1406                 ret = (hooks)->hook_post(priv);
1407                 if (ret < 0)
1408                         goto err;
1409         }
1410 
1411         simple_util_debug_info(priv);
1412 
1413         ret = snd_soc_of_parse_aux_devs(card, "aux-devs");
1414         if (ret < 0)
1415                 goto err;
1416 
1417         ret = devm_snd_soc_register_card(dev, card);
1418 err:
1419         if (ret < 0)
1420                 dev_err_probe(dev, ret, "parse error\n");
1421 
1422         return ret;
1423 }
1424 EXPORT_SYMBOL_GPL(audio_graph2_parse_of);
1425 
1426 static int graph_probe(struct platform_device *pdev)
1427 {
1428         struct simple_util_priv *priv;
1429         struct device *dev = &pdev->dev;
1430 
1431         /* Allocate the private data and the DAI link array */
1432         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
1433         if (!priv)
1434                 return -ENOMEM;
1435 
1436         return audio_graph2_parse_of(priv, dev, NULL);
1437 }
1438 
1439 static const struct of_device_id graph_of_match[] = {
1440         { .compatible = "audio-graph-card2", },
1441         {},
1442 };
1443 MODULE_DEVICE_TABLE(of, graph_of_match);
1444 
1445 static struct platform_driver graph_card = {
1446         .driver = {
1447                 .name = "asoc-audio-graph-card2",
1448                 .pm = &snd_soc_pm_ops,
1449                 .of_match_table = graph_of_match,
1450         },
1451         .probe  = graph_probe,
1452         .remove_new = simple_util_remove,
1453 };
1454 module_platform_driver(graph_card);
1455 
1456 MODULE_ALIAS("platform:asoc-audio-graph-card2");
1457 MODULE_LICENSE("GPL v2");
1458 MODULE_DESCRIPTION("ASoC Audio Graph Card2");
1459 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
1460 

~ [ 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