1
2
3
4
5
6
7
8
9
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>
15#include <linux/of.h>
16#include <linux/of_graph.h>
17#include <linux/platform_device.h>
18#include <linux/string.h>
19#include <sound/graph_card.h>
20
21#define DPCM_SELECTABLE 1
22
23#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret)
24static inline int _graph_ret(struct simple_util_priv *priv,
25 const char *func, int ret)
26{
27 return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func);
28}
29
30#define ep_to_port(ep) of_get_parent(ep)
31static struct device_node *port_to_ports(struct device_node *port)
32{
33 struct device_node *ports = of_get_parent(port);
34
35 if (!of_node_name_eq(ports, "ports")) {
36 of_node_put(ports);
37 return NULL;
38 }
39 return ports;
40}
41
42static int graph_outdrv_event(struct snd_soc_dapm_widget *w,
43 struct snd_kcontrol *kcontrol,
44 int event)
45{
46 struct snd_soc_dapm_context *dapm = w->dapm;
47 struct simple_util_priv *priv = snd_soc_card_get_drvdata(dapm->card);
48
49 switch (event) {
50 case SND_SOC_DAPM_POST_PMU:
51 gpiod_set_value_cansleep(priv->pa_gpio, 1);
52 break;
53 case SND_SOC_DAPM_PRE_PMD:
54 gpiod_set_value_cansleep(priv->pa_gpio, 0);
55 break;
56 default:
57 return -EINVAL;
58 }
59
60 return 0;
61}
62
63static const struct snd_soc_dapm_widget graph_dapm_widgets[] = {
64 SND_SOC_DAPM_OUT_DRV_E("Amplifier", SND_SOC_NOPM,
65 0, 0, NULL, 0, graph_outdrv_event,
66 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
67};
68
69static const struct snd_soc_ops graph_ops = {
70 .startup = simple_util_startup,
71 .shutdown = simple_util_shutdown,
72 .hw_params = simple_util_hw_params,
73};
74
75static bool soc_component_is_pcm(struct snd_soc_dai_link_component *dlc)
76{
77 struct snd_soc_dai *dai = snd_soc_find_dai_with_mutex(dlc);
78
79 if (dai && (dai->component->driver->pcm_construct ||
80 (dai->driver->ops && dai->driver->ops->pcm_new)))
81 return true;
82
83 return false;
84}
85
86static void graph_parse_convert(struct device *dev,
87 struct device_node *ep,
88 struct simple_util_data *adata)
89{
90 struct device_node *top = dev->of_node;
91 struct device_node *port __free(device_node) = ep_to_port(ep);
92 struct device_node *ports __free(device_node) = port_to_ports(port);
93 struct device_node *node __free(device_node) = of_graph_get_port_parent(ep);
94
95 simple_util_parse_convert(top, NULL, adata);
96 simple_util_parse_convert(ports, NULL, adata);
97 simple_util_parse_convert(port, NULL, adata);
98 simple_util_parse_convert(ep, NULL, adata);
99}
100
101static int graph_parse_node(struct simple_util_priv *priv,
102 struct device_node *ep,
103 struct link_info *li,
104 int *cpu)
105{
106 struct device *dev = simple_priv_to_dev(priv);
107 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
108 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
109 struct snd_soc_dai_link_component *dlc;
110 struct simple_util_dai *dai;
111 int ret;
112
113 if (cpu) {
114 dlc = snd_soc_link_to_cpu(dai_link, 0);
115 dai = simple_props_to_dai_cpu(dai_props, 0);
116 } else {
117 dlc = snd_soc_link_to_codec(dai_link, 0);
118 dai = simple_props_to_dai_codec(dai_props, 0);
119 }
120
121 ret = graph_util_parse_dai(priv, ep, dlc, cpu);
122 if (ret < 0)
123 goto end;
124
125 ret = simple_util_parse_tdm(ep, dai);
126 if (ret < 0)
127 goto end;
128
129 ret = simple_util_parse_clk(dev, ep, dai, dlc);
130end:
131 return graph_ret(priv, ret);
132}
133
134static int graph_link_init(struct simple_util_priv *priv,
135 struct device_node *ep_cpu,
136 struct device_node *ep_codec,
137 struct link_info *li,
138 char *name)
139{
140 struct device *dev = simple_priv_to_dev(priv);
141 struct device_node *top = dev->of_node;
142 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
143 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
144 struct device_node *port_cpu __free(device_node) = ep_to_port(ep_cpu);
145 struct device_node *port_codec __free(device_node) = ep_to_port(ep_codec);
146 struct device_node *ports_cpu __free(device_node) = port_to_ports(port_cpu);
147 struct device_node *ports_codec __free(device_node) = port_to_ports(port_codec);
148 enum snd_soc_trigger_order trigger_start = SND_SOC_TRIGGER_ORDER_DEFAULT;
149 enum snd_soc_trigger_order trigger_stop = SND_SOC_TRIGGER_ORDER_DEFAULT;
150 bool playback_only = 0, capture_only = 0;
151 int ret;
152
153 ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec,
154 NULL, &dai_link->dai_fmt);
155 if (ret < 0)
156 goto end;
157
158 graph_util_parse_link_direction(top, &playback_only, &capture_only);
159 graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only);
160 graph_util_parse_link_direction(port_codec, &playback_only, &capture_only);
161 graph_util_parse_link_direction(ep_cpu, &playback_only, &capture_only);
162 graph_util_parse_link_direction(ep_codec, &playback_only, &capture_only);
163
164 of_property_read_u32(top, "mclk-fs", &dai_props->mclk_fs);
165 of_property_read_u32(ports_cpu, "mclk-fs", &dai_props->mclk_fs);
166 of_property_read_u32(ports_codec, "mclk-fs", &dai_props->mclk_fs);
167 of_property_read_u32(port_cpu, "mclk-fs", &dai_props->mclk_fs);
168 of_property_read_u32(port_codec, "mclk-fs", &dai_props->mclk_fs);
169 of_property_read_u32(ep_cpu, "mclk-fs", &dai_props->mclk_fs);
170 of_property_read_u32(ep_codec, "mclk-fs", &dai_props->mclk_fs);
171
172 graph_util_parse_trigger_order(priv, top, &trigger_start, &trigger_stop);
173 graph_util_parse_trigger_order(priv, ports_cpu, &trigger_start, &trigger_stop);
174 graph_util_parse_trigger_order(priv, ports_codec, &trigger_start, &trigger_stop);
175 graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
176 graph_util_parse_trigger_order(priv, port_cpu, &trigger_start, &trigger_stop);
177 graph_util_parse_trigger_order(priv, ep_cpu, &trigger_start, &trigger_stop);
178 graph_util_parse_trigger_order(priv, ep_codec, &trigger_start, &trigger_stop);
179
180 dai_link->playback_only = playback_only;
181 dai_link->capture_only = capture_only;
182
183 dai_link->trigger_start = trigger_start;
184 dai_link->trigger_stop = trigger_stop;
185
186 dai_link->init = simple_util_dai_init;
187 dai_link->ops = &graph_ops;
188 if (priv->ops)
189 dai_link->ops = priv->ops;
190
191 ret = simple_util_set_dailink_name(priv, dai_link, name);
192end:
193 return graph_ret(priv, ret);
194}
195
196static int graph_dai_link_of_dpcm(struct simple_util_priv *priv,
197 struct device_node *cpu_ep,
198 struct device_node *codec_ep,
199 struct link_info *li)
200{
201 struct device *dev = simple_priv_to_dev(priv);
202 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
203 struct simple_dai_props *dai_props = simple_priv_to_props(priv, li->link);
204 struct device_node *top = dev->of_node;
205 struct device_node *ep = li->cpu ? cpu_ep : codec_ep;
206 char dai_name[64];
207 int ret;
208
209 dev_dbg(dev, "link_of DPCM (%pOF)\n", ep);
210
211 if (li->cpu) {
212 struct snd_soc_card *card = simple_priv_to_card(priv);
213 struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
214 struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, 0);
215 int is_single_links = 0;
216
217
218
219
220 dai_link->dynamic = 1;
221 dai_link->dpcm_merged_format = 1;
222
223 ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
224 if (ret)
225 goto end;
226
227 snprintf(dai_name, sizeof(dai_name),
228 "fe.%pOFP.%s", cpus->of_node, cpus->dai_name);
229
230
231
232
233
234
235
236
237
238
239 if (card->component_chaining && !soc_component_is_pcm(cpus)) {
240 dai_link->no_pcm = 1;
241 dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
242 }
243
244 simple_util_canonicalize_cpu(cpus, is_single_links);
245 simple_util_canonicalize_platform(platforms, cpus);
246 } else {
247 struct snd_soc_codec_conf *cconf = simple_props_to_codec_conf(dai_props, 0);
248 struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
249
250
251
252
253 dai_link->no_pcm = 1;
254 dai_link->be_hw_params_fixup = simple_util_be_hw_params_fixup;
255
256 ret = graph_parse_node(priv, codec_ep, li, NULL);
257 if (ret < 0)
258 goto end;
259
260 snprintf(dai_name, sizeof(dai_name),
261 "be.%pOFP.%s", codecs->of_node, codecs->dai_name);
262
263
264 struct device_node *port __free(device_node) = ep_to_port(ep);
265 struct device_node *ports __free(device_node) = port_to_ports(port);
266
267 snd_soc_of_parse_node_prefix(top, cconf, codecs->of_node, "prefix");
268 snd_soc_of_parse_node_prefix(ports, cconf, codecs->of_node, "prefix");
269 snd_soc_of_parse_node_prefix(port, cconf, codecs->of_node, "prefix");
270 }
271
272 graph_parse_convert(dev, ep, &dai_props->adata);
273
274 ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
275
276 li->link++;
277end:
278 return graph_ret(priv, ret);
279}
280
281static int graph_dai_link_of(struct simple_util_priv *priv,
282 struct device_node *cpu_ep,
283 struct device_node *codec_ep,
284 struct link_info *li)
285{
286 struct device *dev = simple_priv_to_dev(priv);
287 struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, li->link);
288 struct snd_soc_dai_link_component *cpus = snd_soc_link_to_cpu(dai_link, 0);
289 struct snd_soc_dai_link_component *codecs = snd_soc_link_to_codec(dai_link, 0);
290 struct snd_soc_dai_link_component *platforms = snd_soc_link_to_platform(dai_link, 0);
291 char dai_name[64];
292 int ret, is_single_links = 0;
293
294 dev_dbg(dev, "link_of (%pOF)\n", cpu_ep);
295
296 ret = graph_parse_node(priv, cpu_ep, li, &is_single_links);
297 if (ret < 0)
298 goto end;
299
300 ret = graph_parse_node(priv, codec_ep, li, NULL);
301 if (ret < 0)
302 goto end;
303
304 snprintf(dai_name, sizeof(dai_name),
305 "%s-%s", cpus->dai_name, codecs->dai_name);
306
307 simple_util_canonicalize_cpu(cpus, is_single_links);
308 simple_util_canonicalize_platform(platforms, cpus);
309
310 ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name);
311 if (ret < 0)
312 goto end;
313
314 li->link++;
315end:
316 return graph_ret(priv, ret);
317}
318
319static inline bool parse_as_dpcm_link(struct simple_util_priv *priv,
320 struct device_node *codec_port,
321 struct simple_util_data *adata)
322{
323 if (priv->force_dpcm)
324 return true;
325
326 if (!priv->dpcm_selectable)
327 return false;
328
329
330
331
332
333
334 if ((of_get_child_count(codec_port) > 1) ||
335 simple_util_is_convert_required(adata))
336 return true;
337
338 return false;
339}
340
341static int __graph_for_each_link(struct simple_util_priv *priv,
342 struct link_info *li,
343 int (*func_noml)(struct simple_util_priv *priv,
344 struct device_node *cpu_ep,
345 struct device_node *codec_ep,
346 struct link_info *li),
347 int (*func_dpcm)(struct simple_util_priv *priv,
348 struct device_node *cpu_ep,
349 struct device_node *codec_ep,
350 struct link_info *li))
351{
352 struct of_phandle_iterator it;
353 struct device *dev = simple_priv_to_dev(priv);
354 struct device_node *node = dev->of_node;
355 struct device_node *cpu_port;
356 struct device_node *codec_port_old = NULL;
357 struct simple_util_data adata;
358 int rc, ret = 0;
359
360
361 of_for_each_phandle(&it, rc, node, "dais", NULL, 0) {
362 cpu_port = it.node;
363
364
365 for_each_of_graph_port_endpoint(cpu_port, cpu_ep) {
366
367 struct device_node *codec_ep __free(device_node) = of_graph_get_remote_endpoint(cpu_ep);
368 struct device_node *codec_port __free(device_node) = ep_to_port(codec_ep);
369
370
371 memset(&adata, 0, sizeof(adata));
372 graph_parse_convert(dev, codec_ep, &adata);
373 graph_parse_convert(dev, cpu_ep, &adata);
374
375
376 if (parse_as_dpcm_link(priv, codec_port, &adata)) {
377
378
379
380
381
382
383 if (li->cpu ||
384 ((codec_port_old != codec_port) && codec_ep))
385 ret = func_dpcm(priv, cpu_ep, codec_ep, li);
386
387 } else {
388 if (li->cpu)
389 ret = func_noml(priv, cpu_ep, codec_ep, li);
390 }
391
392 if (ret < 0)
393 goto end;
394
395 codec_port_old = codec_port;
396 }
397 }
398end:
399 return graph_ret(priv, ret);
400}
401
402static int graph_for_each_link(struct simple_util_priv *priv,
403 struct link_info *li,
404 int (*func_noml)(struct simple_util_priv *priv,
405 struct device_node *cpu_ep,
406 struct device_node *codec_ep,
407 struct link_info *li),
408 int (*func_dpcm)(struct simple_util_priv *priv,
409 struct device_node *cpu_ep,
410 struct device_node *codec_ep,
411 struct link_info *li))
412{
413 int ret;
414
415
416
417
418
419
420
421
422
423
424
425
426 for (li->cpu = 1; li->cpu >= 0; li->cpu--) {
427 ret = __graph_for_each_link(priv, li, func_noml, func_dpcm);
428 if (ret < 0)
429 break;
430 }
431
432 return graph_ret(priv, ret);
433}
434
435static int graph_count_noml(struct simple_util_priv *priv,
436 struct device_node *cpu_ep,
437 struct device_node *codec_ep,
438 struct link_info *li)
439{
440 struct device *dev = simple_priv_to_dev(priv);
441 int ret = -EINVAL;
442
443 if (li->link >= SNDRV_MAX_LINKS)
444 goto end;
445
446
447
448
449
450
451 li->num[li->link].cpus = 1;
452 li->num[li->link].platforms = 1;
453
454 li->num[li->link].codecs = 1;
455
456 li->link += 1;
457
458 dev_dbg(dev, "Count As Normal\n");
459 ret = 0;
460end:
461 return graph_ret(priv, ret);
462}
463
464static int graph_count_dpcm(struct simple_util_priv *priv,
465 struct device_node *cpu_ep,
466 struct device_node *codec_ep,
467 struct link_info *li)
468{
469 struct device *dev = simple_priv_to_dev(priv);
470 int ret = -EINVAL;
471
472 if (li->link >= SNDRV_MAX_LINKS)
473 goto end;
474
475 if (li->cpu) {
476
477
478
479
480
481 li->num[li->link].cpus = 1;
482 li->num[li->link].platforms = 1;
483
484 li->link++;
485 } else {
486 li->num[li->link].codecs = 1;
487
488 li->link++;
489 }
490
491 dev_dbg(dev, "Count As DPCM\n");
492 ret = 0;
493end:
494 return graph_ret(priv, ret);
495}
496
497static int graph_get_dais_count(struct simple_util_priv *priv,
498 struct link_info *li)
499{
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546 return graph_for_each_link(priv, li,
547 graph_count_noml,
548 graph_count_dpcm);
549}
550
551int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev)
552{
553 struct snd_soc_card *card = simple_priv_to_card(priv);
554 int ret = -ENOMEM;
555
556 struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL);
557 if (!li)
558 goto end;
559
560 card->owner = THIS_MODULE;
561 card->dev = dev;
562
563 ret = graph_get_dais_count(priv, li);
564 if (ret < 0)
565 goto end;
566
567 ret = -EINVAL;
568 if (!li->link)
569 goto end;
570
571 ret = simple_util_init_priv(priv, li);
572 if (ret < 0)
573 goto end;
574
575 priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW);
576 if (IS_ERR(priv->pa_gpio)) {
577 ret = PTR_ERR(priv->pa_gpio);
578 dev_err(dev, "failed to get amplifier gpio: %d\n", ret);
579 goto end;
580 }
581
582 ret = simple_util_parse_widgets(card, NULL);
583 if (ret < 0)
584 goto end;
585
586 ret = simple_util_parse_routing(card, NULL);
587 if (ret < 0)
588 goto end;
589
590 memset(li, 0, sizeof(*li));
591 ret = graph_for_each_link(priv, li,
592 graph_dai_link_of,
593 graph_dai_link_of_dpcm);
594 if (ret < 0)
595 goto err;
596
597 ret = simple_util_parse_card_name(priv, NULL);
598 if (ret < 0)
599 goto err;
600
601 snd_soc_card_set_drvdata(card, priv);
602
603 simple_util_debug_info(priv);
604
605 ret = devm_snd_soc_register_card(dev, card);
606 if (ret < 0)
607 goto err;
608
609 return 0;
610err:
611 simple_util_clean_reference(card);
612end:
613 return dev_err_probe(dev, ret, "parse error\n");
614}
615EXPORT_SYMBOL_GPL(audio_graph_parse_of);
616
617static int graph_probe(struct platform_device *pdev)
618{
619 struct simple_util_priv *priv;
620 struct device *dev = &pdev->dev;
621 struct snd_soc_card *card;
622
623
624 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
625 if (!priv)
626 return -ENOMEM;
627
628 card = simple_priv_to_card(priv);
629 card->dapm_widgets = graph_dapm_widgets;
630 card->num_dapm_widgets = ARRAY_SIZE(graph_dapm_widgets);
631 card->probe = graph_util_card_probe;
632
633 if (of_device_get_match_data(dev))
634 priv->dpcm_selectable = 1;
635
636 return audio_graph_parse_of(priv, dev);
637}
638
639static const struct of_device_id graph_of_match[] = {
640 { .compatible = "audio-graph-card", },
641 { .compatible = "audio-graph-scu-card",
642 .data = (void *)DPCM_SELECTABLE },
643 {},
644};
645MODULE_DEVICE_TABLE(of, graph_of_match);
646
647static struct platform_driver graph_card = {
648 .driver = {
649 .name = "asoc-audio-graph-card",
650 .pm = &snd_soc_pm_ops,
651 .of_match_table = graph_of_match,
652 },
653 .probe = graph_probe,
654 .remove = simple_util_remove,
655};
656module_platform_driver(graph_card);
657
658MODULE_ALIAS("platform:asoc-audio-graph-card");
659MODULE_LICENSE("GPL v2");
660MODULE_DESCRIPTION("ASoC Audio Graph Sound Card");
661MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
662