Lines Matching +full:multi +full:- +full:port

1 // SPDX-License-Identifier: GPL-2.0
8 // based on ${LINUX}/sound/soc/generic/audio-graph-card.c
24 port@0 {
25 bitclock-master;
27 frame-master;
36 You can set daifmt at ports/port/endpoint.
39 sample0: left_j, bitclock-master, frame-master
40 sample1: i2s, bitclock-master
56 linux/sound/soc/soc-utils.c
57 linux/sound/soc/generic/test-component.c
60 Normal Audio-Graph
63 CPU <---> Codec
66 compatible = "audio-graph-card2";
71 cpu: port {
72 bitclock-master;
73 frame-master;
74 cpu_ep: endpoint { remote-endpoint = <&codec_ep>; }; };
78 port { codec_ep: endpoint { remote-endpoint = <&cpu_ep>; }; };
82 Multi-CPU/Codec
88 +----+ +---+
89 CPU1 --|A X| <-@----> |x a|-- Codec1
90 CPU2 --|B | | b|-- Codec2
91 +----+ +---+
94 compatible = "audio-graph-card2";
98 multi {
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
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
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>; }; };
123 port@0 { codec1_ep: endpoint { remote-endpoint = <&mcodec1_ep>; }; };
124 port@1 { codec2_ep: endpoint { remote-endpoint = <&mcodec2_ep>; }; };
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
143 compatible = "audio-graph-card2";
150 // indicate all Front-End, Back-End
155 // Front-End
157 fe0: port@0 { fe0_ep: endpoint { remote-endpoint = <&pcm0_ep>; }; };
158 fe1: port@1 { fe1_ep: endpoint { remote-endpoint = <&pcm1_ep>; }; };
161 // Back-End
163 be0: port@0 { be0_ep: endpoint { remote-endpoint = <&dai0_ep>; }; };
164 be1: port@1 { be1_ep: endpoint { remote-endpoint = <&dai1_ep>; }; };
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>; }; };
182 port@0 { dai0_ep: endpoint { remote-endpoint = <&be0_ep>; }; };
183 port@1 { dai1_ep: endpoint { remote-endpoint = <&be1_ep>; }; };
192 +--+
193 | |<-- Codec0 <- IN
194 | |--> Codec1 -> OUT
195 +--+
198 compatible = "audio-graph-card2";
208 c2c: port@0 { c2cf_ep: endpoint { remote-endpoint = <&codec0_ep>; }; };
209 port@1 { c2cb_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
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>; }; };
233 #define GRAPH_NODENAME_MULTI "multi"
245 static struct device_node *port_to_ports(struct device_node *port) in port_to_ports() argument
247 struct device_node *ports = of_get_parent(port); in port_to_ports()
264 * => lnk: port@0 { ... }; in __graph_get_type()
265 * port@1 { ... }; in __graph_get_type()
278 fw_devlink_purge_absent_suppliers(&np->fwnode); in __graph_get_type()
284 fw_devlink_purge_absent_suppliers(&np->fwnode); in __graph_get_type()
290 fw_devlink_purge_absent_suppliers(&np->fwnode); in __graph_get_type()
319 str = "DPCM Front-End"; in graph_get_type()
321 str = "DPCM Back-End"; in graph_get_type()
341 static struct device_node *graph_get_next_multi_ep(struct device_node **port, int idx) in graph_get_next_multi_ep() argument
343 struct device_node *ports __free(device_node) = port_to_ports(*port); in graph_get_next_multi_ep()
347 * multi { in graph_get_next_multi_ep()
349 * => lnk: port@0 { ... }; // to pair in graph_get_next_multi_ep()
350 * port@1 { ep { ... = rep0 } }; // Multi Element in graph_get_next_multi_ep()
351 * port@2 { ep { ... = rep1 } }; // Multi Element in graph_get_next_multi_ep()
357 * port@0 { rep0 }; in graph_get_next_multi_ep()
358 * port@1 { rep1 }; in graph_get_next_multi_ep()
365 * In overlay case, "port" are not necessarily in order. So we need to use in graph_get_next_multi_ep()
368 of_node_put(*port); in graph_get_next_multi_ep()
370 *port = of_graph_get_port_by_id(ports, idx); in graph_get_next_multi_ep()
371 if (*port) { in graph_get_next_multi_ep()
372 struct device_node *ep __free(device_node) = of_graph_get_next_port_endpoint(*port, NULL); in graph_get_next_multi_ep()
389 struct device_node *port __free(device_node) = ep_to_port(ep); in graph_parse_convert()
390 struct device_node *ports __free(device_node) = port_to_ports(port); in graph_parse_convert()
391 struct simple_util_data *adata = &props->adata; in graph_parse_convert()
394 simple_util_parse_convert(port, NULL, adata); in graph_parse_convert()
405 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); in __graph_parse_node()
406 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); in __graph_parse_node()
438 if (!dai_link->name) { in __graph_parse_node()
444 if (dai_link->num_cpus > 1) in __graph_parse_node()
446 if (dai_link->num_codecs > 1) in __graph_parse_node()
453 simple_util_set_dailink_name(priv, dai_link, "%s%s-%s%s", in __graph_parse_node()
454 cpus->dai_name, cpu_multi, in __graph_parse_node()
455 codecs->dai_name, codec_multi); in __graph_parse_node()
460 cpus->of_node, cpus->dai_name, cpu_multi); in __graph_parse_node()
463 codecs->of_node, codecs->dai_name, codec_multi); in __graph_parse_node()
468 simple_util_set_dailink_name(priv, dai_link, "c2c.%s%s-%s%s", in __graph_parse_node()
469 cpus->dai_name, cpu_multi, in __graph_parse_node()
470 codecs->dai_name, codec_multi); in __graph_parse_node()
479 * if DPCM-BE case in __graph_parse_node()
487 snd_soc_of_parse_node_prefix(rports, cconf, codecs->of_node, "prefix"); in __graph_parse_node()
488 snd_soc_of_parse_node_prefix(rport, cconf, codecs->of_node, "prefix"); in __graph_parse_node()
508 * +---+ +---+ in graph_parse_node_multi_nm()
509 * | X|<-@------->|x | in graph_parse_node_multi_nm()
511 * cpu0 <--|A 1|<--------->|4 a|-> codec0 in graph_parse_node_multi_nm()
512 * cpu1 <--|B 2|<-----+--->|5 b|-> codec1 in graph_parse_node_multi_nm()
513 * cpu2 <--|C 3|<----/ +---+ in graph_parse_node_multi_nm()
514 * +---+ in graph_parse_node_multi_nm()
516 * multi { in graph_parse_node_multi_nm()
518 * port@0 { mcpu_top_ep {... = mcodec_ep; }; }; // (X) to pair in graph_parse_node_multi_nm()
519 * <mcpu_port> port@1 { mcpu0_ep { ... = cpu0_ep; }; // (A) Multi Element in graph_parse_node_multi_nm()
521 * port@2 { mcpu1_ep { ... = cpu1_ep; }; // (B) Multi Element in graph_parse_node_multi_nm()
523 * port@3 { mcpu2_ep { ... = cpu2_ep; }; // (C) Multi Element in graph_parse_node_multi_nm()
528 * port@0 { mcodec_top_ep {... = mcpu_ep; }; }; // (x) to pair in graph_parse_node_multi_nm()
529 * <mcodec_port>port@1 { mcodec0_ep { ... = codec0_ep; }; // (a) Multi Element in graph_parse_node_multi_nm()
531 * port@2 { mcodec1_ep { ... = codec1_ep; }; // (b) Multi Element in graph_parse_node_multi_nm()
544 int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); in graph_parse_node_multi_nm()
545 int ret = -EINVAL; in graph_parse_node_multi_nm()
547 if (cpu_idx > dai_link->num_cpus) in graph_parse_node_multi_nm()
563 ret = -EINVAL; in graph_parse_node_multi_nm()
569 /* ignore 1st port which is for pair connection */ in graph_parse_node_multi_nm()
573 if (codec_idx > dai_link->num_codecs) in graph_parse_node_multi_nm()
577 dai_link->ch_maps[*nm_idx].cpu = cpu_idx; in graph_parse_node_multi_nm()
578 dai_link->ch_maps[*nm_idx].codec = codec_idx; in graph_parse_node_multi_nm()
595 struct device_node *port, in graph_parse_node_multi() argument
598 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); in graph_parse_node_multi()
600 int ret = -ENOMEM; in graph_parse_node_multi()
602 int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); in graph_parse_node_multi()
608 if (gtype != GRAPH_DPCM && !dai_link->ch_maps && in graph_parse_node_multi()
609 dai_link->num_cpus > 1 && dai_link->num_codecs > 1 && in graph_parse_node_multi()
610 dai_link->num_cpus != dai_link->num_codecs) { in graph_parse_node_multi()
612 dai_link->ch_maps = devm_kcalloc(dev, nm_max, in graph_parse_node_multi()
614 if (!dai_link->ch_maps) in graph_parse_node_multi()
620 * multi { in graph_parse_node_multi()
622 * <port> port@0 { ... }; // to pair in graph_parse_node_multi()
623 * port@1 { mcpu1_ep { ... = cpu1_ep };}; // Multi Element in graph_parse_node_multi()
624 * port@2 { mcpu2_ep { ... = cpu2_ep };}; // Multi Element in graph_parse_node_multi()
630 * <ep> port@0 { cpu1_ep { ... = mcpu1_ep };}; in graph_parse_node_multi()
634 struct device_node *ep __free(device_node) = graph_get_next_multi_ep(&port, idx + 1); in graph_parse_node_multi()
643 if (is_cpu && dai_link->ch_maps) { in graph_parse_node_multi()
644 ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port); in graph_parse_node_multi()
650 if (is_cpu && dai_link->ch_maps && (nm_idx != nm_max)) in graph_parse_node_multi()
651 ret = -EINVAL; in graph_parse_node_multi()
670 struct device_node *port __free(device_node) = ep_to_port(ep); in graph_parse_node()
673 if (graph_lnk_is_multi(port)) in graph_parse_node()
674 ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu); in graph_parse_node()
696 * port { in graph_parse_daifmt()
714 * This function is called by (C) -> (B) -> (A) order. in graph_parse_daifmt()
725 struct device_node *port __free(device_node) = ep_to_port(ep); in graph_parse_bitframe()
726 struct device_node *ports __free(device_node) = port_to_ports(port); in graph_parse_bitframe()
730 snd_soc_daifmt_parse_clock_provider_as_bitmap(port, NULL) | in graph_parse_bitframe()
741 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); in graph_link_init()
742 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); in graph_link_init()
790 of_property_read_u32(lnk, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
791 of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
792 of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
793 of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
794 of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
795 of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
796 of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs); in graph_link_init()
807 dlc->ext_fmt = graph_parse_bitframe(ep_cpu); in graph_link_init()
814 dlc->ext_fmt = graph_parse_bitframe(ep_codec); in graph_link_init()
822 dai_link->playback_only = playback_only; in graph_link_init()
823 dai_link->capture_only = capture_only; in graph_link_init()
825 dai_link->trigger_start = trigger_start; in graph_link_init()
826 dai_link->trigger_stop = trigger_stop; in graph_link_init()
828 dai_link->dai_fmt = daifmt; in graph_link_init()
829 dai_link->init = simple_util_dai_init; in graph_link_init()
830 dai_link->ops = &graph_ops; in graph_link_init()
831 if (priv->ops) in graph_link_init()
832 dai_link->ops = priv->ops; in graph_link_init()
880 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); in audio_graph2_link_dpcm()
881 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link); in audio_graph2_link_dpcm()
890 * // Front-End in audio_graph2_link_dpcm()
892 * => lnk: port@0 { ep: { ... = rep }; }; in audio_graph2_link_dpcm()
895 * // Back-End in audio_graph2_link_dpcm()
903 * rport: port@0 { rep: { ... = ep } }; in audio_graph2_link_dpcm()
912 dai_link->dynamic = 1; in audio_graph2_link_dpcm()
913 dai_link->dpcm_merged_format = 1; in audio_graph2_link_dpcm()
924 * // Front-End in audio_graph2_link_dpcm()
928 * // Back-End in audio_graph2_link_dpcm()
930 * => lnk: port@0 { ep: { ... = rep; }; }; in audio_graph2_link_dpcm()
937 * rport: port@0 { rep: { ... = ep; }; }; in audio_graph2_link_dpcm()
948 dai_link->no_pcm = 1; in audio_graph2_link_dpcm()
949 dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup; in audio_graph2_link_dpcm()
969 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link); in audio_graph2_link_c2c()
974 int ret = -EINVAL; in audio_graph2_link_c2c()
980 * => lnk: port@0 { c2c0_ep: { ... = codec0_ep; }; }; in audio_graph2_link_c2c()
981 * port@1 { c2c1_ep: { ... = codec1_ep; }; }; in audio_graph2_link_c2c()
987 * port@0 { codec0_ep: ... }; }; in audio_graph2_link_c2c()
988 * port@1 { codec1_ep: ... }; }; in audio_graph2_link_c2c()
1012 return graph_ret(priv, -ENOMEM); in audio_graph2_link_c2c()
1015 c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ in audio_graph2_link_c2c()
1016 c2c_conf->rates = SNDRV_PCM_RATE_8000_384000; in audio_graph2_link_c2c()
1017 c2c_conf->rate_min = in audio_graph2_link_c2c()
1018 c2c_conf->rate_max = val; in audio_graph2_link_c2c()
1019 c2c_conf->channels_min = in audio_graph2_link_c2c()
1020 c2c_conf->channels_max = 2; /* update ME */ in audio_graph2_link_c2c()
1022 dai_link->c2c_params = c2c_conf; in audio_graph2_link_c2c()
1023 dai_link->num_c2c_params = 1; in audio_graph2_link_c2c()
1062 int ret = -EINVAL; in graph_link()
1066 if (hooks && hooks->custom_normal) in graph_link()
1067 func = hooks->custom_normal; in graph_link()
1072 if (hooks && hooks->custom_dpcm) in graph_link()
1073 func = hooks->custom_dpcm; in graph_link()
1078 if (hooks && hooks->custom_c2c) in graph_link()
1079 func = hooks->custom_c2c; in graph_link()
1096 li->link++; in graph_link()
1104 * Multi CPU / Codec in graph_counter()
1106 * multi { in graph_counter()
1108 * => lnk: port@0 { ... }; // to pair in graph_counter()
1109 * port@1 { ... }; // Multi Element in graph_counter()
1110 * port@2 { ... }; // Multi Element in graph_counter()
1124 return of_graph_get_port_count(ports) - 1; in graph_counter()
1143 * => lnk: port { endpoint { .. }; }; in graph_count_normal()
1149 * simple-card.c :: simple_count_noml() in graph_count_normal()
1151 li->num[li->link].cpus = in graph_count_normal()
1152 li->num[li->link].platforms = graph_counter(cpu_port); in graph_count_normal()
1154 li->num[li->link].codecs = graph_counter(codec_port); in graph_count_normal()
1168 * // Front-End in graph_count_dpcm()
1170 * => lnk: port@0 { endpoint { ... }; }; in graph_count_dpcm()
1173 * // Back-End in graph_count_dpcm()
1175 * => lnk: port@0 { endpoint { ... }; }; in graph_count_dpcm()
1185 * simple-card.c :: simple_count_noml() in graph_count_dpcm()
1187 li->num[li->link].cpus = graph_counter(rport); /* FE */ in graph_count_dpcm()
1188 li->num[li->link].platforms = graph_counter(rport); in graph_count_dpcm()
1190 li->num[li->link].codecs = graph_counter(rport); /* BE */ in graph_count_dpcm()
1211 * => lnk: port@0 { endpoint { ... }; }; in graph_count_c2c()
1212 * port@1 { endpoint { ... }; }; in graph_count_c2c()
1219 * simple-card.c :: simple_count_noml() in graph_count_c2c()
1221 li->num[li->link].cpus = in graph_count_c2c()
1222 li->num[li->link].platforms = graph_counter(codec0); in graph_count_c2c()
1224 li->num[li->link].codecs = graph_counter(codec1); in graph_count_c2c()
1237 int ret = -EINVAL; in graph_count()
1239 if (li->link >= SNDRV_MAX_LINKS) { in graph_count()
1267 li->link++; in graph_count()
1283 struct device_node *node = dev->of_node; in graph_for_each_link()
1288 /* loop for all listed CPU port */ in graph_for_each_link()
1310 return -ENOMEM; in audio_graph2_parse_of()
1312 card->probe = graph_util_card_probe; in audio_graph2_parse_of()
1313 card->owner = THIS_MODULE; in audio_graph2_parse_of()
1314 card->dev = dev; in audio_graph2_parse_of()
1316 if ((hooks) && (hooks)->hook_pre) { in audio_graph2_parse_of()
1317 ret = (hooks)->hook_pre(priv); in audio_graph2_parse_of()
1323 if (!li->link) in audio_graph2_parse_of()
1324 ret = -EINVAL; in audio_graph2_parse_of()
1332 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); in audio_graph2_parse_of()
1333 if (IS_ERR(priv->pa_gpio)) { in audio_graph2_parse_of()
1334 ret = PTR_ERR(priv->pa_gpio); in audio_graph2_parse_of()
1358 if ((hooks) && (hooks)->hook_post) { in audio_graph2_parse_of()
1359 ret = (hooks)->hook_post(priv); in audio_graph2_parse_of()
1366 ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); in audio_graph2_parse_of()
1382 struct device *dev = &pdev->dev; in graph_probe()
1387 return -ENOMEM; in graph_probe()
1393 { .compatible = "audio-graph-card2", },
1400 .name = "asoc-audio-graph-card2",
1409 MODULE_ALIAS("platform:asoc-audio-graph-card2");