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