1 // SPDX-License-Identifier: GPL-2.0
3 // ASoC audio graph sound card support
5 // Copyright (C) 2016 Renesas Solutions Corp.
6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
8 // based on ${LINUX}/sound/soc/generic/simple-card.c
10 #include <linux/cleanup.h>
11 #include <linux/clk.h>
12 #include <linux/device.h>
13 #include <linux/gpio/consumer.h>
14 #include <linux/module.h>
16 #include <linux/of_graph.h>
17 #include <linux/platform_device.h>
18 #include <linux/string.h>
19 #include <sound/graph_card.h>
21 #define DPCM_SELECTABLE 1
23 #define ep_to_port(ep) of_get_parent(ep)
24 static struct device_node
*port_to_ports(struct device_node
*port
)
26 struct device_node
*ports
= of_get_parent(port
);
28 if (!of_node_name_eq(ports
, "ports")) {
35 static int graph_outdrv_event(struct snd_soc_dapm_widget
*w
,
36 struct snd_kcontrol
*kcontrol
,
39 struct snd_soc_dapm_context
*dapm
= w
->dapm
;
40 struct simple_util_priv
*priv
= snd_soc_card_get_drvdata(dapm
->card
);
43 case SND_SOC_DAPM_POST_PMU
:
44 gpiod_set_value_cansleep(priv
->pa_gpio
, 1);
46 case SND_SOC_DAPM_PRE_PMD
:
47 gpiod_set_value_cansleep(priv
->pa_gpio
, 0);
56 static const struct snd_soc_dapm_widget graph_dapm_widgets
[] = {
57 SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM
,
58 0, 0, NULL
, 0, graph_outdrv_event
,
59 SND_SOC_DAPM_POST_PMU
| SND_SOC_DAPM_PRE_PMD
),
62 static const struct snd_soc_ops graph_ops
= {
63 .startup
= simple_util_startup
,
64 .shutdown
= simple_util_shutdown
,
65 .hw_params
= simple_util_hw_params
,
68 static bool soc_component_is_pcm(struct snd_soc_dai_link_component
*dlc
)
70 struct snd_soc_dai
*dai
= snd_soc_find_dai_with_mutex(dlc
);
72 if (dai
&& (dai
->component
->driver
->pcm_construct
||
73 (dai
->driver
->ops
&& dai
->driver
->ops
->pcm_new
)))
79 static void graph_parse_convert(struct device
*dev
,
80 struct device_node
*ep
,
81 struct simple_util_data
*adata
)
83 struct device_node
*top
= dev
->of_node
;
84 struct device_node
*port
= ep_to_port(ep
);
85 struct device_node
*ports
= port_to_ports(port
);
86 struct device_node
*node
= of_graph_get_port_parent(ep
);
88 simple_util_parse_convert(top
, NULL
, adata
);
89 simple_util_parse_convert(ports
, NULL
, adata
);
90 simple_util_parse_convert(port
, NULL
, adata
);
91 simple_util_parse_convert(ep
, NULL
, adata
);
98 static int graph_parse_node(struct simple_util_priv
*priv
,
99 struct device_node
*ep
,
100 struct link_info
*li
,
103 struct device
*dev
= simple_priv_to_dev(priv
);
104 struct snd_soc_dai_link
*dai_link
= simple_priv_to_link(priv
, li
->link
);
105 struct simple_dai_props
*dai_props
= simple_priv_to_props(priv
, li
->link
);
106 struct snd_soc_dai_link_component
*dlc
;
107 struct simple_util_dai
*dai
;
111 dlc
= snd_soc_link_to_cpu(dai_link
, 0);
112 dai
= simple_props_to_dai_cpu(dai_props
, 0);
114 dlc
= snd_soc_link_to_codec(dai_link
, 0);
115 dai
= simple_props_to_dai_codec(dai_props
, 0);
118 ret
= graph_util_parse_dai(dev
, ep
, dlc
, cpu
);
122 ret
= simple_util_parse_tdm(ep
, dai
);
126 ret
= simple_util_parse_clk(dev
, ep
, dai
, dlc
);
133 static int graph_link_init(struct simple_util_priv
*priv
,
134 struct device_node
*ep_cpu
,
135 struct device_node
*ep_codec
,
136 struct link_info
*li
,
139 struct device
*dev
= simple_priv_to_dev(priv
);
140 struct device_node
*top
= dev
->of_node
;
141 struct snd_soc_dai_link
*dai_link
= simple_priv_to_link(priv
, li
->link
);
142 struct simple_dai_props
*dai_props
= simple_priv_to_props(priv
, li
->link
);
143 struct device_node
*port_cpu
= ep_to_port(ep_cpu
);
144 struct device_node
*port_codec
= ep_to_port(ep_codec
);
145 struct device_node
*ports_cpu
= port_to_ports(port_cpu
);
146 struct device_node
*ports_codec
= port_to_ports(port_codec
);
147 enum snd_soc_trigger_order trigger_start
= SND_SOC_TRIGGER_ORDER_DEFAULT
;
148 enum snd_soc_trigger_order trigger_stop
= SND_SOC_TRIGGER_ORDER_DEFAULT
;
149 bool playback_only
= 0, capture_only
= 0;
152 ret
= simple_util_parse_daifmt(dev
, ep_cpu
, ep_codec
,
153 NULL
, &dai_link
->dai_fmt
);
157 graph_util_parse_link_direction(top
, &playback_only
, &capture_only
);
158 graph_util_parse_link_direction(port_cpu
, &playback_only
, &capture_only
);
159 graph_util_parse_link_direction(port_codec
, &playback_only
, &capture_only
);
160 graph_util_parse_link_direction(ep_cpu
, &playback_only
, &capture_only
);
161 graph_util_parse_link_direction(ep_codec
, &playback_only
, &capture_only
);
163 of_property_read_u32(top
, "mclk-fs", &dai_props
->mclk_fs
);
164 of_property_read_u32(ports_cpu
, "mclk-fs", &dai_props
->mclk_fs
);
165 of_property_read_u32(ports_codec
, "mclk-fs", &dai_props
->mclk_fs
);
166 of_property_read_u32(port_cpu
, "mclk-fs", &dai_props
->mclk_fs
);
167 of_property_read_u32(port_codec
, "mclk-fs", &dai_props
->mclk_fs
);
168 of_property_read_u32(ep_cpu
, "mclk-fs", &dai_props
->mclk_fs
);
169 of_property_read_u32(ep_codec
, "mclk-fs", &dai_props
->mclk_fs
);
171 graph_util_parse_trigger_order(priv
, top
, &trigger_start
, &trigger_stop
);
172 graph_util_parse_trigger_order(priv
, ports_cpu
, &trigger_start
, &trigger_stop
);
173 graph_util_parse_trigger_order(priv
, ports_codec
, &trigger_start
, &trigger_stop
);
174 graph_util_parse_trigger_order(priv
, port_cpu
, &trigger_start
, &trigger_stop
);
175 graph_util_parse_trigger_order(priv
, port_cpu
, &trigger_start
, &trigger_stop
);
176 graph_util_parse_trigger_order(priv
, ep_cpu
, &trigger_start
, &trigger_stop
);
177 graph_util_parse_trigger_order(priv
, ep_codec
, &trigger_start
, &trigger_stop
);
179 dai_link
->playback_only
= playback_only
;
180 dai_link
->capture_only
= capture_only
;
182 dai_link
->trigger_start
= trigger_start
;
183 dai_link
->trigger_stop
= trigger_stop
;
185 dai_link
->init
= simple_util_dai_init
;
186 dai_link
->ops
= &graph_ops
;
188 dai_link
->ops
= priv
->ops
;
190 ret
= simple_util_set_dailink_name(dev
, dai_link
, name
);
192 of_node_put(ports_cpu
);
193 of_node_put(ports_codec
);
194 of_node_put(port_cpu
);
195 of_node_put(port_codec
);
200 static int graph_dai_link_of_dpcm(struct simple_util_priv
*priv
,
201 struct device_node
*cpu_ep
,
202 struct device_node
*codec_ep
,
203 struct link_info
*li
)
205 struct device
*dev
= simple_priv_to_dev(priv
);
206 struct snd_soc_dai_link
*dai_link
= simple_priv_to_link(priv
, li
->link
);
207 struct simple_dai_props
*dai_props
= simple_priv_to_props(priv
, li
->link
);
208 struct device_node
*top
= dev
->of_node
;
209 struct device_node
*ep
= li
->cpu
? cpu_ep
: codec_ep
;
213 dev_dbg(dev
, "link_of DPCM (%pOF)\n", ep
);
216 struct snd_soc_card
*card
= simple_priv_to_card(priv
);
217 struct snd_soc_dai_link_component
*cpus
= snd_soc_link_to_cpu(dai_link
, 0);
218 struct snd_soc_dai_link_component
*platforms
= snd_soc_link_to_platform(dai_link
, 0);
219 int is_single_links
= 0;
224 dai_link
->dynamic
= 1;
225 dai_link
->dpcm_merged_format
= 1;
227 ret
= graph_parse_node(priv
, cpu_ep
, li
, &is_single_links
);
231 snprintf(dai_name
, sizeof(dai_name
),
232 "fe.%pOFP.%s", cpus
->of_node
, cpus
->dai_name
);
234 * In BE<->BE connections it is not required to create
235 * PCM devices at CPU end of the dai link and thus 'no_pcm'
236 * flag needs to be set. It is useful when there are many
237 * BE components and some of these have to be connected to
238 * form a valid audio path.
240 * For example: FE <-> BE1 <-> BE2 <-> ... <-> BEn where
241 * there are 'n' BE components in the path.
243 if (card
->component_chaining
&& !soc_component_is_pcm(cpus
)) {
244 dai_link
->no_pcm
= 1;
245 dai_link
->be_hw_params_fixup
= simple_util_be_hw_params_fixup
;
248 simple_util_canonicalize_cpu(cpus
, is_single_links
);
249 simple_util_canonicalize_platform(platforms
, cpus
);
251 struct snd_soc_codec_conf
*cconf
= simple_props_to_codec_conf(dai_props
, 0);
252 struct snd_soc_dai_link_component
*codecs
= snd_soc_link_to_codec(dai_link
, 0);
253 struct device_node
*port
;
254 struct device_node
*ports
;
259 dai_link
->no_pcm
= 1;
260 dai_link
->be_hw_params_fixup
= simple_util_be_hw_params_fixup
;
262 ret
= graph_parse_node(priv
, codec_ep
, li
, NULL
);
266 snprintf(dai_name
, sizeof(dai_name
),
267 "be.%pOFP.%s", codecs
->of_node
, codecs
->dai_name
);
269 /* check "prefix" from top node */
270 port
= ep_to_port(ep
);
271 ports
= port_to_ports(port
);
272 snd_soc_of_parse_node_prefix(top
, cconf
, codecs
->of_node
, "prefix");
273 snd_soc_of_parse_node_prefix(ports
, cconf
, codecs
->of_node
, "prefix");
274 snd_soc_of_parse_node_prefix(port
, cconf
, codecs
->of_node
, "prefix");
280 graph_parse_convert(dev
, ep
, &dai_props
->adata
);
282 ret
= graph_link_init(priv
, cpu_ep
, codec_ep
, li
, dai_name
);
289 static int graph_dai_link_of(struct simple_util_priv
*priv
,
290 struct device_node
*cpu_ep
,
291 struct device_node
*codec_ep
,
292 struct link_info
*li
)
294 struct device
*dev
= simple_priv_to_dev(priv
);
295 struct snd_soc_dai_link
*dai_link
= simple_priv_to_link(priv
, li
->link
);
296 struct snd_soc_dai_link_component
*cpus
= snd_soc_link_to_cpu(dai_link
, 0);
297 struct snd_soc_dai_link_component
*codecs
= snd_soc_link_to_codec(dai_link
, 0);
298 struct snd_soc_dai_link_component
*platforms
= snd_soc_link_to_platform(dai_link
, 0);
300 int ret
, is_single_links
= 0;
302 dev_dbg(dev
, "link_of (%pOF)\n", cpu_ep
);
304 ret
= graph_parse_node(priv
, cpu_ep
, li
, &is_single_links
);
308 ret
= graph_parse_node(priv
, codec_ep
, li
, NULL
);
312 snprintf(dai_name
, sizeof(dai_name
),
313 "%s-%s", cpus
->dai_name
, codecs
->dai_name
);
315 simple_util_canonicalize_cpu(cpus
, is_single_links
);
316 simple_util_canonicalize_platform(platforms
, cpus
);
318 ret
= graph_link_init(priv
, cpu_ep
, codec_ep
, li
, dai_name
);
327 static inline bool parse_as_dpcm_link(struct simple_util_priv
*priv
,
328 struct device_node
*codec_port
,
329 struct simple_util_data
*adata
)
331 if (priv
->force_dpcm
)
334 if (!priv
->dpcm_selectable
)
339 * if Codec port has many endpoints,
340 * or has convert-xxx property
342 if ((of_get_child_count(codec_port
) > 1) ||
343 simple_util_is_convert_required(adata
))
349 static int __graph_for_each_link(struct simple_util_priv
*priv
,
350 struct link_info
*li
,
351 int (*func_noml
)(struct simple_util_priv
*priv
,
352 struct device_node
*cpu_ep
,
353 struct device_node
*codec_ep
,
354 struct link_info
*li
),
355 int (*func_dpcm
)(struct simple_util_priv
*priv
,
356 struct device_node
*cpu_ep
,
357 struct device_node
*codec_ep
,
358 struct link_info
*li
))
360 struct of_phandle_iterator it
;
361 struct device
*dev
= simple_priv_to_dev(priv
);
362 struct device_node
*node
= dev
->of_node
;
363 struct device_node
*cpu_port
;
364 struct device_node
*codec_ep
;
365 struct device_node
*codec_port
;
366 struct device_node
*codec_port_old
= NULL
;
367 struct simple_util_data adata
;
370 /* loop for all listed CPU port */
371 of_for_each_phandle(&it
, rc
, node
, "dais", NULL
, 0) {
374 /* loop for all CPU endpoint */
375 for_each_of_graph_port_endpoint(cpu_port
, cpu_ep
) {
377 codec_ep
= of_graph_get_remote_endpoint(cpu_ep
);
378 codec_port
= ep_to_port(codec_ep
);
380 /* get convert-xxx property */
381 memset(&adata
, 0, sizeof(adata
));
382 graph_parse_convert(dev
, codec_ep
, &adata
);
383 graph_parse_convert(dev
, cpu_ep
, &adata
);
385 /* check if link requires DPCM parsing */
386 if (parse_as_dpcm_link(priv
, codec_port
, &adata
)) {
388 * Codec endpoint can be NULL for pluggable audio HW.
389 * Platform DT can populate the Codec endpoint depending on the
392 /* Do it all CPU endpoint, and 1st Codec endpoint */
394 ((codec_port_old
!= codec_port
) && codec_ep
))
395 ret
= func_dpcm(priv
, cpu_ep
, codec_ep
, li
);
396 /* else normal sound */
399 ret
= func_noml(priv
, cpu_ep
, codec_ep
, li
);
402 of_node_put(codec_ep
);
403 of_node_put(codec_port
);
408 codec_port_old
= codec_port
;
415 static int graph_for_each_link(struct simple_util_priv
*priv
,
416 struct link_info
*li
,
417 int (*func_noml
)(struct simple_util_priv
*priv
,
418 struct device_node
*cpu_ep
,
419 struct device_node
*codec_ep
,
420 struct link_info
*li
),
421 int (*func_dpcm
)(struct simple_util_priv
*priv
,
422 struct device_node
*cpu_ep
,
423 struct device_node
*codec_ep
,
424 struct link_info
*li
))
428 * Detect all CPU first, and Detect all Codec 2nd.
430 * In Normal sound case, all DAIs are detected
433 * In DPCM sound case,
434 * all CPUs are detected as "CPU-dummy", and
435 * all Codecs are detected as "dummy-Codec".
436 * To avoid random sub-device numbering,
437 * detect "dummy-Codec" in last;
439 for (li
->cpu
= 1; li
->cpu
>= 0; li
->cpu
--) {
440 ret
= __graph_for_each_link(priv
, li
, func_noml
, func_dpcm
);
448 static int graph_count_noml(struct simple_util_priv
*priv
,
449 struct device_node
*cpu_ep
,
450 struct device_node
*codec_ep
,
451 struct link_info
*li
)
453 struct device
*dev
= simple_priv_to_dev(priv
);
455 if (li
->link
>= SNDRV_MAX_LINKS
) {
456 dev_err(dev
, "too many links\n");
461 * DON'T REMOVE platforms
463 * simple-card.c :: simple_count_noml()
465 li
->num
[li
->link
].cpus
= 1;
466 li
->num
[li
->link
].platforms
= 1;
468 li
->num
[li
->link
].codecs
= 1;
470 li
->link
+= 1; /* 1xCPU-Codec */
472 dev_dbg(dev
, "Count As Normal\n");
477 static int graph_count_dpcm(struct simple_util_priv
*priv
,
478 struct device_node
*cpu_ep
,
479 struct device_node
*codec_ep
,
480 struct link_info
*li
)
482 struct device
*dev
= simple_priv_to_dev(priv
);
484 if (li
->link
>= SNDRV_MAX_LINKS
) {
485 dev_err(dev
, "too many links\n");
491 * DON'T REMOVE platforms
493 * simple-card.c :: simple_count_noml()
495 li
->num
[li
->link
].cpus
= 1;
496 li
->num
[li
->link
].platforms
= 1;
498 li
->link
++; /* 1xCPU-dummy */
500 li
->num
[li
->link
].codecs
= 1;
502 li
->link
++; /* 1xdummy-Codec */
505 dev_dbg(dev
, "Count As DPCM\n");
510 static int graph_get_dais_count(struct simple_util_priv
*priv
,
511 struct link_info
*li
)
514 * link_num : number of links.
515 * CPU-Codec / CPU-dummy / dummy-Codec
516 * dais_num : number of DAIs
517 * ccnf_num : number of codec_conf
518 * same number for "dummy-Codec"
521 * CPU0 --- Codec0 link : 5
522 * CPU1 --- Codec1 dais : 7
526 * => 5 links = 2xCPU-Codec + 2xCPU-dummy + 1xdummy-Codec
527 * => 7 DAIs = 4xCPU + 3xCodec
528 * => 1 ccnf = 1xdummy-Codec
531 * CPU0 --- Codec0 link : 5
532 * CPU1 --- Codec1 dais : 6
536 * => 5 links = 1xCPU-Codec + 3xCPU-dummy + 1xdummy-Codec
537 * => 6 DAIs = 4xCPU + 2xCodec
538 * => 1 ccnf = 1xdummy-Codec
541 * CPU0 --- Codec0 link : 6
543 * CPU2 --- Codec1 ccnf : 2
546 * => 6 links = 0xCPU-Codec + 4xCPU-dummy + 2xdummy-Codec
547 * => 6 DAIs = 4xCPU + 2xCodec
548 * => 2 ccnf = 2xdummy-Codec
551 * CPU0 --- Codec0 (convert-rate) link : 3
552 * CPU1 --- Codec1 dais : 4
555 * => 3 links = 1xCPU-Codec + 1xCPU-dummy + 1xdummy-Codec
556 * => 4 DAIs = 2xCPU + 2xCodec
557 * => 1 ccnf = 1xdummy-Codec
559 return graph_for_each_link(priv
, li
,
564 int audio_graph_parse_of(struct simple_util_priv
*priv
, struct device
*dev
)
566 struct snd_soc_card
*card
= simple_priv_to_card(priv
);
569 struct link_info
*li
__free(kfree
) = kzalloc(sizeof(*li
), GFP_KERNEL
);
573 card
->owner
= THIS_MODULE
;
576 ret
= graph_get_dais_count(priv
, li
);
583 ret
= simple_util_init_priv(priv
, li
);
587 priv
->pa_gpio
= devm_gpiod_get_optional(dev
, "pa", GPIOD_OUT_LOW
);
588 if (IS_ERR(priv
->pa_gpio
)) {
589 ret
= PTR_ERR(priv
->pa_gpio
);
590 dev_err(dev
, "failed to get amplifier gpio: %d\n", ret
);
594 ret
= simple_util_parse_widgets(card
, NULL
);
598 ret
= simple_util_parse_routing(card
, NULL
);
602 memset(li
, 0, sizeof(*li
));
603 ret
= graph_for_each_link(priv
, li
,
605 graph_dai_link_of_dpcm
);
609 ret
= simple_util_parse_card_name(card
, NULL
);
613 snd_soc_card_set_drvdata(card
, priv
);
615 simple_util_debug_info(priv
);
617 ret
= devm_snd_soc_register_card(dev
, card
);
624 simple_util_clean_reference(card
);
626 return dev_err_probe(dev
, ret
, "parse error\n");
628 EXPORT_SYMBOL_GPL(audio_graph_parse_of
);
630 static int graph_probe(struct platform_device
*pdev
)
632 struct simple_util_priv
*priv
;
633 struct device
*dev
= &pdev
->dev
;
634 struct snd_soc_card
*card
;
636 /* Allocate the private data and the DAI link array */
637 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
641 card
= simple_priv_to_card(priv
);
642 card
->dapm_widgets
= graph_dapm_widgets
;
643 card
->num_dapm_widgets
= ARRAY_SIZE(graph_dapm_widgets
);
644 card
->probe
= graph_util_card_probe
;
646 if (of_device_get_match_data(dev
))
647 priv
->dpcm_selectable
= 1;
649 return audio_graph_parse_of(priv
, dev
);
652 static const struct of_device_id graph_of_match
[] = {
653 { .compatible
= "audio-graph-card", },
654 { .compatible
= "audio-graph-scu-card",
655 .data
= (void *)DPCM_SELECTABLE
},
658 MODULE_DEVICE_TABLE(of
, graph_of_match
);
660 static struct platform_driver graph_card
= {
662 .name
= "asoc-audio-graph-card",
663 .pm
= &snd_soc_pm_ops
,
664 .of_match_table
= graph_of_match
,
666 .probe
= graph_probe
,
667 .remove
= simple_util_remove
,
669 module_platform_driver(graph_card
);
671 MODULE_ALIAS("platform:asoc-audio-graph-card");
672 MODULE_LICENSE("GPL v2");
673 MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
674 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");